การทำ Ai เกมเป่ายิ้งฉุบโดยที่ Ai สามารถหลอกเราได้ว่า Ai จะออกอะไรและออกจริงหรือไม่

เกริ่นกันก่อนคือไอเดียของ Ai ตัวนี้เกิดจากการดูอนิเมะเรื่อง No Game No Life โดยเรามีต้นแบบ Ai เกมเป่ายิ้งฉุบมาจากเว็บนี้ https://rockpaperscissors-ai.vercel.app Github ของทางต้นฉบับ https://github.com/arifikhsan/batu-gunting-kertas-nuxt โดยบทความนี้จะเน้นการใช้วิธีการคาดเดาของ Ai และการชั่งน้ำหนักว่า Ai ควรจะออกอะไรเพื่อที่จะชนะผู้เล่น โดยหลักการของบทความนี้คือการจะออกอะไรไม่ว่า กรรไกร ค้อน หรือ กระดาษ ก็คือเมื่อฝั่งของ Ai มีการหลอกว่าจะออกกระดาษ ทำให้อัตราการที่จะไม่เสียแต้มคือ 2/3 จากทั้งหมด ตารางการชนะและเสมอจึงเป็นดังนี้ รูปภาพจาก NO Game No Life ตอนที่ 2 ในรูปมีกติการอื่นของอนิเมะอยู่ด้วยแต่อยากให้สนใจตารางเป็นหลักนะคับ https://youtu.be/3OayLAQil2Y?si=hEBWE9YhyaR_7Tnm&t=317 อันนี้คือตารางแบบปกติแบบที่ยังไม่มีการหลอก และอันนี้คือกรณีที่ Ai ออกกระดาษจริงๆตรงตามที่เราคิดโดยไม่มีการหลอกเกิดขึ้น และในส่วนสุดท้ายคือกรณีที่ Ai หลอกเราสำเร็จไม่ว่าจะเป็นการล่อให้เราออกกรรไกร หรือ ทำให้เราเชื่ออีกทีว่า Ai จะออกค้อนมาเพื่อชนะผู้เล่น แต่ที่นี้ถ้าเราอยากทำให้ Ai ชนะเราได้ละเราต้องทำยังไง ❓ ผมเลยจึงเอาหลักการของ Ai จากทางต้นฉบับนี้มาปรับเปลี่ยนเพื่อให้เข้ากับกติกาของเราแทน โดยหลักการของทางต้นฉบับที่ใช้หลักๆเลยจะเป็น Markov Chains หรือก็คือการคาดเดาความน่าจะเป็นในปัจจุบันโดยไม่อิงข้อมูลจากอดีต ตัวอย่าง การคาดเดาสภาพอากาศ โดยถ้าเป็น Markov Chains จะใช้ข้อมูลของวันนี้เพื่อเดาสภาพอากาศของวันพรุ่งนี้ตามค่าความน่าจะเป็น เช่นวันนี้แดดออกก็จะใช้ตารางของการที่แดดออกในการคาดเดา เช่นวันนี้แดดออกพรุ่งนี้ก็มีโอกาสแดดออกอีก 0.7 เป็นค่าน้ำหนักที่นำไปคำนวนต่อ 0.7 = 70% เป็นต้น เราจึงได้นำสิ่งนี้มาปรับใช้ในงานของเรานั้นเองโดยอาจจะไม่ได้ใช้ตรงๆแต่เป็นการนำมาเพื่อเป็นแนวคิด โดยหลักการที่เราจะนำมาใช้คือ Rule-Based System เพื่อใช้กำหนดกติกาเกม Behavioral Pattern Recognition ใช้เพื่อมีการจำรูปแบบของผู้เล่นเพื่อทำเป็นค่าน้ำหนักสำหรับคำนวณต่อว่าผู้เล่นจะออกอะไร Probabilistic Reasoning สำหรับการคาดการณ์โดยอิงจากความน่าจะเป็น Utility-Based Decision Making หรือก็คือการประเมินค่าน้ำหนักของแต่ละตัวเลือกเพื่อเลือกทางที่ดีที่สุด โดยอธิบายกติกาก่อนที่จะเริ่มอธิบายโค้ด เกมเป่ายิ้งฉุบนี้จะให้ผู้เล่นแข่งกับ Ai โดย Ai จะทำการบอกว่าจะออกอะไรโดยจริงหรือหลอกผู้เล่นไม่มีทางรู้และเมื่อมีใครได้แต้มครบ 10 แต้มก่อนจะเป็นผู้ชนะ โดยจะเล่นกันบน Terminal ขั้นตอนที่ 1 คือการกำหนดข้อมูลพื้นฐานก่อน เป็นการกำหนดข้อมูลพื้นฐานสำหรับเกมๆนี้และกำหนดไฟล์สำหรับเซฟข้อมูลต่างๆ import random import os # === CONFIG === choices = ["rock", "paper", "scissors"] choice_map = {1: "scissors", 2: "rock", 3: "paper"} beats = {"rock": "scissors", "paper": "rock", "scissors": "paper"} score_file = "rock_paper_score.txt" ขั้นตอนที่ 2 เก็บข้อมูลต่างๆ โดยจะมีหลักๆคือประวัติการออกของผู้เล่นและผลแต่ละรอบ # === GAME STATE === rounds = 0 player_score = 0 ai_score = 0 player_history = [] round_history = [] bluff_success_count = 0 bluff_attempts = 0 ขั้นตอนที่ 3 ล้างหน้าจอเพื่อที่จะให้ Ui ดูง่ายตอนเล่น def clear_screen(): os.system('cls' if os.name == 'nt' else 'clear') ขั้นตอนที่ 4 วิเคราะห์ความน่าจะเป็นการออกของผู้เล่น โดยวิเคราะห์แนวโน้มการเล่นของผู้เล่น จากสิ่งที่ผู้เล่นเคยออกแต่ถ้าเป็นตาแรก total จะเท่ากับ 0 จึงให้เป็นการเดาออกไปแบบ 1/3 ทุกอัน และตรงนี้ยังใช้เพื่อให้ Ai นำข้อมูลไปใช้ต่อได้ว่าจะออกอะไรหรือล่อให้ Player ออกอะไรเหมือนเพิ่มอัตราการสิ่งๆนั้นของผู้เล่นเพิ่มขึ้น def predict_player_probabilities(): total = len(player_history) if total == 0: return {"rock": 1/3, "paper": 1/3, "scissors": 1/3} return { "rock": player_history.count("rock") / total, "paper": player_history.count("paper") / total, "scissors": player_history.count("scissors") / total } ขั้นตอนที่ 5 เลือกว่าจะหลอกอะไรผู้เล่น โดยส่วนนี้นั้นจะเป็นการหลอกผู้เล่นว่าจะออกอะไรโดยการนำข้อมูลขั้นตอนที่ 4 มาโดยเมื่อ Ai หาได้แล้วว่าผู้เล่นชอบออกอะไรก็จะทำการหลอกสิ่งที่แพ้สิ่งที่ผู้เล่นชอบออกออกไปยังผู้เล่น เช่น probs = {"rock": 0.6, "paper": 0.3, "scissors": 0.1} ดังนั้น likely_player_move = "rock" ส่วนที่อธิบายมาจากโค้ดตรงนี้ likely_player_move = max(probs, key=probs.get) def choose_bluff(probs): likely_player_move = max(probs, key=probs.get) bluff = beats[likely_player_move] return bluff, likely_player_move ขั้นตอนที่ 6 เลือกสิ่งที่ AI จะออกจริง โดยรวม bluff เข้าไปด้วย โดยค่า blend_factor=0.5 คือค่าที่จะกำหนดว่าให้ใช้ Logic เป็นหลักหรือการหลอกเป็นหลักซึ่ง ในกรณี 0.5 คือใช้ทั้งสองฝั่งแบบสมดุล โดยฟังก์ชันนี้นั้นที่ทำให้ AI ฉลาด โดยการ “ตัดสินใจอย่างมีเหตุผล” + “ใช้กลยุทธ์บัฟ” เพื่อเลือกสิ่งที่มีโอกาสชนะสูงที่สุด def ai_choice_with_bluff_blend(player_probs, expected_player_move, blend_factor=0.5): win_weights = { "rock": player_probs["scissors"], "paper": player_probs["rock"], "scissors": player_probs["paper"] } bluff_target = beats[expected_player_move] for move in win_weights: if move == bluff_target: win_weights[move] += blend_factor best_move = max(win_weights, key=win_weights.get) return best_move, win_weights ขั้นตอนที่ 7 เช็คผู้ชนะ

Apr 11, 2025 - 14:47
 0
การทำ Ai เกมเป่ายิ้งฉุบโดยที่ Ai สามารถหลอกเราได้ว่า Ai จะออกอะไรและออกจริงหรือไม่

เกริ่นกันก่อนคือไอเดียของ Ai ตัวนี้เกิดจากการดูอนิเมะเรื่อง No Game No Life โดยเรามีต้นแบบ Ai เกมเป่ายิ้งฉุบมาจากเว็บนี้
https://rockpaperscissors-ai.vercel.app
Github ของทางต้นฉบับ https://github.com/arifikhsan/batu-gunting-kertas-nuxt

โดยบทความนี้จะเน้นการใช้วิธีการคาดเดาของ Ai และการชั่งน้ำหนักว่า Ai ควรจะออกอะไรเพื่อที่จะชนะผู้เล่น

โดยหลักการของบทความนี้คือการจะออกอะไรไม่ว่า กรรไกร ค้อน หรือ กระดาษ ก็คือเมื่อฝั่งของ Ai มีการหลอกว่าจะออกกระดาษ ทำให้อัตราการที่จะไม่เสียแต้มคือ 2/3 จากทั้งหมด
ตารางการชนะและเสมอจึงเป็นดังนี้

Image description
รูปภาพจาก NO Game No Life ตอนที่ 2
ในรูปมีกติการอื่นของอนิเมะอยู่ด้วยแต่อยากให้สนใจตารางเป็นหลักนะคับ
https://youtu.be/3OayLAQil2Y?si=hEBWE9YhyaR_7Tnm&t=317

อันนี้คือตารางแบบปกติแบบที่ยังไม่มีการหลอก

Image description

และอันนี้คือกรณีที่ Ai ออกกระดาษจริงๆตรงตามที่เราคิดโดยไม่มีการหลอกเกิดขึ้น

Image description

และในส่วนสุดท้ายคือกรณีที่ Ai หลอกเราสำเร็จไม่ว่าจะเป็นการล่อให้เราออกกรรไกร หรือ ทำให้เราเชื่ออีกทีว่า Ai จะออกค้อนมาเพื่อชนะผู้เล่น

Image description

แต่ที่นี้ถ้าเราอยากทำให้ Ai ชนะเราได้ละเราต้องทำยังไง ❓
ผมเลยจึงเอาหลักการของ Ai จากทางต้นฉบับนี้มาปรับเปลี่ยนเพื่อให้เข้ากับกติกาของเราแทน
โดยหลักการของทางต้นฉบับที่ใช้หลักๆเลยจะเป็น
Markov Chains หรือก็คือการคาดเดาความน่าจะเป็นในปัจจุบันโดยไม่อิงข้อมูลจากอดีต
ตัวอย่าง
การคาดเดาสภาพอากาศ

Image description

โดยถ้าเป็น Markov Chains จะใช้ข้อมูลของวันนี้เพื่อเดาสภาพอากาศของวันพรุ่งนี้ตามค่าความน่าจะเป็น เช่นวันนี้แดดออกก็จะใช้ตารางของการที่แดดออกในการคาดเดา เช่นวันนี้แดดออกพรุ่งนี้ก็มีโอกาสแดดออกอีก 0.7 เป็นค่าน้ำหนักที่นำไปคำนวนต่อ 0.7 = 70% เป็นต้น

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

โดยหลักการที่เราจะนำมาใช้คือ
Rule-Based System เพื่อใช้กำหนดกติกาเกม

Behavioral Pattern Recognition ใช้เพื่อมีการจำรูปแบบของผู้เล่นเพื่อทำเป็นค่าน้ำหนักสำหรับคำนวณต่อว่าผู้เล่นจะออกอะไร

Probabilistic Reasoning สำหรับการคาดการณ์โดยอิงจากความน่าจะเป็น

Utility-Based Decision Making หรือก็คือการประเมินค่าน้ำหนักของแต่ละตัวเลือกเพื่อเลือกทางที่ดีที่สุด

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

ขั้นตอนที่ 1 คือการกำหนดข้อมูลพื้นฐานก่อน

เป็นการกำหนดข้อมูลพื้นฐานสำหรับเกมๆนี้และกำหนดไฟล์สำหรับเซฟข้อมูลต่างๆ

import random
import os

# === CONFIG ===
choices = ["rock", "paper", "scissors"]
choice_map = {1: "scissors", 2: "rock", 3: "paper"}
beats = {"rock": "scissors", "paper": "rock", "scissors": "paper"}
score_file = "rock_paper_score.txt"

ขั้นตอนที่ 2 เก็บข้อมูลต่างๆ

โดยจะมีหลักๆคือประวัติการออกของผู้เล่นและผลแต่ละรอบ

# === GAME STATE ===
rounds = 0
player_score = 0
ai_score = 0
player_history = []
round_history = []
bluff_success_count = 0
bluff_attempts = 0

ขั้นตอนที่ 3 ล้างหน้าจอเพื่อที่จะให้ Ui ดูง่ายตอนเล่น

def clear_screen():
    os.system('cls' if os.name == 'nt' else 'clear')

ขั้นตอนที่ 4 วิเคราะห์ความน่าจะเป็นการออกของผู้เล่น

โดยวิเคราะห์แนวโน้มการเล่นของผู้เล่น จากสิ่งที่ผู้เล่นเคยออกแต่ถ้าเป็นตาแรก total จะเท่ากับ 0 จึงให้เป็นการเดาออกไปแบบ 1/3 ทุกอัน และตรงนี้ยังใช้เพื่อให้ Ai นำข้อมูลไปใช้ต่อได้ว่าจะออกอะไรหรือล่อให้ Player ออกอะไรเหมือนเพิ่มอัตราการสิ่งๆนั้นของผู้เล่นเพิ่มขึ้น

def predict_player_probabilities():
    total = len(player_history)
    if total == 0:
        return {"rock": 1/3, "paper": 1/3, "scissors": 1/3}
    return {
        "rock": player_history.count("rock") / total,
        "paper": player_history.count("paper") / total,
        "scissors": player_history.count("scissors") / total
    }

ขั้นตอนที่ 5 เลือกว่าจะหลอกอะไรผู้เล่น

โดยส่วนนี้นั้นจะเป็นการหลอกผู้เล่นว่าจะออกอะไรโดยการนำข้อมูลขั้นตอนที่ 4 มาโดยเมื่อ Ai หาได้แล้วว่าผู้เล่นชอบออกอะไรก็จะทำการหลอกสิ่งที่แพ้สิ่งที่ผู้เล่นชอบออกออกไปยังผู้เล่น
เช่น
probs = {"rock": 0.6, "paper": 0.3, "scissors": 0.1} ดังนั้น likely_player_move = "rock"

ส่วนที่อธิบายมาจากโค้ดตรงนี้
likely_player_move = max(probs, key=probs.get)

def choose_bluff(probs):
    likely_player_move = max(probs, key=probs.get)
    bluff = beats[likely_player_move]
    return bluff, likely_player_move

ขั้นตอนที่ 6 เลือกสิ่งที่ AI จะออกจริง โดยรวม bluff เข้าไปด้วย

โดยค่า blend_factor=0.5 คือค่าที่จะกำหนดว่าให้ใช้ Logic เป็นหลักหรือการหลอกเป็นหลักซึ่ง
ในกรณี 0.5 คือใช้ทั้งสองฝั่งแบบสมดุล

โดยฟังก์ชันนี้นั้นที่ทำให้ AI ฉลาด
โดยการ “ตัดสินใจอย่างมีเหตุผล” + “ใช้กลยุทธ์บัฟ” เพื่อเลือกสิ่งที่มีโอกาสชนะสูงที่สุด

def ai_choice_with_bluff_blend(player_probs, expected_player_move, blend_factor=0.5):
    win_weights = {
        "rock": player_probs["scissors"],
        "paper": player_probs["rock"],
        "scissors": player_probs["paper"]
    }
    bluff_target = beats[expected_player_move]
    for move in win_weights:
        if move == bluff_target:
            win_weights[move] += blend_factor
    best_move = max(win_weights, key=win_weights.get)
    return best_move, win_weights

ขั้นตอนที่ 7 เช็คผู้ชนะ

def get_result(player, ai):
    if player == ai:
        return "Draw!"
    elif beats[player] == ai:
        return "You win!"
    else:
        return "AI wins!"

ขั้นตอนที่ 8 แสดงผลลัพธ์ของรอบและ Ui ต่างๆ

def display_round(player_move, ai_move, result, bluff, round_num):
    clear_screen()
    print("=" * 40)
    print(f"