โจทย์
Minimax คือวิธีที่โปรแกรมเล่นเกมใช้เลือกตาเดิน: สมมติว่าผู้เล่นทั้งสองเล่นได้สมบูรณ์แบบ ให้คะแนนทุกเกมที่จบแล้ว แล้วส่งคะแนนขึ้นไปตามต้นไม้เกม ผู้เล่นที่ถึงตาจะเลือกลูกที่ได้คะแนนสูงสุดสำหรับตัวเอง
กระดานเป็นสตริง 9 ตัวอักษรที่อ่านทีละแถว (index 0-8) ประกอบด้วย "X", "O" หรือ "." สำหรับช่องว่าง X เดินก่อนเสมอ ดังนั้นเป็นตาของ X เมื่อทั้งสองฝ่ายมีจำนวนเครื่องหมายเท่ากัน มิฉะนั้นเป็นตาของ O
ให้คะแนนเกมที่จบแล้วจากมุมมองของผู้เล่นที่ถึงตา: +1 ถ้าชนะ 0 ถ้าเสมอ -1 ถ้าแพ้ คืนช่องว่างที่ตาเดินนั้นได้คะแนน minimax ดีที่สุด ถ้ามีหลายช่องดีเท่ากัน ให้คืน index ที่น้อยที่สุด
จง implement best_move(board)
อินพุต
board: ตำแหน่งที่ถูกต้อง ยังไม่มีใครชนะ และมีช่องว่างอย่างน้อยหนึ่งช่อง
เอาต์พุต
คืน index (0-8) ของตาเดินที่ดีที่สุด
เงื่อนไข
board มี 9 ตัวอักษรพอดี แต่ละตัวคือ X, O หรือ .
ตำแหน่งนี้เกิดขึ้นได้ในเกมจริง ยังไม่มีใครชนะ และมีช่องว่างอย่างน้อยหนึ่งช่อง
ตัวอย่าง
อินพุต:
board = "XX.OO...."
ผลลัพธ์ที่คาดหวัง:
expected = 2
อินพุต:
std::string board = "XX.OO....";
ผลลัพธ์ที่คาดหวัง:
long long expected = 2;
อินพุต:
string board = "XX.OO....";
ผลลัพธ์ที่คาดหวัง:
long expected = 2;
คำอธิบาย
X และ O มีฝ่ายละสองเครื่องหมาย จึงเป็นตาของ X การลงที่ 2 ทำให้แถวบนสุดครบและชนะทันที (+1)
อินพุต:
board = "X..OO...X"
ผลลัพธ์ที่คาดหวัง:
expected = 5
อินพุต:
std::string board = "X..OO...X";
ผลลัพธ์ที่คาดหวัง:
long long expected = 5;
อินพุต:
string board = "X..OO...X";
ผลลัพธ์ที่คาดหวัง:
long expected = 5;
คำอธิบาย
เป็นตาของ X โดย O กำลังขู่จะทำแถวกลางให้ครบที่ช่อง 5 ตาเดินอื่นทั้งหมดทำให้ O ชนะ (-1) ส่วนการกันที่ 5 นำไปสู่การเสมอ (0) คำตอบจึงเป็น 5
แนวทางการแก้
ลองทำเองก่อน แล้วค่อยเปิดคำใบ้ทีละข้อ
คำใบ้ 1
หาว่าเป็นตาของใครจากจำนวน X และ O แล้วประเมินทุก move ที่ถูกต้องแบบ recursive
คำใบ้ 2
ให้คะแนนกระดานที่จบเกมจากมุมมองของผู้เล่นปัจจุบัน แล้วเลือก move ที่ทำให้ค่านั้นสูงสุด
คำใบ้ 3
ถ้า move หลายอันได้คะแนนเท่ากัน ให้เก็บช่องว่างที่มี index แรกสุด และต้องตรวจ win ก่อนพิจารณา move ถัดไป
ความซับซ้อนที่คาดหวัง
เวลา O(9!), หน่วยความจำเพิ่ม O(9)
แหล่งอ้างอิง
โจทย์นี้ปรับให้เหมาะกับ CodeUtility กรุณาทำตามคำชี้แจงและข้อจำกัดด้านบน