Advertisement
SigmaBoy456

Lua tictactoe Minimax (e/m/h)

Mar 2nd, 2025
176
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.27 KB | None | 0 0
  1. local tictactoe = {}
  2. tictactoe.__index = tictactoe
  3.  
  4. function tictactoe.new()
  5.     local self = setmetatable({}, tictactoe)
  6.     self.Board = {
  7.         {1, 2, 3},
  8.         {4, 5, 6},
  9.         {7, 8, 9}
  10.     }
  11.     self.Player = nil
  12.     self.AI = nil
  13.     self.Diff = nil
  14.     self.PrevPlayed = nil
  15.     self.Turn = nil
  16.     return self
  17. end
  18.  
  19. -- Lua Index of Table Start With 1
  20. -- So I use 1 as First Index
  21. function tictactoe:DrawBoard()
  22.     print(string.rep("-", 14))
  23.     for i = 1, 3 do
  24.         print("|"..tostring(self.Board[i][1]).." | "..tostring(self.Board[i][2]).." | "..tostring(self.Board[i][3]).. " |")
  25.     end
  26.     print(string.rep("-", 14))
  27. end
  28. function tictactoe:ChooseTeam()
  29.     ::again::
  30.     io.write("Choose You Team (O or X ) : ")
  31.     local n = string.upper(io.read())
  32.     if n == "O" then
  33.         self.Player = n
  34.         self.AI = "X"
  35.     elseif n == "X" then
  36.         self.Player = n
  37.         self.AI = "O"
  38.     else
  39.         print("Invaild Team")
  40.         goto again
  41.     end
  42. end
  43.  
  44. function tictactoe:SelectDiff()
  45.     ::again::
  46.     io.write("Choose You AI Diff\ne: Easy\nm: Meduim\nh: Hard\nInput Here : ")
  47.     local n = string.lower(io.read())
  48.     if n == "e" then
  49.         self.Diff = n
  50.     elseif n == "m" then
  51.         self.Diff = n
  52.     elseif n == "h" then
  53.         self.Diff = n
  54.     else
  55.         print("Invaild Input")
  56.         goto again
  57.     end
  58. end
  59.  
  60. function tictactoe:StartTurn()
  61.     local n = math.random(1, 2)
  62.     if n == 1 then
  63.         self.Turn = self.Player
  64.     else
  65.         self.Turn = self.AI
  66.     end
  67. end
  68.  
  69. function tictactoe:IsAbleToFill(row, col)
  70.     return type(self.Board[row][col]) == "number"
  71. end
  72.  
  73. function tictactoe:IsTie()
  74.     for i = 1, 3 do
  75.         for j = 1, 3 do
  76.             if self:IsAbleToFill(i, j) then
  77.                 return false
  78.             end
  79.         end
  80.     end
  81.     return true
  82. end
  83.  
  84. function tictactoe:IsGameOver()
  85.     for i = 1, 3 do
  86.         if self.Board[i][1] == self.Board[i][2] and self.Board[i][2] == self.Board[i][3] then
  87.             return true
  88.         elseif self.Board[1][i] == self.Board[2][i] and self.Board[2][i] == self.Board[3][i] then
  89.             return true
  90.         end
  91.     end
  92.     if self.Board[1][1] == self.Board[2][2] and self.Board[2][2] == self.Board[3][3] then
  93.         return true
  94.     elseif self.Board[1][3] == self.Board[2][2] and self.Board[2][2] == self.Board[3][1] then
  95.         return true
  96.     end
  97. end
  98.  
  99. function tictactoe:PlayerFill(row, col)
  100.     if self:IsAbleToFill(row, col) then
  101.         self.Board[row][col] = self.Player
  102.     else
  103.         return
  104.     end
  105. end
  106.  
  107. -- Might Confunse You on This One
  108. -- Function For AI (MiniMax Algorithm/AI Algorithm)
  109. function tictactoe:EasyAIFill()
  110.     local ava = {}
  111.     for i = 1, 3 do
  112.         for j = 1, 3 do
  113.             if self:IsAbleToFill(i, j) then
  114.                 table.insert(ava, {i, j})
  115.             end
  116.         end
  117.     end
  118.     if ava then
  119.         local avaSpot = ava[math.random(1, #ava)]
  120.         self.Board[avaSpot[1]][avaSpot[2]] = self.AI
  121.     end
  122. end
  123.  
  124. function tictactoe:FindAvaSpot(symbol)
  125.     for i= 1,  3 do
  126.         if self.Board[i][1] == symbol and self.Board[i][2] == symbol and self:IsAbleToFill(i, 3) then
  127.             return {i, 3}
  128.         elseif self.Board[i][3] == symbol and self.Board[i][2] == symbol and self:IsAbleToFill(i, 1) then
  129.             return {i, 1}
  130.         elseif self.Board[1][i] == symbol and self.Board[2][i] == symbol and self:IsAbleToFill(3, i) then
  131.             return {3, i}
  132.         elseif self.Board[3][i] == symbol and self.Board[2][i] == symbol and self:IsAbleToFill(1, i) then
  133.             return {1, i}
  134.         elseif self.Board[3][i] == symbol and self.Board[1][i] == symbol and self:IsAbleToFill(2, i) then
  135.             return {2, i}
  136.         elseif self.Board[i][3] == symbol and self.Board[i][1] == symbol and self:IsAbleToFill(i, 2) then
  137.             return {i, 2}
  138.         end
  139.     end
  140.     -- Ava Spot 2 For AI Meduim
  141.     if self.Board[1][1] == symbol and self.Board[2][2] == symbol and self:IsAbleToFill(3, 3) then return {3, 3} end
  142.     if self.Board[3][3] == symbol and self.Board[2][2] == symbol and self:IsAbleToFill(1, 1) then return {1, 1} end
  143.     if self.Board[1][3] == symbol and self.Board[2][2] == symbol and self:IsAbleToFill(3, 1) then return {3, 1} end
  144.     if self.Board[3][1] == symbol and self.Board[2][2] == symbol and self:IsAbleToFill(1, 3) then return {1, 3} end
  145.     return nil
  146. end
  147. -- Now This One Gonna Be The Main Algorithm for The Minimax AI which is a Hard Mode AI
  148. -- This One For Checking Winner With MiniMax Or Maybe you can use The IsGameOver() Func Which i Made this Optional
  149. -- Well is Just Waste of Line You Can Just Replace This With IsGameOver And Make the IsGameOver Reutrn char instead of Bool
  150. function tictactoe:MiniMaxCheckWinner()
  151.     for i = 1, 3 do
  152.         if self.Board[i][1] == self.Board[i][2] and self.Board[i][2] == self.Board[i][3] then
  153.             return self.Board[i][1]
  154.         elseif self.Board[1][i] == self.Board[2][i] and self.Board[2][i] == self.Board[3][i] then
  155.             return self.Board[1][i]
  156.         end
  157.     end
  158.     if self.Board[1][1] == self.Board[2][2] and self.Board[2][2] == self.Board[3][3] then
  159.         return self.Board[1][1]
  160.     elseif self.Board[1][3] == self.Board[2][2] and self.Board[2][2] == self.Board[3][1] then
  161.         return self.Board[1][3]
  162.     end
  163.     return nil
  164. end
  165. -- Now All We Need is Just This Function For The Hard AI Algorithm
  166. function tictactoe:MiniMax(ismaxing)
  167.     if self:MiniMaxCheckWinner() == self.AI then return 1 end
  168.     if self:MiniMaxCheckWinner() == self.Player then return -1 end
  169.     if self:IsTie() then return 0 end
  170.     if ismaxing then
  171.         -- This One For The AI Case
  172.         -- Such That AI Going Check All Possible Way to Win The Player With This Algorithm
  173.         local maxscore = -math.huge
  174.         for i = 1, 3 do
  175.             for j = 1, 3 do
  176.                 if self:IsAbleToFill(i, j) then
  177.                     local temp = self.Board[i][j]
  178.                     self.Board[i][j] = self.AI
  179.                     local score = self:MiniMax(false)
  180.                     maxscore = math.max(score, maxscore)
  181.                     self.Board[i][j] = temp
  182.                 end
  183.             end
  184.         end
  185.         return maxscore
  186.     else
  187.         -- This One For The Player Case
  188.         -- Such That AI Going To Play The Player To Find That How Will AI Win or Block Player Spot When Player is Filling(Might not Accruate)
  189.         local minscore = math.huge
  190.         for i = 1, 3 do
  191.             for j = 1, 3 do
  192.                 if self:IsAbleToFill(i, j) then
  193.                     local temp = self.Board[i][j]
  194.                     self.Board[i][j] = self.Player
  195.                     local score = self:MiniMax(true)
  196.                     minscore = math.min(score, minscore)
  197.                     self.Board[i][j] = temp
  198.                 end
  199.             end
  200.         end
  201.         return minscore
  202.     end
  203. end
  204.  
  205. function tictactoe:AIFill()
  206.     if self.Diff == "e" then
  207.         self:EasyAIFill()
  208.     elseif self.Diff == "m" then
  209.         local WinSpot = self:FindAvaSpot(self.AI)
  210.         if WinSpot then
  211.             self.Board[WinSpot[1]][WinSpot[2]] = self.AI
  212.             return
  213.         end
  214.         local BlockSpot = self:FindAvaSpot(self.Player)
  215.         if BlockSpot then
  216.             self.Board[BlockSpot[1]][BlockSpot[2]] = self.AI
  217.             return
  218.         end
  219.         -- This Code Run When There No WinSpot or BlockSpot
  220.         for i = 1, 3 do
  221.             for j = 1, 3 do
  222.                 if self:IsAbleToFill(i, j) then
  223.                     self.Board[i][j] = self.AI
  224.                     return
  225.                 end
  226.             end
  227.         end
  228.     elseif self.Diff == "h" then
  229.         -- This One Use The Algorithm For Winning So Feel Free To View The Soucre of the Algorithm
  230.         local bestscore = -math.huge
  231.         local bestfill = nil
  232.         for i = 1, 3 do
  233.             for j = 1, 3 do
  234.                 if self:IsAbleToFill(i, j) then
  235.                     local temp = self.Board[i][j]
  236.                     self.Board[i][j] = self.AI
  237.                     local score = self:MiniMax(false)
  238.                     if score > bestscore then
  239.                         bestscore = score
  240.                         bestfill = {i, j}
  241.                     end
  242.                     self.Board[i][j] = temp
  243.                 end
  244.             end
  245.         end
  246.         if bestfill then
  247.             self.Board[bestfill[1]][bestfill[2]] = self.AI
  248.         end
  249.     end
  250. end
  251.  
  252. -- Function For Main Game Code
  253. function tictactoe:AutoPlayRound()
  254.     if self.Turn == self.Player then
  255.         -- Player Code/AI Code Feel Free To View
  256.         ::again::
  257.         local row, col
  258.         io.write(string.format("Player Turn! Currently Player Is %s\nChoose To Fill From 1-9\ninput Here : ", self.Player))
  259.         local plrCin = tonumber(io.read())
  260.         if plrCin > 9 or not plrCin or plrCin < 1 then print("Invaild input") goto again end
  261.         if plrCin <= 3 then
  262.             row, col = 1, plrCin
  263.             if not self:IsAbleToFill(row, col) then print("Board Already Filled Choose Another") goto again end
  264.             self:PlayerFill(row, col)
  265.         elseif plrCin <= 6 then
  266.             row, col = 2, plrCin-3
  267.             if not self:IsAbleToFill(row, col) then print("Board Already Filled Choose Another") goto again end
  268.             self:PlayerFill(row, col)
  269.         elseif plrCin <= 9 then
  270.             row, col = 3, plrCin-6
  271.             if not self:IsAbleToFill(row, col) then print("Board Already Filled Choose Another") goto again end
  272.             self:PlayerFill(row, col)
  273.         end
  274.         self.PrevPlayed = self.Player
  275.         self.Turn = self.AI
  276.     else
  277.         -- AI Code Feel Free To View
  278.         print("AI Turn!..AI is Thinking.. and Choosing")
  279.         self:AIFill()
  280.         self.PrevPlayed = self.AI
  281.         self.Turn = self.Player
  282.     end
  283. end
  284.  
  285. -- Fit In All Function Together into Simple Code
  286. function tictactoe:StartGame()
  287.     self:ChooseTeam()
  288.     self:SelectDiff()
  289.     self:StartTurn()
  290.     while true do
  291.         --os.execute("clear")
  292.         self:DrawBoard()
  293.         if self:IsGameOver() then print("Game Over Winner : " .. self.PrevPlayed) break end
  294.         if self:IsTie() then print("Game Tie!") break end
  295.         self:AutoPlayRound()
  296.     end
  297. end
  298. -- Test Result
  299. local ttt1 = tictactoe.new()
  300. ttt1:StartGame()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement