Skip to content
218 changes: 218 additions & 0 deletions maths/Game Theory/AlphaBetaPruning/alphabetapruning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
from random import choice

Check failure on line 1 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (INP001)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:1:1: INP001 File `maths/Game Theory/AlphaBetaPruning/alphabetapruning.py` is part of an implicit namespace package. Add an `__init__.py`.
from math import inf

board = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

Check failure on line 4 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:1:1: I001 Import block is un-sorted or un-formatted


def Gameboard(board):

Check failure on line 7 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (N802)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:7:5: N802 Function name `Gameboard` should be lowercase

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function Gameboard

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: Gameboard

Please provide return type hint for the function: Gameboard. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

chars = {1: "X", -1: "O", 0: " "}
for x in board:
for y in x:
ch = chars[y]
print(f"| {ch} |", end="")
print("\n" + "---------------")
print("===============")


def Clearboard(board):

Check failure on line 17 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (N802)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:17:5: N802 Function name `Clearboard` should be lowercase

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function Clearboard

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: Clearboard

Please provide return type hint for the function: Clearboard. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

for x, row in enumerate(board):
for y, col in enumerate(row):

Check failure on line 19 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (B007)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:19:16: B007 Loop control variable `col` not used within loop body
board[x][y] = 0


def winningPlayer(board, player):

Check failure on line 23 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (N802)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:23:5: N802 Function name `winningPlayer` should be lowercase

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function winningPlayer

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: winningPlayer

Please provide return type hint for the function: winningPlayer. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

Please provide type hint for the parameter: player

conditions = [
[board[0][0], board[0][1], board[0][2]],
[board[1][0], board[1][1], board[1][2]],
[board[2][0], board[2][1], board[2][2]],
[board[0][0], board[1][0], board[2][0]],
[board[0][1], board[1][1], board[2][1]],
[board[0][2], board[1][2], board[2][2]],
[board[0][0], board[1][1], board[2][2]],
[board[0][2], board[1][1], board[2][0]],
]

if [player, player, player] in conditions:
return True

return False

Check failure on line 38 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (SIM103)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:35:5: SIM103 Return the condition `[player, player, player] in conditions` directly


def gameWon(board):

Check failure on line 41 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (N802)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:41:5: N802 Function name `gameWon` should be lowercase

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function gameWon

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: gameWon

Please provide return type hint for the function: gameWon. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

return winningPlayer(board, 1) or winningPlayer(board, -1)


def printResult(board):

Check failure on line 45 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (N802)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:45:5: N802 Function name `printResult` should be lowercase

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function printResult

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: printResult

Please provide return type hint for the function: printResult. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

if winningPlayer(board, 1):
print("X has won! " + "\n")

elif winningPlayer(board, -1):
print("O's have won! " + "\n")

else:
print("Draw" + "\n")


def blanks(board):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function blanks

Please provide return type hint for the function: blanks. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

blank = []
for x, row in enumerate(board):
for y, col in enumerate(row):

Check failure on line 59 in maths/Game Theory/AlphaBetaPruning/alphabetapruning.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (B007)

maths/Game Theory/AlphaBetaPruning/alphabetapruning.py:59:16: B007 Loop control variable `col` not used within loop body
if board[x][y] == 0:
blank.append([x, y])

return blank


def boardFull(board):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function boardFull

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: boardFull

Please provide return type hint for the function: boardFull. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

if len(blanks(board)) == 0:
return True
return False


def setMove(board, x, y, player):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function setMove

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: setMove

Please provide return type hint for the function: setMove. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

Please provide descriptive name for the parameter: x

Please provide type hint for the parameter: x

Please provide descriptive name for the parameter: y

Please provide type hint for the parameter: y

Please provide type hint for the parameter: player

board[x][y] = player


def playerMove(board):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function playerMove

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: playerMove

Please provide return type hint for the function: playerMove. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

e = True
moves = {
1: [0, 0],
2: [0, 1],
3: [0, 2],
4: [1, 0],
5: [1, 1],
6: [1, 2],
7: [2, 0],
8: [2, 1],
9: [2, 2],
}
while e:
try:
move = int(input("Enter a number between 1-9: "))
if move < 1 or move > 9:
print("Invalid Move! Try again!")
elif not (moves[move] in blanks(board)):
print("Invalid Move! Try again!")
else:
setMove(board, moves[move][0], moves[move][1], 1)
Gameboard(board)
e = False
except (KeyError, ValueError):
print("Enter a number!")


def getScore(board):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function getScore

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: getScore

Please provide return type hint for the function: getScore. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

if winningPlayer(board, 1):
return 10

elif winningPlayer(board, -1):
return -10

else:
return 0


def abminimax(board, depth, alpha, beta, player):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function abminimax

Please provide return type hint for the function: abminimax. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

Please provide type hint for the parameter: depth

Please provide type hint for the parameter: alpha

Please provide type hint for the parameter: beta

Please provide type hint for the parameter: player

row = -1
col = -1
if depth == 0 or gameWon(board):
return [row, col, getScore(board)]

else:
for cell in blanks(board):
setMove(board, cell[0], cell[1], player)
score = abminimax(board, depth - 1, alpha, beta, -player)
if player == 1:
# X is always the max player
if score[2] > alpha:
alpha = score[2]
row = cell[0]
col = cell[1]

else:
if score[2] < beta:
beta = score[2]
row = cell[0]
col = cell[1]

setMove(board, cell[0], cell[1], 0)

if alpha >= beta:
break

if player == 1:
return [row, col, alpha]

else:
return [row, col, beta]


def o_comp(board):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function o_comp

Please provide return type hint for the function: o_comp. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

if len(blanks(board)) == 9:
x = choice([0, 1, 2])
y = choice([0, 1, 2])
setMove(board, x, y, -1)
Gameboard(board)

else:
result = abminimax(board, len(blanks(board)), -inf, inf, -1)
setMove(board, result[0], result[1], -1)
Gameboard(board)


def x_comp(board):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function x_comp

Please provide return type hint for the function: x_comp. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

if len(blanks(board)) == 9:
x = choice([0, 1, 2])
y = choice([0, 1, 2])
setMove(board, x, y, 1)
Gameboard(board)

else:
result = abminimax(board, len(blanks(board)), -inf, inf, 1)
setMove(board, result[0], result[1], 1)
Gameboard(board)


def makeMove(board, player, mode):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function makeMove

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: makeMove

Please provide return type hint for the function: makeMove. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: board

Please provide type hint for the parameter: player

Please provide type hint for the parameter: mode

if mode == 1:
if player == 1:
playerMove(board)

else:
o_comp(board)
else:
if player == 1:
o_comp(board)
else:
x_comp(board)


def pvc():

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file maths/Game Theory/AlphaBetaPruning/alphabetapruning.py, please provide doctest for the function pvc

Please provide return type hint for the function: pvc. If the function does not return a value, please provide the type hint as: def function() -> None:

while True:
try:
order = int(input("Enter to play 1st or 2nd: "))
if not (order == 1 or order == 2):
print("Please pick 1 or 2")
else:
break
except (KeyError, ValueError):
print("Enter a number")

Clearboard(board)
if order == 2:
currentPlayer = -1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: currentPlayer

else:
currentPlayer = 1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable and function names should follow the snake_case naming convention. Please update the following name accordingly: currentPlayer


while not (boardFull(board) or gameWon(board)):
makeMove(board, currentPlayer, 1)
currentPlayer *= -1

printResult(board)


# Driver Code
print("=================================================")
print("TIC-TAC-TOE using MINIMAX with ALPHA-BETA Pruning")
print("=================================================")
pvc()
14 changes: 14 additions & 0 deletions maths/Game Theory/AlphaBetaPruning/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Alpha-Beta Pruning

An optimization technique for the minimax algorithm that reduces the number of nodes evaluated by eliminating branches that won't affect the final decision (basically an upgrade of minimax algorithm)

As we have seen in the minimax search algorithm that the number of game states it has to examine are exponential in depth of the tree. Since we cannot eliminate the exponent, but we can cut it to half. Hence there is a technique by which without checking each node of the game tree we can compute the correct minimax decision, and this technique is called pruning. This involves two threshold parameter Alpha and beta for future expansion, so it is called alpha-beta pruning. It is also called as Alpha-Beta Algorithm. Alpha-beta pruning can be applied at any depth of a tree, and sometimes it not only prunes the tree leaves but also entire sub-tree. The two-parameter can be defined as:

1. Alpha: The best (highest-value) choice we have found so far at any point along the path of Maximizer. The initial value of alpha is -∞.
2. Beta: The best (lowest-value) choice we have found so far at any point along the path of Minimizer. The initial value of beta is +∞. The Alpha-beta pruning to a standard minimax algorithm returns the same move as the standard algorithm does, but it removes all the nodes which are not really affecting the final decision but making algorithm slow. Hence by pruning these nodes, it makes the algorithm fast.
## Acknowledgements

- [Original Author](https://github.com/anmolchandelCO180309)
- [Wiki](https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning)

#### /// The alphabetapruning.py file has a Tic-Tac-Toe game implemented with a good explanation ///
30 changes: 30 additions & 0 deletions maths/Game Theory/minimax/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

# Minimax Algorithm

A decision-making algorithm for two-player games to minimize the maximum possible loss (This is a simple, recursive, implementation of the MiniMax algorithm in Python)

MiniMax is used in decision, game theory, statistics and philosophy. It can be implemented on a two player's game given full information of the states like the one offered by games like Tic Tac Toe. That means MM cannot be used in games that feature randomness like dices. The reason is that it has to be fully aware of all possible moves/states during gameplay before it makes its mind on the best move to play.

The following implementation is made for the cube/sticks game: User sets an initial number of cubes available on a table. Both players (the user & the PC implementing MM) can pick up a number of cubes off the table in groups of 1, 2 or K. K is also set by the user. The player who picks up the last remaining cubes from the table on a single take wins the game.

The MiniMax algorithm is being implemented for the PC player and it always assume that the opponent (user) is also playing optimum. MM is fully aware of the remaining cubes and its valid moves at all states. So technically it will recursively expand the whole game tree and given the fact that the amount of possible moves are three (1,2,K), all tree nodes will end up with 3 leaves, one for each option.

Game over is the case where there are no available cubes on the table or in the case of a negative amount of cubes. The reason for the negative scenario is due to the fact that MM will expand the whole tree without checking if all three options are allowed during a state. In a better implementation we could take care of that scenario as we also did on the user side. No matter what, if MM’s move lead to negative cubes he will lose the game.

Evaluation starts on the leaves of the tree. Both players alternate during game play so each layer of the tree marks the current player (MAX or MIN). That way the evaluation function can set a higher/positive value if player MAX wins and a lower/negative value if he loses (remember evaluation happens from the MiniMax’s perspective so he will be the MAX player). When all leaves get their evaluation and thanks to the recursive implementation of the algorithm, their values climb up on each layer till the root of the tree also gets evaluated. That way MAX player will try to lead the root to get the highest possible value, assuming that MIN player (user) will try its best to lead to the lowest value possible. When the root gets its value, MAX player (who will be the first one to play) knows what move would lead to victory or at least lead to a less painful loss.

So the goal of MiniMax is to minimize the possible loss for a worst case scenario, from the algorithm's perspective.



/// There is an example code implemented with deatailed explanation in the minimax.py file ///




## Acknowledgements

- [Original Author](https://github.com/savvasio)
- [Wiki](https://en.wikipedia.org/wiki/Minimax)
- [Video Explanation](https://www.youtube.com/watch?v=l-hh51ncgDI)

Loading
Loading