Machine Learning in Action : เริ่มต้นด้วยเกมเล็กๆอย่าง Tic Tac Toe

มีไอเดียอยากลองทำเกมง่ายๆ ที่สามารถเรียนรู้ หรือพัฒนาตนเองได้ด้วยประสบการณ์ที่ตัวมันได้พบเจอมา ซึ่งมันก็มีหลายเทคนิคที่มีใช้กันอยู่ และที่เห็นว่าน่าสนใจก็เป็น Q-Learning และ Minimax ทั้งสองเทคนิคล้วนแล้วแต่เป็น State–Action–Reward–State คือ เริ่มต้นคิดจาก State ปัจจุบัน เพื่อหา Action และประเมินผลเป็น Reward จาก State อีกที ซึ่งเหมาะสมมากที่จะนำมาใช้ในระบบเกม

ส่วนเกมที่สนใจจะนำมาทดลองนั้น ก็เป็นเกมง่ายๆ อย่างเกม Tic Tac Toe ที่มีรูปแบบไม่เยอะมากนัก กฎกติกาไม่ซับซ้อน และเป็นการแข่งขันกันของสองผู้เล่น ทำให้ระบบสามารถเรียนรู้ หรือเลียนแบบ วิธีการเล่นของฝั่งตรงข้ามได้โดยง่าย ผ่าน State ที่ได้บันทึกไว้ก่อนหน้านี้เท่านั้นเอง

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

เริ่มต้นออกแบบ

เราจะแบ่งระบบออกเป็น 3 ส่วนใหญ่ๆ ดังนั้น

  1. ส่วนของระบบเกม การจัดการแสดงตาราง การจัดการ Turn ของผู้เล่น รับค่า Input จากคีย์บอร์ด การกำหนดผู้เริ่มเล่น
  2. ส่วนของการตัดสินเกม ระบบนี้จะทำงานเมื่อเกมสิ้นสุดลง และตัดสินผลของเกม
  3. ส่วนของตัว Machine ที่สามารถเรียนรู้ และตัดสินใจในการเล่นแข่งขันกับผู้เล่นที่เป็นมนุษย์

ระบบเกมส์

เริ่มที่การกำหนดวิธีการเล่น และการใช้งานของเกมส์นี้
โดยเราจะเล่นผ่าน Console Terminal เป็นหลัก เพื่อลดภาระงานการออกแบบ Graphic ที่ไม่ใช่จุดประสงค์หลักของสิ่งที่เรากำลังจะทำนี้ ทำให้สภาวะแวดล้อมของเกมส์จะมีลักษณะประมาณนี้ครับ

  • พื้นที่ในเกมส์ จะเป็นตารางขนาด 3×3 ช่อง รวมแล้วมี 9 ช่อง: กำหนดให้ค่า 1 – 9 แทนตำแหน่งของแต่ละช่องของตาราง
  • สถานะของแต่ละช่อง มี 3 สถานะ คือ X , O และ ว่าง: กำหนดให้ X มีค่าเป็น 1 , O มีค่าเป็น -1 และสถานะว่างมีค่าเป็น 0 เพื่อให้สามารถทำการคำนวณทางคณิตศาสตร์ได้ง่ายมากขึ้น
  • กำหนดให้ X เป็นผู้เริ่มเล่นก่อนเสมอ เพื่อให้ง่ายต่อการสร้าง State ให้กับบอต
  • มีการคำนวนส่วนตัดสินเกมทุกครั้งที่จบ Turn
  • แสดงตารางในสภาวะปัจจุบันหลังจบ Turn

การตัดสินเกม

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

  • คำนวนผลจากตาราง ณ ปัจจุบัน
  • ให้ผลว่าใครเป็นผู้ชนะ เมื่อ X เป็นผู้ชนะ ให้ผล 1 , เมื่อ O เป็นผู้ชนะ ให้ผล -1 , เสมอให้ผลเป็น 0 และถ้าเกมส์ยังไม่จบ ให้ผล None เพื่อให้ระบบเกมทำงานต่อไป

ระบบ Machine

ใช้ วิธี Minimax ในการประเมินสถานการณ์และตัดสินใจว่า Machine ควรจะตอบสนองต่อสถานการณ์นั้นอย่างไร

  • บันทึกตารางในแต่ละสถานะ
  • สร้างความสัมพันธ์ระหว่างสถานะ
  • คำนวนค่าความสัมพันธ์ระหว่างสถานะ
  • ตัดสินใจเลือกการกระทำจากค่าความสัมพันธ์ระหว่างสถานการณ์ปัจจุบันกับสถานะถัดไป
  • เมื่อไม่มีสถานะที่เหมาะสม ให้ทำการสุ่มเล่น

ระบบตัดสินเกม

เป็นฟังก์ชันง่ายๆ ที่เริ่มโดยรับค่าตาราง ณ เวลาปัจจุบันเข้ามา
เริ่มต้นตรวจสอบว่ามีช่องว่างเหลืออยู่บนตารางหรือไม่

แล้วคำนวนตามแกนต่างๆ ว่ามีแกนใดที่มีหมากของผู้เล่นวางเรียงกัน ทำให้มีผลรวมของค่าสัมบูรณ์แล้วเท่ากับ 3 บ้าง ถ้าหากมีก็ส่งค่าของผู้ชนะกลับไป

แต่หากว่ายังไม่มีผู้ชนะ แต่ไม่มีช่องว่างบนตารางเหลืออยู่แล้ว จะถือว่าเกมนี้จบลงด้วยผลเสมอ ค่าที่ส่งคือ 0

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

นี่คือฟังก์ชันที่เราจะใช้ตรวจสอบ และตัดสินเกม Tic – Tac – Toe ของเราครับ

ระบบเกม

ฟังก์ชันการแสดงผลตาราง

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

ตาราง Tic Tac Toe ที่ต้องการ

เพื่อความสะดวก จึงสร้างเป็นฟังก์ชันง่ายๆ ขึ้นมา เพื่อใช้ในการแสดงตารางแทน
โดยการแทนค่าตัวเลขที่อยู่ในลิสต์ ด้วยตัวอักษร X , O และช่องว่าง ในตำแหน่งที่ถูกต้องแล้วนำมันมาแสดงผล

ตัวแปร List สำหรับเก็บค่าไว้แสดงผล

วนแทนค่าจากตารางในระบบ ให้เป็นตารางสำหรับแสดงผล

ส่วนแสดงผลผ่าน Terminal

ฟังก์ชันรับค่าจากคีย์บอร์ด

ฟังก์ชันนี้จะรับค่าตำแหน่ง 1 – 9 จากคีย์บอร์ด และตรวจสอบว่าค่าที่ได้รับเหมาะสมและใช้งานได้หรือไม่ ก่อนที่จะส่งค่าตำแหน่งที่เล่นคืนกลับสู่ระบบเกม เพื่อให้เกมดำเนินต่อไป

ส่วนการตรวจสอบช่องว่างบนตารางที่สามารถเล่นได้

ส่วนของการวนรับค่า และตรวจสอบข้อมูลที่ได้รับว่าใช้งานได้หรือไม่

ฟังก์ชันการเคลียร์ Terminal

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

ฟังก์ชันการอัปเดตตาราง

เพราะระบบของเกมจะต้องรองรับทั้งค่าที่ได้รับจากคีย์บอร์ด และค่าที่ได้จาก Machine
ดังนั้นจึงทำฟังก์ชันขึ้นมา เพื่อให้ทั้งสองวิธีสามารถส่งผ่านตำแหน่งการเล่นของตนไปสู่ตารางเดียวกันได้

ระบบเกมหลัก

เกมจะเริ่มต้นที่ การเลือกว่าจะให้ Machine เล่นกับใคร โดยมี 3 ตัวเลือกคือ

  1. You VS Machine
  2. Random VS Machine
  3. Machine VS Machine
เลือก Mode การเล่น

โค้ดส่วนการเลือก Mode ของเกม ซึ่งจะวนถาม/รับค่า ไปจนกว่าคำตอบนั้นจะเหมาะสมกับตัวเลือกที่มีให้

เมื่อเลือก Mode เรียบร้อย เกมจะให้เราเลือกว่า เราจะเป็นฝ่ายเริ่มก่อนหรือไม่
ถ้าเราจะเริ่มเล่นก่อนให้ตอบ Y แล้วกด Enter

เราจะเลือกเริ่มเกมส์ก่อนหรือไม่

โค้ดที่ใช้รับค่าและตรวจสอบค่าที่ได้รับ ซึ่งจะทำงานก็ต่อเมื่อเราเล่นใน Mode ในข้อ 1 เท่านั้น

โค้ดในส่วนที่ใช้จัดการลำดับการเล่นของผู้เล่นในแต่ละ Turn
โดยมีตัวแปล current_player เป็นตัวกำหนดว่ารอบเป็น Turn ของ X หรือ O
และในแต่ละ Turn จะถูกจัดการตาม Mode ที่ได้เลือกไว้ก่อนหน้านี้
ตารางจะอัพเดทผ่านฟังก์ชัน play_move ที่ถูกสร้างไว้ก่อนหน้า

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

หลังจบเกมในกรณีที่เลือก Mode 1 จะมีการถามว่า ยังจะเล่นต่ออีกหรือไม่
และใน Mode 2 จะมีการสลับกันเล่นของ Machine กับการเล่นแบบสุ่ม

ระบบ Machine

กระบวนการตัดสินใจของ Machine

แนวคิดของ Minimax หรือ Q-Learning นั้น มีการใช้ State เพื่อกำหนด Action โดยเลือกจาก Reward ที่เหมาะสมที่สุดจากความสัมพันธ์ของ State กับ State

ตัวอย่างความสัมพันธ์ระหว่าง State 9 กับ State 10 , 14 และ 23

ซึ่งในตัวอย่าง ณ ปัจจุบัน เป็น State ที่ 9 ซึ่งนั่นคือสถานะที่เกิดจากการเล่นของอีกฝั่ง ใน Turn ของ Machine ดังที่เห็นว่า Machine เรียนรู้มามีเพียง 3 ทางเลือกเท่านั้น
สิ่งสำคัญคือ ต้องทำให้ Machine รับรู้ได้ว่า แต่ละเส้นทางของทั้ง 3 ทางเลือกนั้น ทางเลือกใดเหมาะสมที่สุด ในวิธี Minimax นั้น จะใช้ขนาดของคะแนนเป็นเกณฑ์ในการตัดสินใจ ว่าจะเลือกเส้นทางใด ดังนั้นเราจึงต้องสร้างกระบวนการประเมินคะแนนให้กับแต่ละ State ที่ Machine สามารถเลือกได้

การคำนวนคะแนน Reward

เงื่อนไขของคะแนนที่จะต้องมีคือ

  • จะต้องแยกได้ว่าใครแพ้ ใครชนะ และเสมอได้ เพราะ Machine จะต้องเลือกทางที่ตนมีโอกาสชนะมากที่สุด หรือดักทางที่ตนมีโอกาสมากที่สุด
  • ขนาดคะแนนจะต้องลดความสำคัญลงตามความลึกของลำดับการเล่นได้ เพื่อให้สามารถเปรียบเทียบได้ว่า Machine หรือ คู่ต่อสู้ จะเป็นผู้ชนะก่อนในเส้นทางนั้น

จากระบบเกมส์ที่เก็บค่าบนตารางด้วยการใช้ค่า 1 , 0 และ -1 แทนพื้นที่บนตาราง
จึงมองว่าก็สามารถเอาค่านั้นมาเป็น Reward หรือคะแนน เพื่อแทนสักษณะของสถานการณ์นั้นได้เช่นกัน เช่นถ้าหากว่า X เป็นผู้ชนะ Reward ก็จะมีค่าเป็น 1 เหมือนกับที่ระบบเกมใช้ 1 แทน X บนตาราง หรือหาก O เป็นผู้ชนะ Reward จะมีค่าเป็น -1 และหากผลคือเสมอ Reward จะมีค่าเป็น 0

และลำดับชั้นที่อยู่ถัดขึ้นไปจากสถานะนั้น Reward ก็จะถูกลดทอนลงด้วยค่า Discount ไปเรื่อยๆ ดังนั้น ยิ่งสถานะ แพ้ – ชนะ อยู่ลึกลงไปจากสถานะปัจจุบันมากเท่าไร คะแนนก็จะมีผลสัมบูรณ์ลดลงไปเรื่อยๆ ดังนั้นจากคะแนนของแต่ละ State ก็จะทำให้ Machine มองเห็นว่า แต่ละ State ให้ผลอย่างไรในอนาคต เป็นประโยชน์ต่อตนเองมากแค่ไหน

การเปรียบเทียบคะแนน

สิ่งสำคัญอีกอย่างในการตัดสินใจคือ การเปรียบเทียบคะแนน
ในกรณีนี้เลือกที่จะใช้ผลสัมบูรณ์ที่มากที่สุดของ State ที่สัมพันธ์กันกับ State ปัจจุบัน แล้วคูณด้วยค่า Discount เพื่อลดทอนลงตามลำดับชั้นที่สูงขึ้น มาเป็นคะแนนของ State นี้
เหตุที่ใช้ค่าสัมบูรณ์ เนื่องจากว่า จะต้องคำนึงถึง State ที่คู่ต่อสู้จะเล่นเพื่อเอาชนะ Machine ด้วย เช่นกรณีตัวอย่างของความสัมพันธ์นี้

State ที่ 9 นั้น O ไม่ควรเล่นแบบนี้ เพราะ O มีโอกาสแพ้ได้สูงมาก
ถ้าหากว่า State ที่ 10 มี Reward เป็น 1 เนื่องจาก X เป็นผู้ชนะ State ที่ 9 Reward ก็ควรมีค่าเป็น 0.9 หลังจากผ่านการคูณด้วยค่า Discount แล้ว ถ้าหากว่าเราทำการเปรียบเทียบกับค่าใน State อื่นแล้ว 0.9 นี้ก็น่าจะเป็นค่าที่มากที่สุดแล้ว เพราะชัยชนะของ X อยู่ใกล้มาก
แต่ถ้าเราสนใจเลือก State ที่มีคะแนนน้อยที่สุด ซึ่งดูเหมาะสมกับ O ที่มีคะแนนเป็นลบ
เพื่อจะเลี่ยง State ที่ 9 ที่มีคะแนนเป็นบวกได้ และ State 19 ก็ดูจะเหมาะสมกว่า
แต่ถ้าออกแบบให้ระบบส่งคะแนนที่น้อยที่สุดเสมอ เมื่อคำนวนแล้วจะพบว่า State 9 จะไม่มีคะแนนเป็น 0.9 แล้ว เพราะ State 9 มี 2 State สัมพันธ์อยู่ คือ 10 และ 14 ซึ่ง State 14 มีคะแนนน้อยกว่า State 10 ดังนั้น State 14 จะถูกคำนวน และส่งมาเป็นคะแนนของ State 9
ทำให้ Machine อาจจะได้รับข้อมูลที่ผิดไปจากสถานการณ์ และทำให้ตัดสินใจผิดพลาดได้ ตามการคำนวนข้างล่าง

ตัวอย่างในกรณีที่คิดคำนวณคะแนนจากค่าที่น้อยที่สุดเป็นเกณฑ์

ดังนั้นเราจึงเปลี่ยนแนวคิดใหม่ มาใช้เป็นการเปรียบเทียบจากค่าสัมบูรณ์ที่มากที่สุด แล้วค่อยมาดูว่า แท้จริงค่านั้นเหมือนหรือแตกต่าง จากสิ่งที่ต้องการ เช่นหากว่า Machine เล่นในฐานะ O คะแนนที่มีผลดีที่สุดของ O คือ -1 หรือค่าที่น้อยที่สุด แต่หากว่าเป็น X คะแนนที่มีผลดีที่สุดคือ 1 หรือค่าที่มากที่สุด แต่เพื่อให้ Machine สามารถเอาตัวรอดจากสถานการณ์ตัวอย่างก่อนหน้าได้ Machine จึงต้องประเมินจากการเปรียบเทียบด้วยค่าสัมบูรณ์ ซึ่งจะทำให้ Machine จะต้องเจอสถานการณ์ 2 แบบ นั่นคือ

  • แบบแรก คะแนนจริงเป็นผลดีต่อ Machine เช่นเล่นเป็น O ก็มีค่า เป็นลบ หรือเล่นเป็น X คะแนนก็มีค่าเป็น บวก ซึ่ง Machine จะสามารถทำตามสถานการณ์นั้นได้ทันที
  • แบบที่สอง คะแนนจริงเป็นผลตรงข้ามต่อ Machine เช่นเล่นเป็น O แต่คะแนนเป็น บวก หรือ เล่นเป็น X แต่คะแนนเป็น ลบ ซึ่งจะเป็นสถานการณ์ที่แย่ที่สุดที่สามารถเกิดขึ้นได้ เท่าที่ Machine รู้จัก

ในกรณีของแบบแรก Machine จะสามารถเล่นตามสถานการณ์นั้นได้ทันที
แต่หากว่าเป็นในกรณีของแบบที่สอง Machine จะต้องเล่นในสถานการณ์ของ State ฝั่งคู่ต่อสู้ ที่อยู่ลึกลงไปอีก 1 ขึ้น เช่น Machine เล่นเป็น O อยู่ใน State 18
สมมติว่า State ที่ 9 คือ State ที่มีค่าสัมบูรณ์สูงที่สุด วิธีที่ Machine จะต้องทำคือ เดินลึกลงไปจาก State ที่ 9 อีก 1 ขั้น ซึ่งมี 2 State คือ 10 และ 14 และเลือกเล่นใน State ที่มีค่าสัมบูรณ์มากที่สุดของ State ที่ 9 นั่นคือ State ที่ 10 ในตำแหน่งการเล่นของ X จะทำให้สถานการณ์กลายมาเป็น State ที่ 19 ไปแทน ซึ่ง O จะยังไม่แพ้โดยง่าย

ตัวอย่างการคิดโดยใช้ค่าสัมบูรณ์

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

สรุปกระบวนการตัดสินใจของ Machine

  1. รับคะแนน แพ้ ชนะ เสมอ จากผลตัดสินของเกม ใน State สุดท้ายที่เกิดขึ้นนั้น
  2. เปรียบเทียบคะแนนโดยเลือก State ที่มีผลสัมบูรณ์ของคะแนนที่มากที่สุดเป็นหลัก
  3. คำนวนคะแนนของ State นั้นโดยคูณกับค่า Discount เพื่อลดทอนคะแนนลงตามความลึกของ State

การทำงานของ Machine

เพื่อให้เกมสามารถเล่นได้ต่อเนื่อง ตัว Machine จำเป็นจะต้องมีการเก็บสถานะไว้ เพื่อให้สามารถนำกลับมาใช้ได้ในครั้งต่อไป ดังนั้นระบบของ Machine จะเริ่มที่การโหลดสถานะที่เก็บไว้ขึ้นมา แล้วจึงเริ่มเกม

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

การบันทึกและนำข้อมูลกลับมาใช้ใหม่

ในกรณีนี้เพื่อให้ง่ายต่อการใช้งาน และการตรวจสอบ จึงเลือกที่จะเก็บข้อมูลไว้ใน รูปแบบไฟล์ JSON และข้อมูลสถานะของ Machine จะเก็บในตัวแปรรูปแบบ Dictionary ของ Python ซึ่งสามารถแปลงไปเป็น JSON และแปลงกลับมาได้ไม่ยาก

ฟังค์ชันการดึงข้อมูลกลับมาใส่ตัวแปร state_action ซึ่งชื่อไฟล์ จะถูกตั้งไว้เป็น Default ในตัวแปร state_action_fname

ฟังค์ชั่นการบันทึกข้อมูล

สำหรับกรณีที่ Machine อยู่ใน State ที่ไม่รู้จัก จะเล่นแบบสุ่ม
ก็จะเลือกใช้ฟังก์ชันนี้ในการเล่นแบบสุ่ม โดยจะสุ่มจากช่องว่างที่มีอยู่บนตาราง

การเก็บ State และสร้างความสัมพันธ์ของ State

Machine จะเก็บ State และผลตัดสินจากระบบ
ซึ่ง Machine จะใช้ State ในการค้นหา โดยจะเปรียบเทียบกับ State ที่มีอยู่ก่อนแล้ว ถ้าหากพบว่ามี State ตรงกับที่มีอยู่แล้ว ค่าลำดับของ State นั้นจะถูกเพิ่มเข้าในส่วนของ ‘next’ ของ State ที่อยู่ในลำดับการเล่นก่อนหน้านั้น เป็นการสร้างความสัมพันธ์ระหว่าง State กัน

แต่ถ้าหาก State นั้น ไม่ปรากฎในข้อมูลที่มีอยู่แล้ว ระบบจะสร้างค่าลำดับใหม่ และนำลำดับนั้นไปเพิ่มเข้าใน ‘next’ ของ State ที่เล่นในลำดับก่อนหน้าเพื่อสร้างความสัมพันธ์ของ State

ถ้าหาก State นั้น มีผลตัดสินแล้ว จะมีการใส่ส่วนของคะแนนลงใน State นั้นด้วย

ส่วนของการค้นหา ผ่านฟังก์ชัน find_state

ส่วนของการเพิ่ม State ในลำดับการเล่นก่อนหน้า

โค้ดในส่วนของการอัปเดต State ของ Machine

การคำนวณคะแนนของแต่ละ State

รูปแบบการทำงาน จะใช้เป็นแบบ Recursive Function ซึ่งจะวนเรียกตัวฟังก์ชันตามจำนวนของ State ที่มีความสัมพันธ์กับ State ที่เป็นปัจจุบัน ลงไปทีละ State จนสุด
ซึ่งจะทำให้ระบบสามารถประเมินคะแนนของทุก State ที่มีความสัมพันธ์กับ State ปัจจุบันได้อย่างถูกต้อง

ตัวอย่างการทำงานของฟังก์ชัน ตามลูกศร เริ่มที่ลูกศรสีส้มจาก State 18 ไปยัง State 9 จากซ้ายไปขวา

ทิศทางการทำงานของฟังค์ชั่นประเมินคะแนน

โค้ดในฟังก์ชันที่ใช้ในการเรียกตัวเอง เพื่อทำงานตาม State ที่สัมพันธ์กับ State นั้นๆ

ส่วนของการประเมินคะแนนของ State จะเลือกใช้เฉพาะคะแนนจาก State ที่มีคะแนนมากที่สุดจาก State ทั้งหมดที่มีความสัมพันธ์กับ State นี้

โค้ดที่ใช้เลือกและคำนวณคะแนน

การตัดสินใจจากคะแนนของแต่ละ State

ตัว Machine จะเลือก State ไว้ 2 State คือ State ที่มี Score สูงที่สุด และมี Score น้อยที่สุด เพื่อใช้ให้เหมาะสมสำหรับทั้ง กรณีที่เล่นทั้ง X และ O ซึ่งหลังจากได้ Score มากที่สุด และน้อยที่สุดแล้ว จึงค่อยนำมาใช้ในกรณีที่เล่นเป็น X หรือ O

โค้ดในส่วนที่หา Score น้อยที่สุด และมากที่สุด

โค้ดส่วนการเลือก State ในการเล่น ที่เหมาะสมกับ State ในปัจจุบัน

โค้ดฟังก์ชันการเลือกเล่น

ฟังก์ชันสำหรับใช้งาน

เพื่อให้สามารถเรียกใช้งานได้ง่าย จึงควรรวมฟังก์ชันการคิดคะแนน และการเลือกเล่นไว้รวมกัน รวมถึงทำให้ค่าที่ได้จากฟังก์ชันเหมาะสมกับการทำงานของระบบเกม ทำให้ไม่ต้องแก้ระบบเกมให้มารองรับฟังก์ชันของ Machine โดยเฉพาะ

โค้ดส่วนการตรวจสอบช่องว่างที่สามารถเล่นได้

โค้ดส่วนของการคิดคะแนนและการหา State ที่เหมาะสมในการเล่น

โค้ดส่วนของการตรวจสอบ State และหาช่องว่างที่เหมาะสมในการเล่น

เริ่มที่ตรวจสอบว่าตำแหน่งที่ต้องการค้นหานั้นจะมีค่าเป็น -1 หรือ 1

ค้นหาดูว่าตำแหน่งที่ว่างอยู่นั้น มีค่าที่ต้องการอยู่หรือไม่

ถ้าหากว่าตำแหน่งนั้นเล่นได้ ก็จะใช้ค่าตำแหน่งนั้นในการเล่น
แต่หากว่าตำแหน่งนั้นไม่พร้อมที่จะให้เล่นได้ ก็จะเปลี่ยนไปค้นหาด้วยค่าของฝั่งตรงข้ามแทน

แต่หากว่ายังคงไม่พบตำแหน่งที่ควรจะเล่น Machine จะทำสุ่มเล่นจากตำแหน่งที่เล่นได้

โค้ดฟังก์ชันใช้งาน

ฟังก์ชันสำหรับแสดงความสัมพันธ์ของ State

เพื่อให้เราสามารถเห็นภาพความสัมพันธ์ของ State ปัจจุบัน กับ State อื่นๆ ที่เกี่ยวข้องกัน รวมถึงคะแนนของแต่ละ State ได้ชัดเจนมากยิ่งขึ้น
ในส่วนนี้เราใช้ networkx เพื่อสร้างกราฟแสดงความสัมพันธ์

สร้าง G เป็นแบบ DiGraph
โดยความสัมพันธ์จะถูกเก็บไว้ในตัวแปร listEdge ที่ถูกอัพเดทในฟังก์ชัน คำนวณคะแนน score_calculate

เปลี่ยน Label ของ Node ให้แสดงชื่อและคะแนนของ State

คำนวนค่าเพื่อแสดงคะแนน บนกราฟ

เพื่อให้สามารถเรียกใช้ฟังก์ชันนี้ได้ จะต้อง เอาคอมเมนต์ของบรรนทัดนี้ออกไปเสียก่อน

เมื่อ Machine ทำงาน ระบบจะมีการแสดงภาพความสัมพันธ์ดังตัวอย่าง

ภาพตัวอย่างแสดงความสัมพันธ์ของ State และคะแนน
ภาพตัวอย่างแสดงความสัมพันธ์ของ State และคะแนน

โค้ดสำหรับแสดงความสัมพันธ์ของ State

Library ที่ใช้

สามารถติดตั้งจากไฟล์ text โดยใช้คำสั่ง pip install -r <ชื่อไฟล์> ได้
ในไฟล์ text นั้นมีเนื้อหาดังนี้

การใช้งาน

ระบบจะมีไฟล์ประกอบด้วยกัน 4 ไฟล์คือ

  1. main.py
  2. markovDT.py
  3. state_action.json
  4. requirement.txt

เริ่มต้นด้วยเรียกคำสั่ง python เพื่อรันไฟล์ main.py

เริ่มเข้าเกมส์

เลือกว่าจะเริ่มเล่นก่อนหรือไม่

เริ่มเล่นเกมส์ก่อน

เริ่มเล่นเกม

วาง X ลงในตำแหน่งที่ 1

Machine ประมวลผล และเลือกวาง O ลงในตำแหน่งที่ 5

Machine วาง O ในตำแหน่งที่ 5

เล่นแบบนี้ไปจนจบเกมส์

เมื่อจบเกมส์ จะมีการรายงานผล และสรุปสถานะต่างๆ

เมื่อเกมสิ้นสุดลง จะมีคำถามให้เลือกว่าจะเล่นต่ออีกหรือไม่

ไฟล์ที่ใช้

ไฟล์ทั้งหมดสามารถ Download ได้ที่ https://github.com/playelek/Tik-Tak-Toe.git

ไฟล์ state_action.json จะเป็นไฟล์ว่างเปล่า ซึ่งจะเอาไว้เก็บ State

สรุป

ทั้งหมดนี้ทำขึ้นเพียงเพื่อทดลอง และใช้เล่นสนุกๆเท่านั้น
และยังมีช่องว่างให้ถูกพัฒนาต่อได้อีกมาก เช่นการใช้ประโยชน์จากความสมมาตรของตาราง ที่สามารถหมุนตารางก่อน แล้วค่อยนำมาเปรียบเทียบ หรือการทำ Mirror ตาราง ก่อนจะนำมาเปรียบเทียบ ซึ่งจะทำให้รูปแบบของเกมลดลงไปอย่างมาก

นอกจากนี้ตัว Machine ยังเปิดช่องให้สามารภนำเอาเทคนิคอื่นๆมาปรับใช้ได้อีกด้วย เช่นการใช้ Neural Network มาแทน ก็สามารถทำได้ ซึ่งถ้ามีโอกาสจะลองทำมาแบ่งปันกันอีกครั้ง

อ้างอิง

minimax
https://stackabuse.com/minimax-and-alpha-beta-pruning-in-python/
https://towardsdatascience.com/create-ai-for-your-own-board-game-from-scratch-minimax-part-2-517e1c1e3362
https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-1-introduction/
https://dev.to/nestedsoftware/tic-tac-toe-with-the-minimax-algorithm-5988

networkx
https://www.geeksforgeeks.org/operations-on-graph-and-special-graphs-using-networkx-module-python/
https://towardsdatascience.com/python-interactive-network-visualization-using-networkx-plotly-and-dash-e44749161ed7
https://www.geeksforgeeks.org/ml-reinforcement-learning-algorithm-python-implementation-using-q-learning/