Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- แปลงมาจาก OX.py ในหนังสือ Artificial Intelligence
- with Machine Learning ของ รศ.ดร.ปริญญา สงวนสัตย์
- ]]
- --1) แก้ครั้งที่ 1 ลืมตรวจโค้ด function all() ปัญหา checkWin() แล้วได้ false ตลอด 5-12-18 23:12
- --2) แก้ครั้งที่ 2
- -- 2.1) แก้ function all() เพราะจำนวนสมาชิกใน t1 กับ t2 ไม่เท่ากัน
- -- 2.2) เพิ่มส่วนตรวจ X ชนะกรณีที่มี criticalMove
- --3) แก้ครั้งที่ 3
- -- 3.1) เอา 2.2 ออกเพิ่มการตรวจแถวที่มี X สองตำแหน่งและมีตำแหน่งว่างในแถวแทน
- -- 3.2) เปลี่ยนจากสุ่มเลือกตำแหน่งว่างใน criticalMove เป็นเอาตำแหน่งที่ยังว่างมาใช้เลยเพราะใน criticalMove มีตำแหน่งว่างค่าเดียว
- -- 3.3) เพิ่มการแปลงค่าที่ผู้เล่นป้อนให้เป็นจำนวนเต็มด้วยการปัดเศษ
- local O, X = {}, {}
- local win = {{1,2,3},
- {4,5,6},
- {7,8,9},
- {1,4,7},
- {2,5,8},
- {3,6,9},
- {1,5,9},
- {3,5,7}}
- local map = {"[_]","[_]","[_]",
- "[_]","[_]","[_]",
- "[_]","[_]","[_]"}
- local rnd = math.random
- local max = math.max
- --3) เพิ่มตัวย่อฟังก์ชั่นปัดเศษ
- local floor = math.floor
- function all(t1, t2)
- --table.sort(t1) --1) เพิ่มบรรทัดนี้ 2) แก้ออก
- local t = 0 --2 เพิ่มบรรทัดนี้ เก็บผลรวม
- --for i = 1, #t1 do --1) แก้ออก
- for j = 1, #t2 do
- for i = 1, #t1 do --2) เพิ่มบรรทัดนี้
- --if t1[j] ~= t2[j] then --1) เปลี่ยน t1[i] เป็น t1[j] 2) แก้ออก
- if t1[i] == t2[j] then --2) เปลี่ยน t1[j] เป็น t1[i] เปลี่ยนเป็นตรวจเท่ากัน
- t = t + 1 --2) เพิ่มบรรทัดนี้ เก็บจำนวนสมาชิกที่ตรงกัน
- --return false --2) แก้ออก
- if t == 3 then return true end --2) เพิ่มบรรทัดนี้ ถ้าสมาชิกใน t2 (table ของแถวที่สามารถชนะ) ทุกตัว(3)เป็นสมาชิกใน t1
- end
- end --2) เพิ่ม
- end
- --end --1) แก้ออก
- return false --2) เปลี่ยน true เป็น false
- end
- function any(t1, t2)
- local t = 0
- for i = 1, #t1 do
- for j = 1, #t2 do
- if t1[i] == t2[j] then
- t = t + 1
- end
- end
- end
- return t
- end
- function randomChoice(args)
- if type(args) == "table" then
- return args[rnd(#args)]
- elseif type(args) == "string" then
- local p = rnd(#args)
- return args:sub(p,p)
- end
- end
- function checkWin(P)
- for _, w in pairs(win) do
- if all(P, w) then
- return true
- end
- end
- return false
- end
- function displayOX()
- local newMap = {table.unpack(map)}
- if #O > 0 then
- for o = 1, #O do
- newMap[O[o]] = "[O]"
- end
- end
- if #X > 0 then
- for x = 1, #X do
- newMap[X[x]] = "[X]"
- end
- end
- for i = 1, #newMap, 3 do
- print(newMap[i]..newMap[i+1]..newMap[i+2])
- end
- end
- function ai()
- local validMove = {1,2,3,4,5,6,7,8,9}
- --ลบตาเดินใน O กับ X ออกจาก validMove
- --0) เดิมใช้เปลี่ยนค่าใน validMove ที่ตรงกับ O และ X เป็น 0 แล้วค่อยมาลบออก
- --for o = 1, #O do
- --validMove[O[o]] = 0
- --end
- --for x = 1, #X do
- --validMove[X[x]] = 0
- --end
- --for i = #validMove, 1, -1 do
- --if validMove[i] == 0 then
- --table.remove(validMove,i)
- --end
- --end
- --0.5) ปรับเป็นรวม O กับ X เป็น moved ก่อนแล้วลบออกจาก validMove
- --เร็วขึ้นกว่าเดิมหน่อยโค้ดสั้นลงลดไปหนึ่งลูป
- local moved = {table.unpack(O)}
- for _, v in pairs(X) do
- table.insert(moved,v)
- end
- table.sort(moved, function(a,b) return a>b end)
- for _, v in pairs(moved) do
- table.remove(validMove,v)
- end
- --3) เพิ่มส่วน ai เลือกตำแหน่งว่างในแถวที่มี X อยู่สองตำแหน่ง
- for _, w in pairs(win) do
- local cX = any(X,w)
- for _, i in pairs(w) do
- for _, j in pairs(validMove) do
- if cX == 2 and i == j then
- return i
- end
- end
- end
- end
- local V = {-100,-100,-100,-100,-100,-100,-100,-100,-100}
- for _, v in pairs(validMove) do
- local tempX, criticalMove = {table.unpack(X)}, {}
- table.insert(tempX,v)
- V[v], criticalMove = evalOX(O,tempX)
- if #criticalMove > 0 then
- --3) เอาส่วนนี้ออก
- --2) เพิ่มส่วน ai ถึง O จะใกล้ชนะแต่เป็นตาของ X ถ้าเลือกแล้วชนะเกมก็ให้ใช้ค่านี้ไม่ต้องไปเลือกใน criticalMove อีก
- --if checkWin(tempX) then
- --return v
- --end
- --3) เอา move ออก
- local move = {}
- for _, i in pairs(validMove) do
- for _, j in pairs(criticalMove) do
- if j == i then
- --3) เปลี่ยนจากเอาค่าใส่ table เป็นคืนค่านั้นกลับ
- table.insert(move,j)
- return j
- end
- end
- end
- --3) เอาออก
- return randomChoice(move)
- end
- end
- local maxV = max(table.unpack(V))
- local imaxV = {}
- for i, v in pairs(V) do
- if v == maxV then
- table.insert(imaxV,i)
- end
- end
- return randomChoice(imaxV)
- end
- function evalOX(o,x)
- local SO, SX, criticalMove =calSOX(o,x)
- return (1 + SX - SO), criticalMove
- end
- function calSOX(o,x)
- local SO, SX = 0, 0
- local criticalMove = {}
- for _, w in pairs(win) do
- local cO = any(o,w)
- local cX = any(x,w)
- if cX == 0 then
- SO = SO + cO
- if cO == 2 then
- print("critical", "{".. table.concat(w,",").."}")
- criticalMove = w
- end
- end
- if cO == 0 then
- SX = SX + cX
- end
- end
- return SO, SX, criticalMove
- end
- while true do
- io.write("Choose position [1-9]: ")
- local move = tonumber(io.read())
- print("")
- goto checkMove
- ::chooseAgain::
- io.write("Bad move: choose position [1-9]: ")
- move = tonumber(io.read())
- print("")
- ::checkMove::
- if not move then
- goto chooseAgain
- --3) เปลี่ยนให้แปลง move แป็นจำนวนเต็มด้วยการปัดเศษก่อนตรวจหาช่วงของ move
- --elseif move > 9 or move < 1 then
- --goto chooseAgain
- else
- move = floor(move)
- if move > 9 or move < 1 then
- goto chooseAgain
- end
- end
- for _, v in pairs(O) do
- if move == v then
- goto chooseAgain
- end
- end
- for _, v in pairs(X) do
- if move == v then
- goto chooseAgain
- end
- end
- table.insert(O,move)
- displayOX()
- if checkWin(O) then
- print("O win")
- break
- end
- if #O + #X == 9 then
- print("Draw")
- break
- end
- table.insert(X,ai())
- displayOX()
- if checkWin(X) then
- print("X win")
- break
- end
- --2) เอาออกไม่ต้องใช้ตรวจเฉพาะในตาของ O ก็พอ
- --if #O + #X == 9 then
- --print("Draw")
- --break
- --end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement