Advertisement
wwwRong

ox_game

Dec 5th, 2019
613
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.39 KB | None | 0 0
  1. --[[
  2.   แปลงมาจาก OX.py ในหนังสือ Artificial Intelligence
  3.   with Machine Learning ของ รศ.ดร.ปริญญา สงวนสัตย์
  4. ]]
  5. --1) แก้ครั้งที่ 1 ลืมตรวจโค้ด function all() ปัญหา checkWin() แล้วได้ false ตลอด 5-12-18 23:12
  6. --2) แก้ครั้งที่ 2
  7. -- 2.1) แก้ function all() เพราะจำนวนสมาชิกใน t1 กับ t2 ไม่เท่ากัน
  8. -- 2.2) เพิ่มส่วนตรวจ X ชนะกรณีที่มี criticalMove
  9. --3) แก้ครั้งที่ 3
  10. -- 3.1) เอา 2.2 ออกเพิ่มการตรวจแถวที่มี X สองตำแหน่งและมีตำแหน่งว่างในแถวแทน
  11. -- 3.2) เปลี่ยนจากสุ่มเลือกตำแหน่งว่างใน criticalMove เป็นเอาตำแหน่งที่ยังว่างมาใช้เลยเพราะใน criticalMove มีตำแหน่งว่างค่าเดียว
  12. -- 3.3) เพิ่มการแปลงค่าที่ผู้เล่นป้อนให้เป็นจำนวนเต็มด้วยการปัดเศษ
  13. local O, X = {}, {}
  14. local win = {{1,2,3},
  15.             {4,5,6},
  16.             {7,8,9},
  17.             {1,4,7},
  18.             {2,5,8},
  19.             {3,6,9},
  20.             {1,5,9},
  21.             {3,5,7}}
  22. local map = {"[_]","[_]","[_]",
  23.             "[_]","[_]","[_]",
  24.             "[_]","[_]","[_]"}
  25. local rnd = math.random
  26. local max = math.max
  27. --3) เพิ่มตัวย่อฟังก์ชั่นปัดเศษ
  28. local floor = math.floor
  29.  
  30. function all(t1, t2)
  31.   --table.sort(t1) --1) เพิ่มบรรทัดนี้ 2) แก้ออก
  32.   local t = 0 --2 เพิ่มบรรทัดนี้ เก็บผลรวม
  33.   --for i = 1, #t1 do --1) แก้ออก
  34.     for j = 1, #t2 do
  35.     for i = 1, #t1 do --2) เพิ่มบรรทัดนี้
  36.       --if t1[j] ~= t2[j] then  --1) เปลี่ยน t1[i] เป็น t1[j] 2) แก้ออก
  37.       if t1[i] == t2[j] then  --2) เปลี่ยน t1[j] เป็น t1[i] เปลี่ยนเป็นตรวจเท่ากัน
  38.         t = t + 1  --2) เพิ่มบรรทัดนี้ เก็บจำนวนสมาชิกที่ตรงกัน
  39.         --return false  --2) แก้ออก
  40.         if t == 3 then return true end --2) เพิ่มบรรทัดนี้ ถ้าสมาชิกใน t2 (table ของแถวที่สามารถชนะ) ทุกตัว(3)เป็นสมาชิกใน t1
  41.       end
  42.     end  --2) เพิ่ม
  43.     end
  44.   --end --1) แก้ออก
  45.   return false --2) เปลี่ยน true เป็น false
  46. end
  47.  
  48. function any(t1, t2)
  49.   local t = 0
  50.   for i = 1, #t1 do
  51.     for j = 1, #t2 do
  52.       if t1[i] == t2[j] then
  53.         t = t + 1
  54.       end
  55.     end
  56.   end
  57.   return t
  58. end
  59.  
  60. function randomChoice(args)
  61.   if type(args) == "table" then
  62.     return args[rnd(#args)]
  63.   elseif type(args) == "string" then
  64.     local p = rnd(#args)
  65.     return args:sub(p,p)
  66.   end
  67. end
  68.  
  69. function checkWin(P)
  70.   for _, w in pairs(win) do
  71.     if all(P, w) then
  72.       return true
  73.     end
  74.   end
  75.   return false
  76. end
  77.  
  78. function displayOX()
  79.   local newMap = {table.unpack(map)}
  80.   if #O > 0 then
  81.     for o = 1, #O do
  82.       newMap[O[o]] = "[O]"
  83.     end
  84.   end
  85.   if #X > 0 then
  86.     for x = 1, #X do
  87.       newMap[X[x]] = "[X]"
  88.     end
  89.   end
  90.   for i = 1, #newMap, 3 do
  91.     print(newMap[i]..newMap[i+1]..newMap[i+2])
  92.   end
  93. end
  94.  
  95. function ai()
  96.   local validMove = {1,2,3,4,5,6,7,8,9}
  97.   --ลบตาเดินใน O กับ X ออกจาก validMove
  98.   --0) เดิมใช้เปลี่ยนค่าใน validMove ที่ตรงกับ O และ X เป็น 0 แล้วค่อยมาลบออก
  99.   --for o = 1, #O do
  100.     --validMove[O[o]] = 0
  101.   --end
  102.   --for x = 1, #X do
  103.     --validMove[X[x]] = 0
  104.   --end
  105.   --for i = #validMove, 1, -1 do
  106.     --if validMove[i] == 0 then
  107.       --table.remove(validMove,i)
  108.     --end
  109.   --end
  110.   --0.5) ปรับเป็นรวม O กับ X เป็น moved ก่อนแล้วลบออกจาก validMove
  111.   --เร็วขึ้นกว่าเดิมหน่อยโค้ดสั้นลงลดไปหนึ่งลูป
  112.   local moved = {table.unpack(O)}
  113.   for _, v in pairs(X) do
  114.     table.insert(moved,v)
  115.   end
  116.   table.sort(moved, function(a,b) return a>b end)
  117.   for _, v in pairs(moved) do
  118.     table.remove(validMove,v)
  119.   end
  120.   --3) เพิ่มส่วน ai เลือกตำแหน่งว่างในแถวที่มี X อยู่สองตำแหน่ง
  121.   for _, w in pairs(win) do
  122.     local cX = any(X,w)
  123.     for _, i in pairs(w) do
  124.       for _, j in pairs(validMove) do
  125.         if cX == 2 and i == j then
  126.           return i
  127.         end
  128.       end
  129.     end
  130.   end
  131.   local V = {-100,-100,-100,-100,-100,-100,-100,-100,-100}
  132.   for _, v in pairs(validMove) do
  133.     local tempX, criticalMove = {table.unpack(X)}, {}
  134.     table.insert(tempX,v)
  135.     V[v], criticalMove = evalOX(O,tempX)
  136.     if #criticalMove > 0 then
  137.       --3) เอาส่วนนี้ออก
  138.       --2) เพิ่มส่วน ai ถึง O จะใกล้ชนะแต่เป็นตาของ X ถ้าเลือกแล้วชนะเกมก็ให้ใช้ค่านี้ไม่ต้องไปเลือกใน criticalMove อีก
  139.       --if checkWin(tempX) then
  140.         --return v
  141.       --end
  142.       --3) เอา move ออก
  143.       local move = {}
  144.       for _, i in pairs(validMove) do
  145.         for _, j in pairs(criticalMove) do
  146.           if j == i then
  147.             --3) เปลี่ยนจากเอาค่าใส่ table เป็นคืนค่านั้นกลับ
  148.             table.insert(move,j)
  149.             return j
  150.           end
  151.         end
  152.       end
  153.       --3) เอาออก
  154.       return randomChoice(move)
  155.     end
  156.   end
  157.   local maxV = max(table.unpack(V))
  158.   local imaxV = {}
  159.   for i, v in pairs(V) do
  160.     if v == maxV then
  161.       table.insert(imaxV,i)
  162.     end
  163.   end
  164.   return randomChoice(imaxV)
  165. end
  166.  
  167. function evalOX(o,x)
  168.   local SO, SX, criticalMove =calSOX(o,x)
  169.   return (1 + SX - SO), criticalMove
  170. end
  171.  
  172. function calSOX(o,x)
  173.   local SO, SX = 0, 0
  174.   local criticalMove = {}
  175.   for _, w in pairs(win) do
  176.     local cO = any(o,w)
  177.     local cX = any(x,w)
  178.     if cX == 0 then
  179.       SO = SO + cO
  180.       if cO == 2 then
  181.         print("critical", "{".. table.concat(w,",").."}")
  182.         criticalMove = w
  183.       end
  184.     end
  185.     if cO == 0 then
  186.       SX = SX + cX
  187.     end
  188.   end
  189.   return SO, SX, criticalMove
  190. end
  191.  
  192. while true do
  193.   io.write("Choose position [1-9]: ")
  194.   local move = tonumber(io.read())
  195.   print("")
  196.   goto checkMove
  197.   ::chooseAgain::
  198.   io.write("Bad move: choose position [1-9]: ")
  199.   move = tonumber(io.read())
  200.   print("")
  201.   ::checkMove::
  202.   if not move then
  203.     goto chooseAgain
  204.   --3) เปลี่ยนให้แปลง move แป็นจำนวนเต็มด้วยการปัดเศษก่อนตรวจหาช่วงของ move
  205.   --elseif move > 9 or move < 1 then
  206.     --goto chooseAgain
  207.   else
  208.     move = floor(move)
  209.     if move > 9 or move < 1 then
  210.       goto chooseAgain
  211.     end
  212.   end
  213.   for _, v in pairs(O) do
  214.     if move == v then
  215.       goto chooseAgain
  216.     end
  217.   end
  218.   for _, v in pairs(X) do
  219.     if move == v then
  220.       goto chooseAgain
  221.     end
  222.   end
  223.   table.insert(O,move)
  224.   displayOX()
  225.   if checkWin(O) then
  226.     print("O win")
  227.     break
  228.   end
  229.   if #O + #X == 9 then
  230.     print("Draw")
  231.     break
  232.   end
  233.   table.insert(X,ai())
  234.   displayOX()
  235.   if checkWin(X) then
  236.     print("X win")
  237.     break
  238.   end
  239.   --2) เอาออกไม่ต้องใช้ตรวจเฉพาะในตาของ O ก็พอ
  240.   --if #O + #X == 9 then
  241.     --print("Draw")
  242.     --break
  243.   --end
  244. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement