-- Compiled with roblox-ts v1.2.7 local TS = _G[script] local TicTacToeState = TS.import(script, script.Parent.Parent, "enum", "TicTacToeState").TicTacToeState local TicTacToeSymbol = TS.import(script, script.Parent.Parent, "enum", "TicTacToeSymbol").TicTacToeSymbol local TicTacToeCell = TS.import(script, script.Parent.Parent, "TicTacToeCell").TicTacToeCell local TicTacToePlayer = TS.import(script, script.Parent, "TicTacToePlayer").TicTacToePlayer local TicTacToeMinMaxPlayer do local super = TicTacToePlayer TicTacToeMinMaxPlayer = setmetatable({}, { __tostring = function() return "TicTacToeMinMaxPlayer" end, __index = super, }) TicTacToeMinMaxPlayer.__index = TicTacToeMinMaxPlayer function TicTacToeMinMaxPlayer.new(...) local self = setmetatable({}, TicTacToeMinMaxPlayer) return self:constructor(...) or self end function TicTacToeMinMaxPlayer:constructor(name, maxDepth) if maxDepth == nil then maxDepth = math.huge end super.constructor(self, name) self.maxDepth = maxDepth end function TicTacToeMinMaxPlayer:makeMove(board, ownSymbol) local _binding = self:minMax(board, ownSymbol, math.abs(self.maxDepth)) local row = _binding.row local col = _binding.col if row == nil or col == nil then return nil end return { row = row, col = col, } end function TicTacToeMinMaxPlayer:minMax(board, winSymbol, maxDepth) local _binding = board:getCurrentState() local state = _binding[1] repeat if state == (TicTacToeState.X_WON) then return winSymbol == TicTacToeSymbol.X and { score = 1, } or { score = -1, } end if state == (TicTacToeState.O_WON) then return winSymbol == TicTacToeSymbol.O and { score = 1, } or { score = -1, } end if state == (TicTacToeState.DRAW) then return { score = 0, } end until true if maxDepth <= 0 then return { score = 0, } end local emptyCells = board:getEmptyCells() local movesMade = {} for _, cell in ipairs(emptyCells) do local _binding_1 = { cell:getRow(), cell:getCol() } local row = _binding_1[1] local col = _binding_1[2] local move = { row = row, col = col, score = 0, } board:setCell(TicTacToeCell.new(row, col, winSymbol)) local res = self:minMax(board, self:getNextSymbol(winSymbol), maxDepth - 1) move.score = res.score -- ▼ Array.push ▼ movesMade[#movesMade + 1] = move -- ▲ Array.push ▲ end local bestMove if winSymbol == TicTacToeSymbol.X then local _arg0 = function(prev, curr) return prev.score < curr.score and curr or prev end -- ▼ ReadonlyArray.reduce ▼ if #movesMade == 0 then error("Attempted to call `ReadonlyArray.reduce()` on an empty array without an initialValue.") end local _result = movesMade[1] local _callback = _arg0 for _i = 2, #movesMade do _result = _callback(_result, movesMade[_i], _i - 1, movesMade) end -- ▲ ReadonlyArray.reduce ▲ bestMove = _result else local _arg0 = function(prev, curr) return prev.score > curr.score and curr or prev end -- ▼ ReadonlyArray.reduce ▼ if #movesMade == 0 then error("Attempted to call `ReadonlyArray.reduce()` on an empty array without an initialValue.") end local _result = movesMade[1] local _callback = _arg0 for _i = 2, #movesMade do _result = _callback(_result, movesMade[_i], _i - 1, movesMade) end -- ▲ ReadonlyArray.reduce ▲ bestMove = _result end return bestMove end function TicTacToeMinMaxPlayer:getNextSymbol(symbol) return symbol == TicTacToeSymbol.X and TicTacToeSymbol.O or TicTacToeSymbol.X end end return { TicTacToeMinMaxPlayer = TicTacToeMinMaxPlayer, }