{"id":15701044,"url":"https://github.com/abdallahhemdan/minimax","last_synced_at":"2025-07-20T00:32:05.917Z","repository":{"id":111034591,"uuid":"247539738","full_name":"AbdallahHemdan/MiniMax","owner":"AbdallahHemdan","description":"🥇 Unbeatable Tic Tac Toe game with a README contains very thing about MiniMax algorithms with explanation of it with c++ and js Implementation code","archived":false,"fork":false,"pushed_at":"2020-03-15T23:25:01.000Z","size":180,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-12T15:52:27.819Z","etag":null,"topics":["cmp2022","cpp","cufe2022","hemdan","minimax","minimax-search","minimax-xo","python","tic-tac-toe","tic-tac-toe-javascript","tictactoe-game","unbeatable-tic-tac-toe","unbeatable-tic-tac-toe-game"],"latest_commit_sha":null,"homepage":"https://abdallahhemdan.github.io/MiniMax/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AbdallahHemdan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-15T19:47:51.000Z","updated_at":"2025-03-31T18:18:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"e41396ea-7a0d-4d3a-90b0-ff118228e222","html_url":"https://github.com/AbdallahHemdan/MiniMax","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AbdallahHemdan/MiniMax","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbdallahHemdan%2FMiniMax","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbdallahHemdan%2FMiniMax/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbdallahHemdan%2FMiniMax/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbdallahHemdan%2FMiniMax/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AbdallahHemdan","download_url":"https://codeload.github.com/AbdallahHemdan/MiniMax/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbdallahHemdan%2FMiniMax/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266048498,"owners_count":23868738,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cmp2022","cpp","cufe2022","hemdan","minimax","minimax-search","minimax-xo","python","tic-tac-toe","tic-tac-toe-javascript","tictactoe-game","unbeatable-tic-tac-toe","unbeatable-tic-tac-toe-game"],"created_at":"2024-10-03T19:58:48.431Z","updated_at":"2025-07-20T00:32:05.894Z","avatar_url":"https://github.com/AbdallahHemdan.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎯 Minimax Algorithm\n\n## 📜 Explanation\n\n---\n\n- Minimax is a kind of backtracking algorithm to find the optimal move for a player, assuming that your opponent also plays optimally.\n\n- In Minimax the two players are called maximizer and minimizer. The maximizer tries to get the highest score possible while the minimizer tries to do the opposite and get the lowest score possible.\n\n- Every board state has a value associated with it. In a given state if the maximizer has upper hand then, the score of the board will tend to be some positive value. If the minimizer has the upper hand in that board state then it will tend to be some negative value.\n\n- Since this is a backtracking based algorithm, it tries all possible moves, then backtracks and makes a decision.\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://media.geeksforgeeks.org/wp-content/uploads/minmax1.png\"\u003e\n\u003c/div\u003e\n\n## 👩‍💻 Get Maximizer value\n\n---\n\n```cpp\n#include \u003cbits\\stdc++.h\u003e\nusing namespace std;\n\nint getLeftChild(int node) { return node * 2; }\nint getRightChild(int node) { return node * 2 + 1; }\n\nint minimax(int curDepth, int nodeIndex, bool isMaximizer, vector\u003cint\u003e scores, int h) {\n if (curDepth == h) { // we finished the tree\n  return scores[nodeIndex];\n }\n if (isMaximizer) { // I am a maximizer node\n    int leftValue = minimax(curDepth + 1, getLeftChild(nodeIndex), false, scores, h);\n    int rightValue = minimax(curDepth + 1, getRightChild(nodeIndex), false, scores, h);\n    return max(leftValue, rightValue); // get max from my children\n }\n else {\n    int leftValue = minimax(curDepth + 1, getLeftChild(nodeIndex), true, scores, h);\n    int rightValue = minimax(curDepth + 1, getRightChild(nodeIndex), true, scores, h);\n    return min(leftValue, rightValue);\n }\n}\n\nint main() {\n vector\u003cint\u003e scores = { 3, 5, 2, 9, 12, 5, 23, 23 };\n int n = scores.size();\n int h = ceil(log2(n));\n int maximizerValue = minimax(0, 0, true, scores, h);\n cout \u003c\u003c maximizerValue \u003c\u003c endl; // 12\n}\n```\n\n---\n\n## 🔎 Introduction to Evaluation Function\n\n- In the above example, the scores (leaves of Game Tree) are given to us. For a typical game, we need to derive these values by a function, This function is often known as Evaluation Function, It is sometimes also called Heuristic Function.\n\n- The basic idea behind the evaluation function is to give a high value for a board if maximizer‘s turn or a low value for the board if minimizer‘s turn.\n\n- let us consider X as the maximizer and O as the minimizer.\n\n  1.  If X wins on the board we give it a positive value of +10\n\n      \u003cp align=\"center\"\u003e\n         \u003cimg src=\"https://media.geeksforgeeks.org/wp-content/uploads/TicTacToe.png\" /\u003e\n      \u003c/p\u003e\n\n  2.  If O wins on the board we give it a negative value of -10.\n\n      \u003cp align=\"center\"\u003e\n         \u003cimg src=\"https://media.geeksforgeeks.org/wp-content/uploads/TicTacToe1.png\" /\u003e\n      \u003c/p\u003e\n\n  3.  If no one has won or the game results in a draw then we give a value of +0.\n      \u003cp align=\"center\"\u003e\n         \u003cimg src=\"https://media.geeksforgeeks.org/wp-content/uploads/TicTacToe2-1.png\" /\u003e\n      \u003c/p\u003e\n\n### 💡 Evaluation function for the game Tic-Tac-Toe\n\n---\n\n```cpp\n#include \u003cbits\\stdc++.h\u003e\nusing namespace std;\n\n\nconst int maximizerValue = 10;\nconst int minimizerValue = -10;\n\nint evaluate(char grid[3][3]) {\n // check winning state in rows\n for (int row = 0; row \u003c 3; row++) {\n  if (grid[row][0] == grid[row][1] \u0026\u0026 grid[row][0] == grid[row][2]) {\n   if (grid[row][0] == 'x') return maximizerValue;\n   else if (grid[row][0] == 'o') return minimizerValue;\n  }\n }\n\n // check winning state in cols\n for (int col = 0; col \u003c 3; col++) {\n  if (grid[0][col] == grid[1][col] \u0026\u0026 grid[0][col] == grid[2][col]) {\n   if (grid[0][col] == 'x') return maximizerValue;\n   else if (grid[0][col] == 'o') return minimizerValue;\n  }\n }\n\n // check winning state in main diagonal\n if (grid[0][0] == grid[1][1] \u0026\u0026 grid[0][0] == grid[2][2]) {\n  if (grid[0][0] == 'x') return maximizerValue;\n  else if (grid[0][0] == 'o') return minimizerValue;\n }\n\n // check winning state in anti diagonal\n if (grid[0][2] == grid[1][1] \u0026\u0026 grid[1][1] == grid[2][0]) {\n  if (grid[0][2] == 'x') return maximizerValue;\n  else if (grid[0][2] == 'o') return minimizerValue;\n }\n\n return 0; // tie state\n}\n\n\nint main() {\n // x for maximizer player\n // o for minimizer player\n // _ empty cell\n char board[3][3] =\n {\n  { 'x', '_', 'o' },\n  { '_', 'x', 'o' },\n  { '_', '_', 'x' }\n };\n int evalValue = evaluate(board);\n cout \u003c\u003c evalValue \u003c\u003c endl;\n}\n```\n\n## 🏆 Finding the Best Move\n\n---\n\n- We shall be introducing a new function called findBestMove(). This function evaluates all the available moves using minimax() and then returns the best move the maximizer can make\n\n```pseudo\nfunction findBestMove(board):\n    bestMove = NULL\n    for each move in board :\n        if current move is better than bestMove\n            bestMove = current move\n    return bestMove\n```\n\n- To check whether or not the current move is better than the best move we take the help of minimax() function which will consider all the possible ways the game can go and returns the best value for that move, assuming the opponent also plays optimally\n\n```pseudo\nfunction minimax(board, depth, isMaximizingPlayer):\n\n    if current board state is a terminal state :\n        return value of the board\n    if isMaximizingPlayer :\n        bestVal = -INFINITY\n        for each move in board :\n            value = minimax(board, depth+1, false)\n            bestVal = max( bestVal, value)\n        return bestVal\n\n    else :\n        bestVal = +INFINITY\n        for each move in board :\n            value = minimax(board, depth+1, true)\n            bestVal = min( bestVal, value)\n        return bestVal\n```\n\n- To check whether the game is over and to make sure there are no moves left we use isMovesLeft() function\n\n```pseudo\nfunction isMovesLeft(board):\n   for each cell in board:\n      if current cell is empty:\n         return true\n   return false\n```\n\n## 🤖 Let's make our AI smarter\n\n---\n\n- Even though the following AI plays perfectly, it might choose to make a move which will result in a slower victory or a faster loss. Lets take an example and explain it.\n\n- Assume that there are 2 possible ways for X to win the game from a give board state.\n\n  - Move A : X can win in 2 move\n  - Move B : X can win in 4 moves\n\n- Our evaluation function will return a value of +10 for both moves A and B. Even though the move A is better because it ensures a faster victory, our AI may choose B sometimes.\n- To overcome this problem we subtract the depth value from the evaluated score. This means that in case of a victory it will choose a the victory which takes least number of moves and in case of a loss it will try to prolong the game and play as many moves as possible. So the new evaluated value will be\n  - Move A will have a value of +10 – 2 = 8\n  - Move B will have a value of +10 – 4 = 6\n\n```cpp\n#include \u003cbits\\stdc++.h\u003e\nusing namespace std;\n\n\nconst int maximizerValue = 10;\nconst int minimizerValue = -10;\n\nconst char player = 'x';\nconst char ai = 'o';\n\n\nstruct Move {\n\tint row, col;\n};\n\nint evaluate(char grid[3][3]) {\n\t// check winning state in rows\n\tfor (int row = 0; row \u003c 3; row++) {\n\t\tif (grid[row][0] == grid[row][1] \u0026\u0026 grid[row][0] == grid[row][2]) {\n\t\t\tif (grid[row][0] == 'x') return maximizerValue;\n\t\t\telse if (grid[row][0] == 'o') return minimizerValue;\n\t\t}\n\t}\n\n\t// check winning state in cols\n\tfor (int col = 0; col \u003c 3; col++) {\n\t\tif (grid[0][col] == grid[1][col] \u0026\u0026 grid[0][col] == grid[2][col]) {\n\t\t\tif (grid[0][col] == 'x') return maximizerValue;\n\t\t\telse if (grid[0][col] == 'o') return minimizerValue;\n\t\t}\n\t}\n\n\t// check winning state in main diagonal\n\tif (grid[0][0] == grid[1][1] \u0026\u0026 grid[0][0] == grid[2][2]) {\n\t\tif (grid[0][0] == 'x') return maximizerValue;\n\t\telse if (grid[0][0] == 'o') return minimizerValue;\n\t}\n\n\t// check winning state in anti diagonal\n\tif (grid[0][2] == grid[1][1] \u0026\u0026 grid[1][1] == grid[2][0]) {\n\t\tif (grid[0][2] == 'x') return maximizerValue;\n\t\telse if (grid[0][2] == 'o') return minimizerValue;\n\t}\n\n\treturn 0; // tie state\n}\n\n\nbool isMoveLeft(char board[3][3]) {\n\tfor (int row = 0; row \u003c 3; row++) {\n\t\tfor (int col = 0; col \u003c 3; col++) {\n\t\t\tif (board[row][col] == '_') return true;\n\t\t}\n\t}\n\treturn false;\n}\n\n\nint minimax(char board[3][3], int depth, int isMazimizer) {\n\tint score = evaluate(board);\n\tif (score == maximizerValue) return maximizerValue;\n\tif (score == minimizerValue) return minimizerValue;\n\tif (!isMoveLeft(board)) return 0;\n\n\t// If this maximizer's move\n\tif (isMazimizer)\n\t{\n\t\tint best = -1000;\n\t\t// Traverse all cells\n\t\tfor (int row = 0; row\u003c3; row++)\n\t\t{\n\t\t\tfor (int col = 0; col\u003c3; col++)\n\t\t\t{\n\t\t\t\t// Check if cell is empty\n\t\t\t\tif (board[row][col] == '_')\n\t\t\t\t{\n\t\t\t\t\t// Make the move\n\t\t\t\t\tboard[row][col] = player;\n\n\t\t\t\t\t// Call minimax recursively and choose\n\t\t\t\t\t// the maximum value\n\t\t\t\t\tbest = max(best,\n\t\t\t\t\t\tminimax(board, depth + 1, !isMazimizer));\n\n\t\t\t\t\t// Undo the move\n\t\t\t\t\tboard[row][col] = '_';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn best;\n\t}\n\n\t// If this minimizer's move\n\telse\n\t{\n\t\tint best = 1000;\n\n\t\t// Traverse all cells\n\t\tfor (int row = 0; row\u003c3; row++)\n\t\t{\n\t\t\tfor (int col = 0; col\u003c3; col++)\n\t\t\t{\n\t\t\t\t// Check if cell is empty\n\t\t\t\tif (board[row][col] == '_')\n\t\t\t\t{\n\t\t\t\t\t// Make the move\n\t\t\t\t\tboard[row][col] = ai;\n\n\t\t\t\t\t// Call minimax recursively and choose\n\t\t\t\t\t// the minimum value\n\t\t\t\t\tbest = min(best,\n\t\t\t\t\t\tminimax(board, depth + 1, !isMazimizer));\n\n\t\t\t\t\t// Undo the move\n\t\t\t\t\tboard[row][col] = '_';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn best;\n\t}\n}\n\n\nMove findBestMove(char board[3][3]) {\n\tint bestVal = INT_MIN;\n\tMove bestMove;\n\tbestMove.row = -1;\n\tbestMove.col = -1;\n\n\tfor (int row = 0; row \u003c 3; row++) {\n\t\tfor (int col = 0; col \u003c 3; col++) {\n\t\t\t// Check if cell is empty\n\t\t\tif (board[row][col] == '_') {\n\t\t\t\t// Make the move\n\t\t\t\tboard[row][col] = player;\n\n\t\t\t\tint moveValue = minimax(board, 0, false);\n\t\t\t\tif (moveValue \u003e bestVal) {\n\t\t\t\t\tbestVal = moveValue;\n\t\t\t\t\tbestMove.row = row;\n\t\t\t\t\tbestMove.col = col;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tcout \u003c\u003c \"The value of the best move is : \" \u003c\u003c bestVal \u003c\u003c endl;\n\treturn bestMove;\n}\n\n\nint main() {\n\t// x for maximizer player\n\t// o for minimizer player\n\t// _ empty cell\n\tchar board[3][3] =\n\t{\n\t\t{ 'x', 'o', 'x' },\n\t\t{ 'o', 'o', 'x' },\n\t\t{ '_', '_', '_' }\n\t};\n\tMove bestMove = findBestMove(board);\n\n\tcout \u003c\u003c \"The Optimal Move is : \" \u003c\u003c endl;\n\tcout \u003c\u003c bestMove.row \u003c\u003c ' ' \u003c\u003c bestMove.col \u003c\u003c endl;\n}\n```\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://media.geeksforgeeks.org/wp-content/uploads/TIC_TAC.jpg\"/\u003e\n\u003c/p\u003e\n\n- This image depicts all the possible paths that the game can take from the root board state. It is often called the Game Tree\n\n---\n## 🥇 Unbeatable tic tac toe using Minimax algorithm\n\n\u003cimg src=\"https://github.com/AbdallahHemdan/MiniMax/blob/master/screenshots/1.png\"\u003e\n\u003chr/\u003e\n\u003cimg src=\"https://github.com/AbdallahHemdan/MiniMax/blob/master/screenshots/2.png\"\u003e\n\u003chr/\u003e\n\u003cimg src=\"https://github.com/AbdallahHemdan/MiniMax/blob/master/screenshots/3.png\"\u003e\n\u003chr/\u003e\n\u003cimg src=\"https://github.com/AbdallahHemdan/MiniMax/blob/master/screenshots/4.png\"\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabdallahhemdan%2Fminimax","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabdallahhemdan%2Fminimax","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabdallahhemdan%2Fminimax/lists"}