กากบาทไม่มีความเป็นเอกซ์


10

ทุกคนตระหนักดีว่าTic Tac Toeเป็นเกมที่แก้ไขแล้ว อย่างไรก็ตามรุ่น X-X ของMisèreให้ทางเลือกที่น่าสนใจ

ในเกมเวอร์ชั่นนี้ผู้เล่นทั้งสองเล่น Xs บนกระดานและพยายามหลีกเลี่ยงการสร้างสามแถวติดต่อกัน หากคุณต้องการดูเพิ่มเติมเกี่ยวกับเรื่องนี้Numberphileมีวิดีโอที่ดีเกี่ยวกับแนวคิดนี้

ให้บอร์ดของMisère Crosses เล่นท่าที่เหมาะสมที่สุด

คณะกรรมการเป็นสามบรรทัดสามตัวอักษรแต่ละที่หรือX ดังนั้น:

X X
X  
 XX

เป็นคณะกรรมการที่ถูกต้อง คุณสามารถทำได้ในรูปแบบที่สะดวกใด ๆ ตราบใดที่อินพุตและเอาต์พุตของคุณใช้รูปแบบเดียวกัน รูปแบบรวมถึง (แต่ไม่ จำกัด เฉพาะ): สตริงแบบหลายบรรทัด (ขึ้นบรรทัดใหม่ที่เป็นตัวเลือก); อาร์เรย์ 2 มิติของตัวละครที่เป็นXหรือ; อาร์เรย์บูลีน 1D ที่แบนราบของค่าบูลีนที่เป็นตัวแทนของแต่ละตำแหน่งที่เล่น

การย้ายที่ดีที่สุดคือสิ่งที่รับประกันว่าคุณจะชนะโดยการเล่นต่อไปอย่างเหมาะสมหรือยืดเวลาการสูญเสียของคุณให้นานที่สุดเท่าที่จะทำได้และถูกกำหนดโดยกฎต่อไปนี้:

  • หลีกเลี่ยงการทำสามในแถว
  • ถ้าคุณไปก่อนเล่นกลาง
  • หากมีเพียงพื้นที่ว่างที่อยู่ตรงกลางให้เล่นในพื้นที่ว่างที่เหลืออยู่
  • หากไม่ได้ครอบครองจัตุรัสกลางและจัตุรัสด้านนอกให้เล่นตรงข้ามกับการเล่นครั้งสุดท้ายของฝ่ายตรงข้าม
  • หากสแควร์กลางถูกครอบครองและสแควร์ด้านนอกคือเล่น "ย้ายอัศวิน" (ตรงข้ามมากกว่าหนึ่ง) ออกไปจากการย้ายก่อนหน้านี้ที่ไม่ทำให้คุณสูญเสีย
  • หากไม่มีสี่เหลี่ยมที่เหลืออยู่ซึ่งคุณจะไม่แพ้ให้เล่นในสี่เหลี่ยมที่เหลือ

[หมายเหตุ: สิ่งนี้ได้รับการพิสูจน์แล้วว่าไม่เหมาะสมในกรณีหนึ่งแต่คุณควรใช้อัลกอริทึมนี้ต่อไป]

คุณอาจคิดว่าการเคลื่อนไหวก่อนหน้านี้ทั้งหมดของคุณนั้นดีที่สุด ดังนั้นบอร์ดตัวอย่างแรกไม่ใช่อินพุตที่ถูกต้อง การเคลื่อนไหวของคู่ต่อสู้ของคุณอาจจะเหมาะสมหรือไม่ก็ได้

หากเกมจบลง (เช่นมีการทำสามในแถว) พฤติกรรมจะไม่ได้กำหนด

เช่นนี้คือคำตอบที่สั้นที่สุดในหน่วยไบต์ชนะ!

เส้นทางเดียวที่เป็นไปได้โดยใช้การเคลื่อนไหวที่ดีที่สุดเท่านั้นคือ:

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

นี่คืออินพุตที่เป็นไปได้ที่มาจากฝ่ายตรงข้ามโดยใช้การเคลื่อนไหวที่ไม่เหมาะสม:
(โปรดทราบว่าเฉพาะแผงด้านซ้ายในรายการนี้เป็นอินพุตที่ถูกต้อง)

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

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

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


รูปแบบอินพุตและเอาต์พุตคืออะไร ฉันสมมติว่าคณะกรรมการที่นำมาเป็นอาร์เรย์หรือสตริง? อย่างไรก็ตามสิ่งนี้ไม่ได้ให้ข้อมูลเกี่ยวกับการย้ายครั้งล่าสุดดังนั้นคำถามต่อไปของฉัน
เลเวลริเวอร์เซนต์

1
กลยุทธ์ "เล่นตรงข้ามของฝ่ายตรงข้ามเล่นล่าสุด" ถือว่าความรู้เกี่ยวกับประวัติความเป็นมาย้ายของฝ่ายตรงข้ามอย่างใดอย่างหนึ่งหรือว่าคุณได้ปฏิบัติตามก่อนหน้านี้กลยุทธ์นี้คือยังไม่ได้รับการถ่ายทอดคณะกรรมการเช่น.XX\nX..\nX..ตัวอย่างเช่น เราต้องพิจารณาบอร์ดที่สืบทอดเช่นนี้หรือไม่?
เลเวลริเวอร์เซนต์

@LevelRiverSt ตามที่เขียนไว้ว่า "คุณอาจสันนิษฐานว่าการเคลื่อนไหวก่อนหน้านี้ทั้งหมดของคุณนั้นดีที่สุด" ดังนั้นบอร์ดนั้นจะเป็นอินพุตที่ไม่ถูกต้อง คุณสามารถป้อนข้อมูลในรูปแบบใดก็ได้ที่คุณต้องการ แต่สตริงหลายบรรทัดเช่นตัวอย่างของคุณจะมี "ค่าเริ่มต้น": ฉันไม่ต้องการ จำกัด ใครให้แยกสตริงเมื่อตรรกะการย้ายเป็นจุดของ ความท้าทาย
CAD97

คำตอบ:


3

Ruby, Rev B 121 ไบต์

การส่งเป็นฟังก์ชันที่ไม่ระบุชื่อลบf=ด้วย แสดงในโปรแกรมทดสอบเพื่อแสดงการใช้งาน

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 ไบต์ที่บันทึกไว้โดยทำให้จัตุรัสกลางมีความสำคัญน้อยที่สุดแทนบิตที่สำคัญที่สุด (ลบโดย/2แทนที่จะเป็น%256) ที่เหลืออยู่โดยการปรับโครงสร้างองค์กรของตารางการเคลื่อนไหวที่ยอมรับได้ การจัดระเบียบเป็นศูนย์จัตุรัสว่าง / ครอบครองแทนโดยจำนวนทั้งหมดของ X ช่วยให้การทดสอบง่ายขึ้น นอกจากนี้ในตอนนี้มีเพียง 2 สตริงในอาเรย์ดังนั้น%w{string1 string2}ไวยากรณ์จึงถูกละทิ้งเนื่องจากเป็น["string1","string2"]ไวยากรณ์ สิ่งนี้ทำให้\7สามารถรวมอักขระที่ไม่สามารถพิมพ์ได้ซึ่งจะทำให้สามารถเข้ารหัสได้ง่ายขึ้น: 126-tแทนที่จะ(36-t)%120ใช้

Ruby, Rev A 143 ไบต์

->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}

นี่คือฟังก์ชั่นที่ไม่ระบุชื่อ รูปแบบอินพุต / เอาต์พุตเปิดทิ้งไว้ดังนั้นฉันจึงไปหาเลขฐานสองขนาด 9 บิต บิตของ 512 หมายถึงศูนย์กลางโดยที่บิตที่เหลือหมุนวนรอบมัน (บิตของ 1 ถือเป็นมุม)

มีอินพุตที่เป็นไปได้มากกว่าเอาต์พุตที่ยอมรับได้ดังนั้นอัลกอริทึมคือลองทุกการเคลื่อนไหวและค้นหาอินพุตที่เหมาะกับรูปแบบเอาต์พุตที่ยอมรับได้ รูปแบบเอาต์พุตที่ยอมรับได้สำหรับ X แต่ละจำนวนนั้นเป็นฮาร์ดโค้ด

ข้อมูลเกี่ยวกับจัตุรัสกลางถูกถอดออกและส่วนที่เหลืออีก 8 บิตจะถูกคูณด้วย 257 เพื่อทำซ้ำ รูปแบบนี้จะหมุนผ่านรูปแบบที่ยอมรับได้โดยการเลื่อนระดับสิทธิ์

การวนซ้ำไม่ออกเมื่อพบรูปแบบดังนั้นรูปแบบที่ส่งคืนจะเป็นรูปแบบที่ยอมรับได้ล่าสุด ด้วยเหตุนี้รูปแบบที่นิยม (ซึ่งมีการตั้งค่า) มาในภายหลังในรายการ

ด้วยกลยุทธ์ 'Knights move' มันมีความสำคัญเล็กน้อยไม่ว่าจะเป็นรูปแบบการหมุน 45 องศาหรือไม่ รุ่น ungolfed เป็นไปตามกลยุทธ์การย้ายของอัศวินและดังนั้นจึงไม่จำเป็นต้องแยกแยะความแตกต่างระหว่างมุมของสี่เหลี่ยมกับมุมของสี่เหลี่ยมจัตุรัส

อย่างไรก็ตามฉันพบว่านี่ไม่ใช่กลยุทธ์ที่ดีที่สุดเสมอเนื่องจากมีเคล็ดลับต่อไปนี้ หากฝ่ายตรงข้ามของคุณไปก่อนและใช้ศูนย์เขาควรจะชนะ แต่ในการย้ายครั้งที่สองของเขาเขาทำให้เกิดข้อผิดพลาดในการอนุญาตให้คุณสร้าง 2x2 ตารางคุณควรจะใช้มันเพราะสิ่งนี้ช่วยให้คุณบังคับให้เขาสร้างสามแถว นี่คือการดำเนินการในรุ่น golfed จำเป็นต้องมีรหัสพิเศษเล็กน้อยในอินสแตนซ์นี้เพื่อแยกความแตกต่างระหว่าง X สามตัวที่มุมหนึ่ง (บังคับให้คู่ต่อสู้แพ้) และ 3 X ตามขอบหนึ่ง (การฆ่าตัวตายทันที)

Ungolfed ในโปรแกรมทดสอบ

เวอร์ชันที่ไม่ดีขึ้นตามตรรกะที่แสดงในคำถาม

ในรุ่นแข็งแรงเล่นกอล์ฟตารางมีการแก้ไขเล็กน้อยเพื่อที่จะใช้ลักษณะการทำงานที่แตกต่างกันเล็กน้อยสำหรับกรณีที่[[0],[1,17],[9],[37,7,51,85],[45],[47,119]] r=3จากนั้นจะถูกบีบอัดเป็น ASCII ที่พิมพ์ได้ (ต้องการการถอดรหัส(t-36)%120) ต้องใช้ตรรกะเพิ่มเล็กน้อยเพื่อแยกความแตกต่างระหว่างสาม X ในมุมและสาม X ตามขอบในกรณีของรายการตาราง 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}

ผลลัพธ์ของโปรแกรมทดสอบ

สิ่งนี้จะเกิดขึ้นเมื่อคอมพิวเตอร์เล่นเอง

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

การวิเคราะห์การเล่นเกมครั้งแรก

นี่เป็นเรื่องง่ายและเป็นเส้นตรง

เมื่อเล่นก่อนสี่เหลี่ยมกลางจะเป็นสี่เหลี่ยมจัตุรัสแรกที่ถูกครอบครองเสมอ

r = 0

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

r = 2

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

r = 4

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

มีทางเดียวเท่านั้น (ขึ้นอยู่กับความสมมาตร) ที่มี X ห้าตัวรวมถึงจตุรัสกลางบนกระดานโดยที่เกมไม่จบ มี X ในช่องกลางตรงกลางแต่ละเส้นทแยงมุม (ที่ 90 องศาซึ่งกันและกัน) และอีกอันหนึ่งสำหรับแต่ละแนวนอน / แนวตั้งศูนย์กลาง (ที่ 90 องศาต่อกัน) เนื่องจากขอบทั้งหมดไม่สามารถครอบครองด้านบนได้เท่านั้น การจัดการที่เป็นไปได้ ผู้เล่นคนอื่นจะต้องแพ้ในการย้ายครั้งต่อไป

การวิเคราะห์การเล่นเกมที่สอง

การเล่นแตกต่างกันมากขึ้นอยู่กับว่าผู้เล่นคนอื่นเลือกจัตุรัสกลาง

r = 1

สแควร์กลางครอบครอง

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

จัตุรัสกลางฟรี

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

r = 3

Middle Square ครอบครองถ้าผู้เล่นคนอื่นเล่นติดกับ X สุดท้ายของคุณการเล่นเป็นอัศวินย้ายไปด้านล่างได้รับการสนับสนุนในรุ่น ungolfed

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

อย่างไรก็ตามข้างต้นไม่ได้เป็นการเคลื่อนไหวที่ดีที่สุดและไม่ได้รับการสนับสนุนในเวอร์ชั่น golfed การย้ายที่ดีที่สุดมีดังนี้บังคับให้ชนะในเทิร์นถัดไป:

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

จัตุรัสกลางถูกครอบครองหากผู้เล่นคนอื่นเล่นที่ 90 หรือ 135 องศาจนถึง X สุดท้ายของคุณ (เล่นเป็นอัศวินย้ายไป)

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

จัตุรัสกลางฟรี

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

r = 5

สแควร์กลางครอบครอง ด้วยเหตุผลที่กล่าวข้างต้นใน r = 4 มีการเคลื่อนไหวที่เป็นไปได้สี่อย่างซึ่งทั้งหมดจะเสีย รองรับเพียงหนึ่งเท่านั้น: 101111 = 47

จัตุรัสกลางฟรี มีบอร์ดเดียวที่เป็นไปได้จนถึงสมมาตรดังนี้ ผู้เล่นคนอื่นต้องแพ้ในการเคลื่อนที่ครั้งต่อไปดังนั้นจึงไม่จำเป็นต้องสนับสนุน r> 5

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

นี่คือคำตอบที่น่าอัศจรรย์! ฉันคิดว่าฉันได้ตรวจสอบทุกกรณีว่าดีที่สุด แต่ฉันคิดว่าฉันพลาดไป สเป็คจะยังคงเหมือนเดิมสำหรับความเรียบง่ายแม้ว่า (จริงๆแล้วมันยอดเยี่ยมมากขอบคุณสำหรับการทำสิ่งนี้และมันก็อธิบายได้ดีมาก! ฉันปล่อยให้ I / O เสียไปเพื่อให้ผู้คนสามารถทำสิ่งที่น่าอัศจรรย์เช่นนี้ได้)
CAD97

1
ขอบคุณมันเป็นความท้าทายที่น่าสนใจ ตอนนี้ฉันพยายามตีกอล์ฟอีกเล็กน้อย
เลเวลริเวอร์เซนต์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.