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)Таким образом, оба игрока сами нажимают на клетки, но перед ходом видят, какие из них лучше выбрать согласно алгоритму «Минимакс».