การค้นหาและ AI สำหรับเกม: A* และ minimax ใน Python
AI แบบดั้งเดิมแก้ปัญหาด้วยการค้นหาในสถานะที่เป็นไปได้ A* หาเส้นทางที่ถูกที่สุดโดยรวมต้นทุนที่เดินมาแล้วกับค่าประมาณต้นทุนที่เหลือ ส่วน minimax เลือกตาเดินในเกมสองผู้เล่นโดยสมมติว่าคู่แข่งเล่นได้ดี
แนวคิดแบบเข้าใจง่าย
AI แบบดั้งเดิมแก้ปัญหาด้วยการค้นหาในสถานะที่เป็นไปได้ A* หาเส้นทางที่ถูกที่สุดโดยรวมต้นทุนที่เดินมาแล้วกับค่าประมาณต้นทุนที่เหลือ ส่วน minimax เลือกตาเดินในเกมสองผู้เล่นโดยสมมติว่าคู่แข่งเล่นได้ดี
หาเส้นทางที่สั้นที่สุดบนตารางด้วยการค้นหา A* และเลือกตาเดินที่ดีที่สุดในเกมด้วย minimax
ประเด็นสำคัญ
- A* หาเส้นทางที่ดีที่สุดได้เมื่อค่าประมาณ (heuristic) ไม่เคยเกินต้นทุนจริง
- minimax ค้นในต้นไม้เกมจนถึงความลึกที่กำหนดหรือจนจบเกม
- การตัดแต่งแบบ alpha-beta ข้ามกิ่งที่ไม่สามารถเปลี่ยนการตัดสินใจได้
- อัลกอริทึมเชิงพันธุกรรมค้นหาด้วยวิธีต่างออกไป คือวิวัฒนาการประชากรของคำตอบที่เป็นไปได้
ควรใช้เมื่อใด?
- เข้าใจสิ่งที่เกิดขึ้นภายในโครงข่ายประสาทเทียมและไลบรารี AI
- เข้าใจแนวคิดก่อนลงมือเขียนเองในโจทย์ที่เกี่ยวข้อง
- เตรียมตัวสำหรับคอร์สแมชชีนเลิร์นนิง การสัมภาษณ์งาน และโปรเจกต์
ลองดูการทำงานจริง
กด เล่น เพื่อดู A* สำรวจตาราง คลิกที่ช่องเพื่อเพิ่มหรือลบกำแพง ในต้นไม้เกม คลิกที่ใบเพื่อเปลี่ยนคะแนน
โค้ดตัวอย่าง
import heapq
# A* finds the cheapest path using cost so far + a guess of the cost left.
grid = ["S..#",
".#..",
"...G"]
start, goal = (0, 0), (2, 3)
guess = lambda r, c: abs(r - goal[0]) + abs(c - goal[1]) # Manhattan distance
frontier = [(guess(*start), 0, start, [start])]
seen = set()
while frontier:
_, cost, (r, c), path = heapq.heappop(frontier)
if (r, c) == goal:
print("path:", path, "cost:", cost)
break
if (r, c) in seen:
continue
seen.add((r, c))
for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
nr, nc = r + dr, c + dc
if 0 <= nr < 3 and 0 <= nc < 4 and grid[nr][nc] != "#":
heapq.heappush(frontier, (cost + 1 + guess(nr, nc), cost + 1, (nr, nc), path + [(nr, nc)]))
# Minimax: the maximizer assumes the opponent always picks the worst for it.
def minimax(node, maximizing):
if isinstance(node, int):
return node
values = [minimax(child, not maximizing) for child in node]
return max(values) if maximizing else min(values)
tree = [[3, 5], [2, 9], [0, 7]] # our move, then the opponent's reply
print("best guaranteed score:", minimax(tree, True))
ผลลัพธ์ที่คาดหวัง
path: [(0, 0), (0, 1), (0, 2), (1, 2), (1, 3), (2, 3)] cost: 5
best guaranteed score: 3
หลักการทำงาน
คิวลำดับความสำคัญจะขยายช่องที่มีต้นทุน + ค่าประมาณน้อยที่สุดเสมอ โดยค่าประมาณคือระยะแมนฮัตตันถึงเป้าหมาย A* จึงไปถึง G ใน 5 ก้าวโดยอ้อมกำแพง ส่วน minimax() เลือกค่าสูงสุดในตาของเราและค่าต่ำสุดในตาของคู่แข่ง ตาเดินแรกรับประกันได้ 3 ซึ่งดีที่สุดในบรรดากรณีแย่ที่สุดทั้งสาม
เปลี่ยนค่าและรันโปรแกรมด้วย คอมไพเลอร์ Python ออนไลน์ของ CodeUtility โดยไม่ต้องติดตั้ง Python
แบบฝึกหัด
ลองเปลี่ยน input และทดสอบกรณีขอบก่อนใช้ชุดข้อมูลที่ใหญ่ขึ้น
- เปลี่ยนอินพุตหรือน้ำหนัก แล้วลองทายผลลัพธ์ก่อนรัน
- พิมพ์ค่าระหว่างทางออกมาเพื่อดูการคำนวณทีละขั้น
- แก้โจทย์ที่ลิงก์ไว้ด้านล่างเพื่อเขียนแนวคิดนี้ด้วยตัวเอง
ฝึกด้วยโจทย์
ใช้สิ่งที่เรียนในบทนี้แก้ปัญหาจริง ทุกโจทย์รันในเบราว์เซอร์ พร้อมการทดสอบทันทีและรีวิวจาก AI
- การค้นหา A* บนตารางที่มีน้ำหนัก หาเส้นทางที่ถูกที่สุดผ่านตารางค่าใช้จ่ายของภูมิประเทศด้วย A* อัลกอริทึมค้นหาที่อยู่เบื้องหลังการหาเส้นทางในเกมและหุ่นยนต์ ปานกลาง
- เกม OX ด้วย Minimax เลือกตาเดินที่สมบูรณ์แบบในเกม OX โดยค้นหาต้นไม้เกมทั้งหมดด้วย minimax ปานกลาง
- การตัดกิ่งแบบ Alpha-Beta ประเมินต้นไม้เกมด้วย minimax และการตัดกิ่งแบบ alpha-beta แล้วนับว่าการค้นหาดูใบไม้จริง ๆ กี่ใบ ปานกลาง
- หนึ่งรุ่นของอัลกอริทึมเชิงพันธุกรรม สร้างสตริงบิตรุ่นถัดไปด้วยการคัดเลือกแบบทัวร์นาเมนต์ การไขว้จุดเดียว และการกลายพันธุ์ ปานกลาง