Tic Tac Toe: in tất cả các vị trí có thể mà không trùng lặp


8

Viết chương trình xuất ra tất cả các vị trí Tic Tac Toe có thể bao gồm cả kết quả trò chơi tương ứng. Tránh đầu ra trùng lặp của các vị trí bằng nhau.

Chương trình không có đầu vào.

Quy tắc:

  • Một đầu ra vị trí phải bao gồm 9 ký tự, sử dụng XOcho các ô vuông đã lấy và một ký tự không phải khoảng trắng tùy ý cho các ô vuông trống
  • Mỗi vị trí phải được in thành 3 dòng / cột, với một dòng trống làm dấu phân cách giữa hai vị trí.
  • Các ký tự vẽ khoảng trắng / dòng trống / hộp trống bổ sung được chào đón
  • Người chơi X đi trước
  • Các kết quả có thể là của:

    • X đã thắng
    • O đã thắng
    • Vẽ tranh
    • Trò chơi đang diễn ra

    Bạn có thể tự do lựa chọn một hình ảnh phù hợp về kết quả của vị trí, ví dụ như văn bản màu hoặc chú thích văn bản, miễn là nó được đặt gần vị trí tương ứng

  • Vị trí được coi là bằng nhau nếu có thể lấy được vị trí này từ vị trí kia bằng cách xoay hoặc phản chiếu. Vị trí trùng lặp không được in. (Nói cách khác, chỉ in các lớp bằng.)
    Ví dụ: chỉ in một trong các cách sau:
X••  ••X  •••  •••
•••  •••  •••  •••
•••  •••  X••  ••X
  • Đây là , vì vậy mã ngắn nhất sẽ thắng!

Đầu ra mẫu:

•••
•••
••• -

X••
•••
••• -

•X•
•••
••• -

•••
•X•
••• -


[…]


XXO
OOX
XXO /

OXO
XXX
OXO X

Gợi ý: Có 765 vị trí, với 91 chiến thắng cho X, 44 chiến thắng cho O và 3 trận hòa.


Một câu hỏi tương tự đã được hỏi trước đây, nhưng câu hỏi này thì khác.


2
Chào mừng đến với PPCG! Mọi thách thức trên PPCG đều phải có tiêu chí chiến thắng. Tiêu chí cho thử thách này là gì? Đây có phải là môn đánh gôn không , nơi chương trình có số lần thắng ngắn nhất sẽ thắng?
dùng41805

Nếu bạn xác nhận tiêu chí chiến thắng, điều này sẽ sớm được mở lại. Tôi chưa đếm các vị trí, nhưng tôi tự hỏi, bảng trống a) bắt buộc b) bị cấm c) không bắt buộc?
Cấp sông St

Chỉ cần nhận ra, bạn đã nói mã ngắn nhất thắng. Chỉnh sửa trong thẻ golf-code. Chúng tôi thường chấm điểm theo số byte ở đây, vì có một số ngôn ngữ được phát minh đặc biệt để sử dụng các ký tự đa nhân để rút ngắn mã, điều này không thú vị lắm.
Cấp sông St

@StephenS Đó là một điều khác biệt. Một byte có thể có bất kỳ giá trị nào từ 0-255. Trang web này chỉ có thể hiển thị các ký tự byte đơn trong phạm vi 32-126 cộng với một vài ký tự khác. Bộ mã 256 byte đã có từ rất lâu và bản thân tôi đã đăng câu trả lời C trong codepage 437. UTF-8 được phát minh vì những bộ mã này không có đủ ký tự cho tất cả các ngôn ngữ tự nhiên, nhưng UTF-8 không được thiết kế để xử lý phi văn bản dữ liệu với các byte ngẫu nhiên. Tôi đã đề cập đến các ngôn ngữ như esolangs.org/wiki/Sclipting sử dụng rộng rãi các ký tự đa nhân châu Á để khai thác lỗ hổng ghi điểm trong các ký tự
Level River St

@LevelRiverSt ah, gotcha. Cảm ơn thông tin :)
Stephen

Câu trả lời:


5

Thạch , 192 179 168 byte

5ĿḢṠµFf0L¬ị⁾-/µ5ĿḢṠµ?
U,µṚ,µ€µ“æɗþƑ’DịFs3,µ€€Fs9s3$€Ṣ
FSµ×’¬
ÑPµA_µọ9n1
,UŒDḢ$€;;ZS€f3,-3
Ç,SS€µṪµṪCµSṠ‘µ?÷Ḣ
Ça3Ŀa4Ŀ
3ṗ9_2s3$€ÇÐf2Ŀ€QḢ€µ;ÑFµ€µ3Ḷ’,“O¤X”yµ€Fs10µs3Gµ€j⁾¶¶

Hãy thử trực tuyến! (Mất khoảng 30 giây, vì vậy hãy kiên nhẫn).

Làm thế nào nó hoạt động

Tổng quan cấp cao:

Trong các bước trung gian, cửa hàng này lưu X 1, không thay thế 0và O là -1. Chương trình tạo ra tất cả 3 ^ 9 khả năng, sau đó chỉ giữ các vị trí hợp lệ dựa trên việc đáp ứng ba tiêu chí:

  • Có 1 hoặc 0 X nhiều hơn O.
  • Không phải cả X và O đều thắng.
  • Nếu X đã thắng, có nhiều hơn X so với O. Nếu O đã thắng, có số lượng Os và X bằng nhau.

Sau đó, chương trình thay thế từng trạng thái trò chơi bằng tất cả các phép quay và phản xạ của nó để có được danh sách tất cả các lớp tương đương. Đây là hoạt động mất phần lớn thời gian.

Trạng thái trò chơi đầu tiên được lấy từ mỗi lớp tương đương, sau đó ai thắng sẽ được tính.

Trường hợp điều này xảy ra Các dòng được đánh số để dễ đọc

1: 5ĿḢṠµFf0L¬ị⁾-/µ5ĿḢṠµ?          ••calculates who wins (output as -1 or 1) or draw ("-") or in game ("/")
                 µ5ĿḢṠµ?          - if(someone won based on line 5):
   5ĿḢṠ                             - return 1 if X won and -1 if O won
       µ                          - else:
        Ff0L¬ị⁾-/                   - return "/" if the game is in progress and "-" if the game is at a tied end-state
2: U,µṚ,µ€µ“æɗþƑ’DịFs3,µ€€Fs9s3$€Ṣ••outputs the equivalence class to a game state
   U,                             - list of game state [reflected horizontally, unaltered]
     µṚ,µ€                        - for each, replace with the list [reflected vertically,unaltered]
          µ“æɗþƑ’DịFs3,µ€€        - for each, replace with the list [rotated 90 degrees counter-clockwise,unaltered]
                          Fs9s3$€ - reformat into list of game states
                                 Ṣ- Sort
3: FSµ×’¬                         ••outputs truthy iff there is the right number of `X`s to `O`s (condition 1)
   FS                             - d = number of `X`s minus number of `O`s
     µ×’                          - d*(d-1): falsey iff d is 0 or 1
        ¬                         - logical not, to return truthy iff d is 0 or 1
4: ÑPµA_µọ9n1                     ••outputs truthy iff there is the right number of winners (condition 2)
   Ñ                              - the winners. [-3,3] is what we want to return falsy on
    PµA_µ                         - 18 on [-3,3] and 0 otherwise
         ọ9n1                     - not divisible by 9 exactly once: 0 on [-3,3] and 1 otherwise
5: ,UŒDḢ$€;;ZS€f3,-3              ••outputs the number of times each player won.
   ,UŒDḢ$€;;Z                     - the diagonals, rows, and columns of a board
             S€                   - sum of each. Returns -3 or 3 iff the line is only 1s or -1s
               f3,-3              - filter out, keeping only 3s and -3s
6: Ç,SS€µṪµṪCµSṠ‘µ?÷Ḣ             ••return truthy iff the winner corresponds to the respective numbers of X and O (condition 3)
   Ç,SS€                          - list of winners and how many more Xs than Os there are
             µSṠ‘µ?               - if O won, then
        µṪ                          - how many more Xs than Os there are
                                  - else:
          µṪC                       - the complement of how many more Xs than Os there are
                   ÷Ḣ             - deal with no one winning
7: Ça3Ŀa4Ŀ                        ••return truthy iff the game state meets all three conditions
   Ç 3Ŀ 4Ŀ                        - the three conditions: on line 3,4, and 6
    a  a                          - joined by logical ANDs
8: 3ṗ9_2s3$€ÇÐf2Ŀ€QḢ€µ;ÑFµ€µ3Ḷ’,“O¤X”yµ€Fs10µs3Gµ€j⁾¶¶ ••do everything
   3ṗ9_2                        - all possible game states, with -1 for O and 1 for X
        s3$€                    - turn into two-dimensional game boards
            ÇÐf                 - filter based on line 6: if the board meets all three ocnditions
               2Ŀ€Q             - generate the equivalence classes for each and remove repeats based on line 1
                   Ḣ€           - get the first board from each class
                     µ;ÑFµ€     - append the winner to each board based on line 1
   µ3Ḷ’,“O¤X”yµ€                   - map each -1, 0, and 1 to the proper `O`,  `¤`, and `X`.
                Fs10µs3Gµ€         - format each board- winner combos
                          j⁾¶¶     - join the combos by double-newlines

2

Ruby, 305 byte

19683.times{|i|c=(i%3).to_s 
s=(9**8+i/3*6562).to_s(3)
w=0
t=(0..3).map{|j|r=s[1+j*2,9]
w|=1<<r[0..2].sum%8|1<<(c+r[j/2]+r[4+j/2]).sum%8
[r,r.reverse].min}.min
v=t[0..2]+$/+t[7]+c+t[3]+$/+t[6]+t[5]+t[4]
w&=65
b=v.sum%51
w<65&&b>w/64&&b<3-w%2&&t==s[1,9]&&puts(v.tr("012","X.O"),w<1?v.include?(?1):w%31,"")}

Điều này hoạt động tương tự với các câu trả lời khác ở chỗ nó tạo ra tất cả các 3**9bảng sau đó lọc ra những câu hợp lệ. Trong nội bộ, chúng tôi sử dụng số ternary 0=X 1=. 2=Otrong đầu ra. Lặp lại cqua 3 giá trị có thể cho trung tâm và sthông qua các 3**8 = 6561giá trị cho chu vi. Trước khi chuyển đổi i/3thành một chuỗi đại diện cho một số thứ ba, chúng tôi nhân 6562với nhân đôi tất cả các chữ số và thêm 3**16để bắt đầu số với số 1, để đảm bảo có các số 0 đứng đầu khi áp dụng. wlà điều kiện thắng - đặt giá trị này thành 0.

Đối với mỗi bảng Lặp lại qua 4 lần quay của các chữ số sđể tìm phiên bản thấp nhất về mặt từ vựng của số thứ ba 8 chữ số hiện tại đại diện cho chu vi. Đồng thời, thêm các giá trị ascii của 3 chữ số đầu tiên (hàng trên cùng của vòng quay hiện tại) và sử dụng giá trị này để kiểm tra một chiến thắng. Ngoài ra, thêm các giá trị ascii của cvà một cặp chữ số ngược nhau để kiểm tra xem có chiến thắng qua trung tâm hay không.

Kiểm tra xem đầu ra có hợp lệ không - Nếu cả hai bit 1 và 64 bit wđều được đặt, cả hai bên đều thắng - điều này không hợp lệ. Kiểm tra số dư của X và O (nếu chưa có người chiến thắng thì có thể bằng X và O hoặc thêm một X - nhưng nếu trò chơi chiến thắng, chỉ có một giá trị có thể, vì người chiến thắng phải đi sau cùng.) Để tránh hiển thị các góc quay khác nhau của cùng một bảng, chỉ xuất ra nếu phiên bản thấp nhất của chu vi tương ứng với giá trị hiện tại của s[2,9].

Xuất bảng , duy trì các biểu tượng tr("012","X.O"). Trạng thái trò chơi được hiển thị bên dưới bảng. Nếu w = 0, đây là truenếu vẫn còn các ô vuông trống (trò chơi vẫn đang diễn ra) và falsenếu bảng đã đầy. Nếu wkhác không, chúng tôi xuất ra 1nếu người chơi 1 (X) đã thắng hoặc 64%31==2nếu người chơi 2 (O) đã thắng.

Ung dung

19683.times{|i|                             #check 3**9 possibilities
  c=(i%3).to_s                              #centre square: 0=X, 1=. 2=O 
  s=(9**8+i/3*6562).to_s(3)                 #perimeter:multiply i/3 by 3**8+1 to duplicate digits, add 3**16 to give a 1 at left side to ensure leading zeros
  w=0                                       #set w=0 to clear wins (1´s bit holds win for X, 64´s bit holds win for O)
  t=(0..3).map{|j|                          #build an array of 4 different rotations of the perimeter
     r=s[1+j*2,9]                           #by taking different 9-character slices of s
     w|=1<<r[0..2].sum%8|                   #add ascii codes mod 8 for top row of current rotation, take sum modulo 8 to give sum of digits. set a bit in w (we only care about bits 0 and 6)
        1<<(c+r[j/2]+r[4+j/2]).sum%8        #do the same for one of the 4 lines through the centre. if j/2=0 check diagonal, if j/2=1 check horizontal/vertical. 
     [r,r.reverse].min}.min                 #add to the array the lexically lowest version(forward or reverse) of the current rotation. When the loop ends, find the lexically lowest version overall and assign to t.
  v=t[0..2]+$/+t[7]+c+t[3]+$/+t[6]+t[5]+t[4]#format the output into a square 012\n 7c3\n 654
  w&=65                                     #clear bits 1 through 5 of w, leave only bits 0 and 6 which are the ones of interest.
  b=v.sum%51                                #valid values of sum of ascii codes in output are 461 (equal 0's and 2's) and 460 (one more 0 than 2). Take modulo 51 to reduce these values to 1 and 2       
  w<65&&                                    #if a maximum of one player has a winning line (not both) and
  b>w/64&&                                  #b must be 1 or 2 (only 2 permitted if O's won)
  b<3-w%2&&                                 #b must be 1 or 2 (only 1 permitted if X's won)
  t==s[1,9]&&                               #s[2,9] is the lexically lowest version of the current board (to avoid duplicates) then 
  puts(v.tr("012","X.O"),                   #output the board, subsituting internal "012" characters for external "X.O"
  w<1?v.include?(?1):w%31,"")               #if nobody won, output true if game in still in play (1's present on board) else false
}                                           #if there is a winner, output (player) 1 for X, (player) w%31=2 for O. Also output a blank line.

Đề án kiểm tra

Các sơ đồ dưới đây cho thấy sơ đồ xoay vòng (và kiểm tra thắng, tính bằng thủ đô). Các sơ đồ được hiển thị không bảo vệ. Bốn phép quay khác nhau được lấy làm chuỗi con từ bản sao kép i/3, với 3 chữ in hoa liên tiếp trên chu vi của mỗi sơ đồ ("đỉnh" trên mỗi vòng quay hiện tại) là 3 ký tự đầu tiên trong chuỗi con 9 ký tự. Đối với mỗi vòng quay, đảo ngược 9 ký tự (lật chéo về trục AE hoặc CG) cũng được thử. Bảng chỉ là đầu ra nếu giá trị hiện tại i/3là thấp nhất về mặt từ vựng của tất cả các phép quay và gương.

 ABC    abC    aBc    Abc 
 hZd    hZD    hZd    HZD
 gfE    GfE    GFE    Gfe

2

Python 2 , 648 620 byte

import re
M=re.match
x='X';o='O'
R=lambda b,z=[6,3,0,7,4,1,8,5,2]:''.join(b[z[i]]for i in range(9))
p='XXX......|...XXX...|......XXX|X...X...X';q=p.replace(x,o)
def e(b):c=b.count;d=c(x)-c(o);w=M(p,b)or M(p,R(b));v=M(q,b)or M(q,R(b));return 0 if d not in[0,1]else 0 if w and v else(x if d==1 else 0)if w else(o if d==0 else 0)if v else'.'if'.'in b else'/'
h=set()
for n in range(3**9):
 b=reduce(lambda a,v:('.XO'[a[1]%3]+a[0],a[1]/3),range(9),('',n))[0]
 if b not in h:
	u=e(b)
	if u:print'%s\n%s\n%s %s\n'%(b[:3],b[3:6],b[6:],u)
	h.update(reduce(lambda a,v:a+[R(a[-2]),R(a[-1])],range(3),[b,R(b,[2,1,0,5,4,3,8,7,6])]))

Hãy thử trực tuyến!

Có lẽ một chút chơi golf nhỏ có thể ở đây với phương pháp này; nhưng không nhiều.

Chỉnh sửa: Thx thành ovs, người đã lưu ý một tinh chỉnh đạt được 28 byte; và 3 từ Artemis Fowl

Mã không chơi gôn

Ý tưởng cơ bản ở đây là: vũ phu mỗi trong số 3 ^ 9 = 19683 bảng mã có thể có. Theo dõi các liên hợp (xoay và phản xạ) của các bảng đã được kiểm tra để bạn không trùng lặp các mục. Tối thiểu, các bảng hợp lệ phải có số lượng X và O bằng nhau hoặc nhiều hơn một X so với O. Không thể có cả chiến thắng cho X và chiến thắng cho O; cộng với một số hạn chế khó khăn bổ sung.

import re
from collections import Counter

FLIP_XFRM = [2,1,0,5,4,3,8,7,6]
ROT_XFRM = [6,3,0,7,4,1,8,5,2]

def xfrm(b, xf):
    return ''.join(b[xf[i]] for i in range(9))

def flipIt(b):
    return xfrm(b,FLIP_XFRM)

def rotIt(b):
    return xfrm(b,ROT_XFRM)

def conjugates(b):
    conj = [b, flipIt(b)]
    for i in range(3):
        conj += [rotIt(conj[-2]), rotIt(conj[-1])]
    return conj

def tttToB(n):
    b = ''
    for i in range(9):
        b = '.XO'[n %3]+b
        n /= 3
    return b

def printBoard(b,outcome='.'):
    print '%s\n%s\n%s %s\n' % (b[:3],b[3:6],b[6:],outcome)

def evalBoard(b):
    c = Counter(b)
    if c['X']-c['O'] not in [0,1]:
        return False

    p1 = 'XXX......|...XXX...|......XXX|X...X...X'
    p2 = p1.replace('X','O')

    br = rotIt(b)
    w1 = re.match(p1,b) or re.match(p1,br)    
    w2 = re.match(p2,b) or re.match(p2,br)    
    if w1 and w2:
        return False

    if w1:
        return 'X' if c['X']==c['O']+1 else False

    if w2:
        return 'O' if c['X']==c['O'] else False

    if '.' in b:
        return '.'
    else:
        return '/'

def main():
    history = set()
    for m in range(3**9):
        b = tttToB(m)
        if b not in history:
            outcome = evalBoard(b)
            if outcome:
                printBoard(b,outcome)
            history.update(conjugates(b))

main()

Tôi không thonk bạn cần Counter. Bạn có thể thay thế nó bằngc=b.count;d=c(x)-c(o)
ovs

@ovs: nên lưu ý!
Chas Brown

Nó dài returncó thể làreturn 0if d not in[0,1]else 0if w and v else(x*(d==1))if w else(o*(d==0))if v else'.'if'.'in b else'/'
Zacharý

Bài cũ tôi biết, nhưng đây có vẻ là 623 byte? Bạn có thể thay thế mức thụt dòng thứ hai (2 khoảng trắng) bằng một tab duy nhất cho 620 byte, có lẽ bạn muốn làm điều này?
Artemis vẫn không tin tưởng SE

@ArtemisFowl Yup, đây là trước khi tôi phát hiện ra TIO - dễ mắc lỗi đếm!
Chas Brown
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.