local backg = gui.background local grid = backg.U...
创建于:2025年2月8日
创建于:2025年2月8日
local backg = gui.background
local grid = backg.UIGridLayout
grid.CellPadding = UDim2.new(.02,0,.02,0)
grid.CellSize = UDim2.new(1/3.3,0,1/3.3,0)
grid.HorizontalAlignment = Enum.HorizontalAlignment.Center
grid.VerticalAlignment = Enum.VerticalAlignment.Center
grid.FillDirectionMaxCells = 3
local hash = {
Cells = {},
CurrentPlayer = 0 -- 1 - O, 2 - X
}
local makeMove = function() return end
local checkWin = function() return end
local aiMeko
makeMove = function(cell)
if cell.Text ~= "" then return end -- Нельзя ходить в занятые клетки
textif hash.CurrentPlayer == 1 then cell.Text = "O" cell.TextColor3 = Color3.new(0.666667, 0.333333, 0.498039) hash.CurrentPlayer = 0 elseif hash.CurrentPlayer == 0 then cell.Text = "X" cell.TextColor3 = Color3.new(0.666667, 1, 0.498039) hash.CurrentPlayer = 1 end local winner = checkWin() if winner then print("Победитель: " .. winner) for i,v in hash.Cells do v.Text = "" hash.CurrentPlayer = 0 end -- Здесь можно добавить логику для завершения игры end
end
checkWin = function()
local winPatterns = {
{1, 2, 3}, -- Верхняя строка
{4, 5, 6}, -- Средняя строка
{7, 8, 9}, -- Нижняя строка
{1, 4, 7}, -- Первый столбец
{2, 5, 8}, -- Второй столбец
{3, 6, 9}, -- Третий столбец
{1, 5, 9}, -- Диагональ слева направо
{3, 5, 7}, -- Диагональ справа налево
}
textfor _, pattern in ipairs(winPatterns) do local a, b, c = pattern[1], pattern[2], pattern[3] if hash.Cells[a].Text ~= "" and hash.Cells[a].Text == hash.Cells[b].Text and hash.Cells[b].Text == hash.Cells[c].Text then return hash.Cells[a].Text -- Возвращает "X" или "O" end end return nil -- Победителя нет
end
for i=1, 3*3 do
local cell = Instance.new("TextButton")
cell.Text = ""
cell.TextSize = 60
cell.BackgroundColor3 = Color3.fromRGB(0, 65, 47)
cell.Parent = backg
cell.Name = "C"..i
hash.Cells[i] = cell
textlocal corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(.1,0) corner.Parent = cell cell.MouseButton1Click:Connect(function() makeMove(cell) end)
end
это игра крестики нолики для roblox studio. можешь пожалуйста сделать так, чтобы крестики играл игрок, и за нолики играл игрок и у них подсвечивались лучшие ходы для выигрыша от ии минимакс
Ниже приведён пример кода, в котором оба игрока (X и O) ходят сами, а при каждом ходе подсвечиваются все лучшие ходы (по версии алгоритма «Минимакс») для текущего игрока.
Обратите внимание:
Важно: В Roblox Studio, цвета могут несколько отличаться, если вы используете разные Lighting-технологии или конфигурации ColorSpace. При желании корректируйте значения
Color3
на своё усмотрение.
lualocal backg = gui.background local grid = backg.UIGridLayout grid.CellPadding = UDim2.new(.02,0,.02,0) grid.CellSize = UDim2.new(1/3.3,0,1/3.3,0) grid.HorizontalAlignment = Enum.HorizontalAlignment.Center grid.VerticalAlignment = Enum.VerticalAlignment.Center grid.FillDirectionMaxCells = 3 local hash = { Cells = {}, -- хранилище кнопок CurrentPlayer = "X" -- "X" или "O" } -- Минимакс-оценка (возвращает +10, если выиграл X, -10 если выиграл O, 0 при ничьей или если пока неизвестно) local function evaluate(board) -- Проверка всех выигрышных сочетаний local wins = { {1,2,3},{4,5,6},{7,8,9}, -- строки {1,4,7},{2,5,8},{3,6,9}, -- столбцы {1,5,9},{3,5,7} -- диагонали } for _, combo in ipairs(wins) do local a, b, c = combo[1], combo[2], combo[3] if board[a] ~= "" and board[a] == board[b] and board[b] == board[c] then if board[a] == "X" then return 10 else return -10 end end end -- Если никто не выиграл, возвращаем 0 return 0 end -- Проверка, есть ли пустые ячейки local function hasEmptyCells(board) for i=1,9 do if board[i] == "" then return true end end return false end -- Функция «Минимакс»: возвращает оценку для текущей конфигурации -- depth — для более тонкой оценки (чем быстрее выигрыш, тем лучше, и наоборот) -- isMaximizing — булево, если ходит X (максимизирующий игрок) local function minimax(board, depth, isMaximizing) local score = evaluate(board) -- Если кто-то выиграл, возвратим оценку с учётом глубины if score == 10 then -- Чем меньше глубина, тем быстрее X выиграл, тем лучше return score - depth elseif score == -10 then -- Чем меньше глубина, тем быстрее O выиграл, тем лучше (для O — хуже для X), -- поэтому depth вычитаем, чтобы "наказать" X за быструю потерю. return score + depth end -- Если не осталось ходов и никто не выиграл, то ничья if not hasEmptyCells(board) then return 0 end if isMaximizing then -- Ходит X — пытается максимально повысить счёт local best = -99999 for i=1,9 do if board[i] == "" then board[i] = "X" best = math.max(best, minimax(board, depth+1, false)) board[i] = "" end end return best else -- Ходит O — пытается минимизировать счёт local best = 99999 for i=1,9 do if board[i] == "" then board[i] = "O" best = math.min(best, minimax(board, depth+1, true)) board[i] = "" end end return best end end -- Получаем одномерный массив текущего состояния (9 ячеек) из Text кнопок local function getBoardState() local board = {} for i=1, 9 do board[i] = hash.Cells[i].Text end return board end -- Возвращает список лучших ходов для текущего игрока (X или O), -- используя Минимакс, чтобы найти максимальный (для X) или минимальный (для O) счёт local function getBestMoves(currentPlayer) local board = getBoardState() local bestMoves = {} local isX = (currentPlayer == "X") local bestScore = isX and -99999 or 99999 for i=1,9 do if board[i] == "" then board[i] = currentPlayer -- Вызываем minimax: если ходит X, то isMaximizing = false для следующего шага local moveScore = minimax(board, 0, not isX) board[i] = "" if isX then -- Максимизируем if moveScore > bestScore then bestScore = moveScore bestMoves = {i} elseif moveScore == bestScore then table.insert(bestMoves, i) end else -- Минимизируем if moveScore < bestScore then bestScore = moveScore bestMoves = {i} elseif moveScore == bestScore then table.insert(bestMoves, i) end end end end return bestMoves end -- Подсвечивает все клетки зелёным цветом, которые входят в bestMoves -- Перед этим убираем подсветку со всех клеток local function highlightBestMoves(bestMoves) -- Сбрасываем цвет у всех клеток на базовый for i=1,9 do hash.Cells[i].BackgroundColor3 = Color3.fromRGB(0, 65, 47) end -- Подсвечиваем рекомендуемые ходы for _, index in ipairs(bestMoves) do hash.Cells[index].BackgroundColor3 = Color3.fromRGB(0, 255, 0) end end -- Проверка победителя (возвращает "X" или "O" при выигрыше, nil — если нет) local function checkWin() local winPatterns = { {1, 2, 3}, -- Верхняя строка {4, 5, 6}, -- Средняя строка {7, 8, 9}, -- Нижняя строка {1, 4, 7}, -- Первый столбец {2, 5, 8}, -- Второй столбец {3, 6, 9}, -- Третий столбец {1, 5, 9}, -- Диагональ слева направо {3, 5, 7}, -- Диагональ справа налево } for _, pattern in ipairs(winPatterns) do local a, b, c = pattern[1], pattern[2], pattern[3] if hash.Cells[a].Text ~= "" and hash.Cells[a].Text == hash.Cells[b].Text and hash.Cells[b].Text == hash.Cells[c].Text then return hash.Cells[a].Text -- "X" или "O" end end return nil end -- Сброс поля при выигрыше local function resetBoard(winner) print("Победитель: " .. winner) -- Сбрасываем все клетки for i=1,9 do hash.Cells[i].Text = "" hash.Cells[i].BackgroundColor3 = Color3.fromRGB(0, 65, 47) end -- Начинаем заново. По традиции, пусть X ходит первым: hash.CurrentPlayer = "X" highlightBestMoves(getBestMoves(hash.CurrentPlayer)) end -- Делаем ход в клетку local function makeMove(cellIndex) -- Если клетка занята, выходим if hash.Cells[cellIndex].Text ~= "" then return end -- Ставим X или O в клетку hash.Cells[cellIndex].Text = hash.CurrentPlayer if hash.CurrentPlayer == "X" then hash.Cells[cellIndex].TextColor3 = Color3.new(0.666667, 1, 0.498039) -- немного зеленоватый hash.CurrentPlayer = "O" else hash.Cells[cellIndex].TextColor3 = Color3.new(0.666667, 0.333333, 0.498039) -- розоватый hash.CurrentPlayer = "X" end -- Проверяем победу local winner = checkWin() if winner then -- Если есть победитель, сбрасываем поле resetBoard(winner) return end -- Если нет победителя, проверяем нет ли ничьей local board = getBoardState() if not hasEmptyCells(board) then print("Ничья!") -- Сброс resetBoard("Ничья") return end -- Подсвечиваем лучшие ходы для следующего игрока local bestMoves = getBestMoves(hash.CurrentPlayer) highlightBestMoves(bestMoves) end -- Создаём 9 кнопок и вешаем на каждую функцию makeMove(i) for i=1, 9 do local cell = Instance.new("TextButton") cell.Text = "" cell.TextSize = 60 cell.BackgroundColor3 = Color3.fromRGB(0, 65, 47) cell.Parent = backg cell.Name = "C"..i hash.Cells[i] = cell local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(.1,0) corner.Parent = cell cell.MouseButton1Click:Connect(function() makeMove(i) end) end -- В самом начале сразу подсветим лучшие ходы для X, так как X ходит первым highlightBestMoves(getBestMoves(hash.CurrentPlayer))
evaluate(board)
minimax(board, depth, isMaximizing)
getBestMoves(currentPlayer)
currentPlayer
и считает оценку через minimax
. Сравнивает оценки, собирая все клетки, которые дают «лучшую» оценку (макс. для X, мин. для O).highlightBestMoves(bestMoves)
makeMove(cellIndex)
Таким образом, оба игрока сами нажимают на клетки, но перед ходом видят, какие из них лучше выбрать согласно алгоритму «Минимакс».