Thánh giá, không có Noughts


10

Mọi người đều nhận ra rằng Tic Tac Toe là một trò chơi đã được giải quyết. Tuy nhiên, phiên bản Misère của chỉ X-cung cấp một sự thay thế thú vị.

Trong phiên bản này của trò chơi, cả hai người chơi đều chơi Xs trên bảng và cố gắng tránh làm ba liên tiếp. Nếu bạn muốn xem thêm về điều này, Numberphile có một video hay về khái niệm này.

Đưa ra một bảng của Misère Crosses, chơi một bước đi tối ưu.

Một bảng là ba dòng gồm ba ký tự, mỗi dòng là Xhoặc . Như vậy:

X X
X  
 XX

là một hội đồng hợp lệ. Bạn có thể sử dụng định dạng này ở bất kỳ định dạng thuận tiện nào, miễn là đầu vào và đầu ra của bạn sử dụng cùng một định dạng. Các định dạng bao gồm (nhưng không giới hạn ở): Chuỗi nhiều dòng (với dòng mới theo dõi tùy chọn); Một mảng 2D của các ký tự là Xhoặc ; một mảng phẳng 1D của các giá trị boolean đại diện nếu mỗi vị trí đã được phát.

Một nước đi tối ưu là một bước đảm bảo bạn sẽ giành chiến thắng bằng cách tiếp tục chơi tối ưu hoặc kéo dài sự mất mát của bạn càng lâu càng tốt và được xác định theo các quy tắc sau:

  • Tránh làm ba liên tiếp.
  • Nếu bạn đi trước, chơi ở giữa.
  • Nếu không gian bị chiếm duy nhất là giữa, hãy chơi ở bất kỳ không gian còn lại nào.
  • Nếu hình vuông ở giữa không bị chiếm đóng và hình vuông bên ngoài là, hãy chơi đối diện với lần chơi cuối cùng của đối thủ.
  • Nếu hình vuông ở giữa bị chiếm đóng và hình vuông bên ngoài, hãy chơi một "hiệp sĩ di chuyển" (đối diện, một trên) từ một di chuyển trước đó không khiến bạn thua cuộc.
  • Nếu không còn ô vuông nào còn lại nơi bạn sẽ không bị mất, hãy chơi ở bất kỳ ô vuông nào còn lại.

[LƯU Ý: điều này đã được chứng minh là không tối ưu trong một trường hợp nhưng dù sao bạn cũng nên sử dụng thuật toán này.]

Bạn có thể cho rằng tất cả các động thái trước đó của bạn là tối ưu. Vì vậy, bảng ví dụ đầu tiên không phải là một đầu vào hợp lệ. Di chuyển của đối thủ của bạn có thể hoặc không thể là tối ưu.

Nếu trò chơi đã kết thúc (tức là ba liên tiếp đã được thực hiện), hành vi không được xác định.

Vì đây là , câu trả lời ngắn nhất bằng byte sẽ thắng!

Một con đường có thể, chỉ sử dụng các bước di chuyển tối ưu, là:

[   ]  [   ]  [X  ]  [X  ]  [X  ]  [X  ]  [XX ]
[   ]->[ X ]->[ X ]->[ XX]->[ XX]->[ XX]->[ XX]
[   ]  [   ]  [   ]  [   ]  [ X ]  [XX ]  [XX ]

Dưới đây là các đầu vào có thể có nguồn gốc từ đối thủ bằng cách sử dụng các bước di chuyển không tối ưu:
(Lưu ý rằng chỉ các bảng bên trái trong danh sách này là các đầu vào hợp lệ.)

[X  ]  [X  ]
[   ]->[   ]
[   ]  [  X]

[XX ]  [XX ]
[   ]->[   ]
[  X]  [ XX]

[XX ]  [XX ]
[X  ]->[X X]
[ XX]  [ XX]


Các định dạng đầu vào và đầu ra là gì? Tôi đang giả sử một bảng được lấy dưới dạng một mảng hoặc chuỗi? Tuy nhiên điều này không cung cấp thông tin về động thái cuối cùng, do đó câu hỏi tiếp theo của tôi.
Cấp sông St

1
Chiến lược "chơi đối diện với lần chơi cuối cùng của đối thủ" giả định kiến ​​thức về lịch sử di chuyển của đối thủ hoặc trước đây bạn đã theo chiến lược này, ví dụ như không được thừa hưởng một bảng như vậy .XX\nX..\nX... Chúng ta có phải xem xét kế thừa các bảng như thế này?
Cấp sông St

@LevelRiverSt Như đã viết, "Bạn có thể cho rằng tất cả các bước đi trước đó của bạn là tối ưu", do đó bảng sẽ là đầu vào không hợp lệ. Bạn có thể lấy đầu vào ở bất kỳ định dạng nào bạn thích, nhưng một chuỗi nhiều dòng như ví dụ của bạn sẽ có "mặc định": Tôi chỉ không muốn hạn chế bất kỳ ai phải phân tích Chuỗi khi logic di chuyển là điểm của các thách thức.
CAD97

Câu trả lời:


3

Ruby, Rev B 121 byte

Trình là chức năng ẩn danh, trừ đi f=. Hiển thị trong chương trình thử nghiệm để minh họa việc sử dụng.

f=->n{["~mK)\7","}uYwQO"][l=n%2].bytes{|t|9.times{|i|(m=n|1<<i)==n||8.times{|j|m/2*257>>j&255==126-t&&t+j%2!=119&&l=m}}}
l}

puts g=f[gets.to_i]
puts
[7,6,5,
 8,0,4,
 1,2,3].each{|i|print g>>i&1; puts if i/3==1}

2 byte được lưu bằng cách làm cho hình vuông trung tâm trở thành bit đáng kể nhất thay vì bit đáng kể nhất (loại bỏ /2thay vì %256.) Tiết kiệm còn lại bằng cách sắp xếp lại bảng di chuyển chấp nhận được. Tổ chức dưới dạng ô vuông trung tâm miễn phí / chiếm thay vì tổng số X cho phép thử nghiệm đơn giản hơn. Ngoài ra, bây giờ chỉ có 2 chuỗi trong mảng nên %w{string1 string2}cú pháp bị bỏ qua có lợi cho ["string1","string2"]cú pháp. Điều này cho phép \7bao gồm một ký tự không thể in được, từ đó cho phép sử dụng mã hóa đơn giản hơn: 126-tthay vì (36-t)%120.

Ruby, Rev A 143 byte

->n{l=r=("%b"%n).sum%8
%w{$ %5 - I+Wy Q S#}[r].bytes{|t|9.times{|i|(m=n|1<<i)==n||8.times{|j|m%256*257>>j&255==(t-36)%120&&t+j%2!=43&&l=m}}}
l}

Đây là một chức năng ẩn danh. Định dạng đầu vào / đầu ra bị bỏ ngỏ, vì vậy tôi đã sử dụng số nhị phân 9 bit. bit 512 đại diện cho trung tâm, với các bit còn lại xoắn quanh nó (bit 1 được coi là một góc.)

Có nhiều đầu vào khả dĩ hơn đầu ra chấp nhận được, vì vậy thuật toán là thử tất cả các bước di chuyển và tìm một đầu vào phù hợp với mẫu đầu ra chấp nhận được. Các mẫu đầu ra chấp nhận được cho mỗi số X là mã hóa cứng.

Thông tin về hình vuông trung tâm bị loại bỏ và 8 bit còn lại được nhân với 257 để nhân đôi chúng. Mẫu này sau đó được xoay qua các mẫu có thể chấp nhận được bằng cách chuyển quyền.

Vòng lặp không được thoát khi tìm thấy một mẫu, do đó mẫu được trả về sẽ là mẫu được chấp nhận LAST được tìm thấy. Vì lý do này, các mẫu thích hợp hơn (nơi có ưu tiên) đến sau trong danh sách.

Với chiến lược 'Hiệp sĩ di chuyển', việc một mô hình được xoay 45 độ hay không là rất quan trọng. Phiên bản không có người theo chiến lược di chuyển của các hiệp sĩ và do đó không cần phân biệt giữa hình vuông góc và hình vuông cạnh: dù sao thì ba cái liên tiếp cũng phải tránh.

Tuy nhiên, tôi thấy rằng đây không phải lúc nào cũng là chiến lược tốt nhất, vì có mẹo sau đây. Nếu đối thủ của bạn đi trước và chiếm trung tâm, anh ta sẽ giành chiến thắng. Nhưng trong lần di chuyển thứ hai, anh ta mắc lỗi khi cho phép bạn tạo một hình vuông 2x2, bạn nên lấy nó, vì điều này cho phép bạn buộc anh ta thực hiện ba lần liên tiếp. Điều này được thực hiện trong phiên bản golf. Trong trường hợp này cần thêm một ít mã để phân biệt giữa ba chữ X trong một góc (buộc đối thủ thua cuộc) và 3 chữ X dọc theo một cạnh (tự sát ngay lập tức.)

Ungolfed trong chương trình thử nghiệm

Phiên bản không được tuân theo logic được thể hiện trong câu hỏi.

Trong phiên bản golf, bảng được sửa đổi một chút [[0],[1,17],[9],[37,7,51,85],[45],[47,119]]để thực hiện hành vi hơi khác nhau cho trường hợp r=3. Sau đó, nó được nén thành ASCII có thể in (yêu cầu giải mã (t-36)%120). Cần thêm một chút logic để phân biệt giữa ba chữ X trong một góc và ba chữ X dọc theo một cạnh trong trường hợp của bảng 7:&&t+j%2!=43

f=->n{l=r=("%b"%n).sum%8                                      #convert input to text, take character checksum to count 1's(ASCII 49.) 
                                                              #0 is ASCII 48, so %8 removes unwanted checksum bloat of 48 per char.
                                                              #l must be initialised here for scoping reasons.
  [[0],[1,17],[9],[11,13,37,51,85],[45],[47,119]][r].each{|t| #according to r, find the list of acceptable perimeter bitmaps, and search for a solution.
    9.times{|i|(m=n|1<<i)==n||                                #OR 1<<i with input. if result == n, existing X overwritten, no good.
                                                              #ELSE new X is in vacant square, good. So.. 
      8.times{|j|m%256*257>>j&255==t&&l=m}}                   #%256 to strip off middle square. *257 to duplicate bitmap.
                                                              #rightshift, see if pattern matches t. If so, write to l
  }
l}                                                            #return l (the last acceptable solution found) as the answer.

#call function and pretty print output (not part of submission)
puts g=f[gets.to_i]
puts
[6,7,0,
 5,8,1,
4,3,2].each{|i|print g>>i&1; puts if i<3}

Đầu ra của chương trình thử nghiệm

Điều này xảy ra khi máy tính tự chơi.

C: \ Users \ steve> ruby ​​tictac.rb
0
256

000
010
000

C: \ Users \ steve> ruby ​​tictac.rb
256
384

010
010
000

C: \ Users \ steve> ruby ​​tictac.rb
384
400

010
010
100

C: \ Users \ steve> ruby ​​tictac.rb
400
404

010
010
101

C: \ Users \ steve> ruby ​​tictac.rb
404
436

010
110
101

C: \ Users \ steve> ruby ​​tictac.rb
436
444

010
110
111

PHÂN TÍCH CHƠI TRÒ CHƠI ĐẦU TIÊN

Điều này thực sự rất đơn giản và tuyến tính.

Khi chơi đầu tiên, hình vuông ở giữa sẽ luôn là hình vuông đầu tiên bị chiếm đóng.

r = 0

...  binary representation 0
.X.
...

r = 2

X..  binary representation 1001=9 
.XX
...

r = 4

X.. binary representation 101101=45
.XX
XX.

Chỉ có một cách (tối đa đối xứng) để có năm chữ X bao gồm hình vuông ở giữa trên bảng mà không có trò chơi kết thúc. Có một chữ X ở ô vuông ở giữa, một trên mỗi đường chéo (ở góc 90 độ với nhau) và một chữ trên mỗi đường trung tâm ngang / dọc (ở 90 độ với nhau.) Vì toàn bộ cạnh không thể bị chiếm ở trên sắp xếp có thể. Người chơi khác phải thua trong lần di chuyển tiếp theo.

PHÂN TÍCH CHƠI TRÒ CHƠI THỨ HAI

Chơi là khá khác nhau tùy thuộc nếu người chơi khác chọn hình vuông ở giữa.

r = 1

chiếm vuông giữa

.X. X..  binary representation 1 
.X. .X.
... ...

giữa vuông miễn phí

X.. .X. binary representation 10001=17
... ...
..X .X.

r = 3

Hình vuông ở giữa bị chiếm đóng, nếu người chơi khác chơi liền kề với X cuối cùng của bạn Chơi một hiệp sĩ di chuyển đi như bên dưới được hỗ trợ trong phiên bản không có người nhận

XX. .XX binary representation 1011=11 
.X. XX. or mirror image 1101=13
X.. ...

Tuy nhiên, ở trên KHÔNG phải là nước đi tốt nhất và không được hỗ trợ trong phiên bản chơi gôn. Động thái tốt nhất là như sau, buộc một chiến thắng ở lượt tiếp theo:

XX. binary representation 111=7.           XXX
XX. Only to be used where j is odd.        .X.
... Even j would look like image to right. ...

Hình vuông ở giữa bị chiếm đóng, nếu người chơi khác chơi ở 90 hoặc 135 độ so với chữ X cuối cùng của bạn (chơi di chuyển hiệp sĩ đi.)

X.X .X. binary representation 100101=37 
.X. .XX
.X. X..

Trung vuông miễn phí

X.X .X. XX. binary representations:
... X.X ...    1010101=85 (first two)
X.X .X. .XX and 110011=51 (last one)

r = 5

quảng trường trung chiếm. Vì những lý do đã nêu ở trên trong r = 4, có bốn động thái có thể xảy ra, tất cả đều mất. chỉ có một được hỗ trợ: 101111 = 47.

giữa vuông miễn phí. Chỉ có một bảng có thể lên đến đối xứng, như sau. Người chơi khác phải thua trong lần di chuyển tiếp theo, vì vậy không cần phải hỗ trợ r> 5.

XX. binary representation 1110111=119
X.X
.XX

Đây là một câu trả lời tuyệt vời! Tôi nghĩ rằng tôi đã kiểm tra tất cả các trường hợp cho moe tối ưu, nhưng tôi đoán tôi đã bỏ lỡ một. Thông số kỹ thuật sẽ giữ nguyên cho đơn giản, mặc dù. (! Thực sự điều này là tuyệt vời cảm ơn bạn đã làm điều này và điều này là rất tốt giải thích tôi rời I / O mất để mọi người có thể làm điều gì đó tuyệt vời như thế này.)
CAD97

1
Cảm ơn, đó là một thử thách thú vị. Bây giờ tôi đã xoay sở để chơi gôn hơn một chút.
Cấp sông St
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.