make blokus in rust
This commit is contained in:
parent
98f161c620
commit
eca2b4acb8
11 changed files with 706 additions and 156 deletions
177
blokus.py
177
blokus.py
|
|
@ -1,159 +1,30 @@
|
|||
#!/usr/bin/env python
|
||||
from typing import Any
|
||||
import numpy as np
|
||||
import random
|
||||
import game
|
||||
|
||||
BOARD_SIZE = 14
|
||||
|
||||
|
||||
def make_board():
|
||||
a = np.array([[0 for i in range(BOARD_SIZE)] for j in range(BOARD_SIZE)])
|
||||
a[4, 4] = -1
|
||||
a[9, 9] = -1
|
||||
return a
|
||||
|
||||
|
||||
tiles = [
|
||||
np.array([[1]]),
|
||||
np.array([[1], [1]]),
|
||||
np.array([[1], [1], [1]]),
|
||||
np.array([[1, 0], [1, 1]]),
|
||||
np.array([[1], [1], [1], [1]]),
|
||||
np.array([[1, 0], [1, 0], [1, 1]]),
|
||||
np.array([[1, 0], [1, 1], [1, 0]]),
|
||||
np.array([[1, 1], [1, 1]]),
|
||||
np.array([[1, 1, 0], [0, 1, 1]]),
|
||||
np.array([[1], [1], [1], [1], [1]]),
|
||||
np.array([[1, 0], [1, 0], [1, 0], [1, 1]]),
|
||||
np.array([[1, 0], [1, 0], [1, 1], [0, 1]]),
|
||||
np.array([[1, 0], [1, 1], [1, 1]]),
|
||||
np.array([[1, 1], [1, 0], [1, 1]]),
|
||||
np.array([[1, 0], [1, 1], [1, 0], [1, 0]]),
|
||||
np.array([[0, 1, 0], [0, 1, 0], [1, 1, 1]]),
|
||||
np.array([[1, 0, 0], [1, 0, 0], [1, 1, 1]]),
|
||||
np.array([[1, 1, 0], [0, 1, 1], [0, 0, 1]]),
|
||||
np.array([[1, 0, 0], [1, 1, 1], [0, 0, 1]]),
|
||||
np.array([[1, 0, 0], [1, 1, 1], [0, 1, 0]]),
|
||||
np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]]),
|
||||
]
|
||||
|
||||
|
||||
def get_permutations(which_tiles: list[int]) -> list[tuple[int, np.ndarray]]:
|
||||
permutations: list[tuple[int, np.ndarray]] = []
|
||||
|
||||
for i, tile in enumerate(tiles):
|
||||
if i not in which_tiles:
|
||||
continue
|
||||
|
||||
rots = [np.rot90(tile, k) for k in range(4)]
|
||||
flips = [np.flip(r, axis=1) for r in rots] # flip horizontally
|
||||
all_orients = rots + flips # 8 orientations
|
||||
|
||||
seen: set[tuple[Any, bytes]] = set()
|
||||
for t in all_orients:
|
||||
key = (t.shape, t.tobytes())
|
||||
if key not in seen:
|
||||
seen.add(key)
|
||||
permutations.append((i, t))
|
||||
|
||||
return permutations
|
||||
tiles = game.game_tiles()
|
||||
|
||||
|
||||
def can_place(
|
||||
board: np.ndarray, tile: np.ndarray, player: int
|
||||
board: game.Board, tile: game.Tile, player: game.Player
|
||||
) -> list[tuple[int, int]]:
|
||||
placements: list[tuple[int, int]] = []
|
||||
has_minus_one = False
|
||||
for x in range(BOARD_SIZE):
|
||||
for y in range(BOARD_SIZE):
|
||||
if board[x, y] == -1:
|
||||
has_minus_one = True
|
||||
with np.nditer(tile, flags=["multi_index"]) as it:
|
||||
for v in it:
|
||||
if v == 1:
|
||||
(i, j) = it.multi_index
|
||||
if x + i >= BOARD_SIZE:
|
||||
break
|
||||
if y + j >= BOARD_SIZE:
|
||||
break
|
||||
if board[x + i][y + j] > 0:
|
||||
break
|
||||
if x + i - 1 >= 0 and board[x + i - 1][y + j] == player:
|
||||
break
|
||||
if y + j - 1 >= 0 and board[x + i][y + j - 1] == player:
|
||||
break
|
||||
if x + i + 1 < BOARD_SIZE and board[x + i + 1][y + j] == player:
|
||||
break
|
||||
if y + j + 1 < BOARD_SIZE and board[x + i][y + j + 1] == player:
|
||||
break
|
||||
else:
|
||||
placements.append((x, y))
|
||||
final: list[tuple[int, int]] = []
|
||||
if has_minus_one:
|
||||
for x, y in placements:
|
||||
with np.nditer(tile, flags=["multi_index"]) as it:
|
||||
for v in it:
|
||||
(i, j) = it.multi_index
|
||||
if v == 1 and board[x + i, y + j] == -1:
|
||||
final.append((x, y))
|
||||
break
|
||||
else:
|
||||
for x, y in placements:
|
||||
with np.nditer(tile, flags=["multi_index"]) as it:
|
||||
for v in it:
|
||||
(i, j) = it.multi_index
|
||||
if (
|
||||
x + i + 1 < BOARD_SIZE
|
||||
and y + j + 1 < BOARD_SIZE
|
||||
and board[x + i + 1][y + j + 1] == player
|
||||
):
|
||||
final.append((x, y))
|
||||
break
|
||||
if (
|
||||
x + i + 1 < BOARD_SIZE
|
||||
and y + j - 1 >= 0
|
||||
and board[x + i + 1][y + j - 1] == player
|
||||
):
|
||||
final.append((x, y))
|
||||
break
|
||||
if (
|
||||
x + i - 1 >= 0
|
||||
and y + j + 1 < BOARD_SIZE
|
||||
and board[x + i - 1][y + j + 1] == player
|
||||
):
|
||||
final.append((x, y))
|
||||
break
|
||||
if (
|
||||
x + i - 1 >= 0
|
||||
and y + j - 1 >= 0
|
||||
and board[x + i - 1][y + j - 1] == player
|
||||
):
|
||||
final.append((x, y))
|
||||
break
|
||||
return final
|
||||
placements = []
|
||||
placements.extend
|
||||
|
||||
|
||||
def do_placement(
|
||||
tidx: int,
|
||||
tile: np.ndarray,
|
||||
placement: tuple[int, int],
|
||||
game_state: tuple[np.ndarray, list[int], list[int]],
|
||||
player: int,
|
||||
):
|
||||
assert player > 0
|
||||
(x, y) = placement
|
||||
with np.nditer(tile, flags=["multi_index"]) as it:
|
||||
for v in it:
|
||||
(i, j) = it.multi_index
|
||||
if v == 1:
|
||||
game_state[0][x + i, y + j] = player
|
||||
game_state[player].remove(tidx)
|
||||
|
||||
|
||||
def print_game_state(game_state: tuple[np.ndarray, list[int], list[int]]):
|
||||
def print_game_state(game_state: tuple[game.Board, list[int], list[int]]):
|
||||
(board, p1tiles, p2tiles) = game_state
|
||||
|
||||
for row in board:
|
||||
barr = []
|
||||
for i in range(BOARD_SIZE):
|
||||
barr.append([])
|
||||
for j in range(BOARD_SIZE):
|
||||
barr[i].append(board[(j, i)])
|
||||
|
||||
for row in barr:
|
||||
print(
|
||||
"".join(
|
||||
[
|
||||
|
|
@ -169,7 +40,7 @@ def print_game_state(game_state: tuple[np.ndarray, list[int], list[int]]):
|
|||
|
||||
|
||||
game_state = (
|
||||
make_board(),
|
||||
game.Board(),
|
||||
[i for i in range(21)],
|
||||
[i for i in range(21)],
|
||||
)
|
||||
|
|
@ -179,12 +50,15 @@ playing = True
|
|||
player = 1
|
||||
while playing:
|
||||
moves = []
|
||||
assert player > 0
|
||||
for tidx, tile in get_permutations(game_state[player]):
|
||||
for placement in can_place(game_state[0], tile, player):
|
||||
moves.append((tidx, tile, placement))
|
||||
assert player == 1 or player == 2
|
||||
gp = game.Player.P1 if player == 1 else game.Player.P2
|
||||
for tile_idx in game_state[player]:
|
||||
tile = tiles[tile_idx]
|
||||
perms = tile.permutations()
|
||||
for perm in perms:
|
||||
plcs = game_state[0].tile_placements(perm, gp)
|
||||
moves.extend((tile_idx, perm, plc) for plc in plcs)
|
||||
|
||||
print_game_state(game_state)
|
||||
print(f"player {player} has {len(moves)} options")
|
||||
|
||||
if len(moves) == 0:
|
||||
|
|
@ -193,7 +67,12 @@ while playing:
|
|||
continue
|
||||
|
||||
(tidx, tile, placement) = random.choice(moves)
|
||||
do_placement(tidx, tile, placement, game_state, player)
|
||||
print(
|
||||
f"player {player} is placing the following tile with index {tidx} at {placement}\n{tile}"
|
||||
)
|
||||
game_state[0].place(tile, placement, gp)
|
||||
game_state[player].remove(tidx)
|
||||
print_game_state(game_state)
|
||||
|
||||
if player == 1:
|
||||
player = 2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue