- numpy import numpy as np # from numba import njit # @njit def check(board): return (np.sum(board, 1) == 0).any() # @njit def rotate_board(board): return np.rot90(np.rot90(board)) def create_board(): '''Create a board with 6 rows and 2 columns''' return np.ones((2, 6), dtype=np.uint8) * 4 def move(board, position, pieces=0, pit_additions=0): '''Move stones from one positon around the board to another''' if not pieces: pieces = board[1, position] if not pieces: return board, 0, False, False board[1, position] = 0 s = min(pieces, 6 - position) board[1, position + 1: position+s+1] += 1 pieces -= s if not pieces and position+s == 6: return board, pit_additions + 1, False, True if board[1, min(position+s, 5)] == 1 and not pieces and board[0, min(position+s, 5)]: pit_additions += 1 + board[0, min(position+s, 5)] board[:, min(position+s, 5)] = 0 return board, pit_additions, True, True if pieces > 0: pit_additions += 1 board[0, 6-min(pieces, 6):] += 1 pieces -= min(pieces, 6) if pieces > 0: board, pit_additions, _, _ = move(board, -1, pieces, pit_additions) return board, pit_additions, True, True def printboard(board): for i in range(len(board)): for j in range(len(board[i])): pyscript.write(f'{i},{j}', board[i, j]) pyscript.write('p1', p1) pyscript.write('p2', p2) pyscript.write('turn', 1 if player1+1 else 2) def minimax(board, depth, alpha=-50, beta=50, player=True): if not depth: return 0, 0 if check(board): return [np.sum(board)] scores = np.zeros(6, dtype=np.int16) if player: for i in reversed(range(6)): if board[1, i] == 0: scores[i] = 0 continue a, score, change, valid = move(board.copy(), i) if not valid: continue if change: a = rotate_board(a) score += min(minimax(a, depth-1, alpha, beta, not player)) else: score += max(minimax(a, depth, alpha, beta, player)) scores[i] = score alpha = max(alpha, score) if beta <= alpha: break else: for i in reversed(range(6)): if board[1, i] == 0: scores[i] = 0 continue a, score, change, valid = move(board.copy(), i) score *= -1 if not valid: continue if change: a = rotate_board(a) score += max(minimax(a, depth-1, alpha, beta, not player)) else: score += min(minimax(a, depth, alpha, beta, player)) scores[i] = score beta = min(beta, score) if beta <= alpha: break return scores

Mancala AI

Here is the board with the stones in the mancala. The player with the most stones in their mancala wins.

Player 1 has stones.
Player 2 has stones.

It is Player 's turn.

Best moves -

from js import document from pyodide import create_proxy a = create_board() player1 = True p1 = p2 = 0 printboard(a) pyscript.write('parts', list(minimax(a, 5))) def wrapper(index): def inner(e): print(e) global a, player1, p1, p2 a, score, change, valid = move(a, index % 6) if not valid: return if player1+1: p1 += score else: p2 += score if change: player1 *= -1 a = rotate_board(a) printboard(a) pyscript.write('parts', 'Calculating...') best = list(minimax(a,8) if p1 > 12 or p2 > 12 else list(minimax(a, 6))) pyscript.write('parts', best) if check(a): mx = np.sum(a) if player1+1: p1 += mx else: p2 += mx a *= 0 printboard(a) if p1 > p2: document.getElementById('words').innerHTML += '

Player 1 wins!

' elif p2 > p1: document.getElementById('words').innerHTML += '

Player 2 wins!

' else: document.getElementById('words').innerHTML += '

Draw!

' return inner pits = [document.getElementById(f'1,{i}') for i in range(6)] proxies = [create_proxy(wrapper(i)) for i in range(len(pits))] for i, pit in enumerate(pits): pit.addEventListener("click", proxies[i])