mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-23 07:29:02 -08:00
complete port HEXAPAWN to Python
refactoring for more pythonic idioms, moved parallel data arrays into a class, which helped structure board matching functionality and move list updating. Should be pretty readable now.
This commit is contained in:
@@ -14,6 +14,38 @@ Conversion to MITS BASIC by Steve North
|
||||
Port to Python by Dave LeCompte
|
||||
"""
|
||||
|
||||
"""
|
||||
PORTING NOTES:
|
||||
|
||||
I printed out the BASIC code and hand-annotated what each little block
|
||||
of code did, which feels amazingly retro.
|
||||
|
||||
I encourage other porters that have a complex knot of GOTOs and
|
||||
semi-nested subroutines to do hard-copy hacking, it might be a
|
||||
different perspective that helps.
|
||||
|
||||
A spoiler - the objective of the game is not documented, ostensibly to
|
||||
give the human player a challenge. If a player (human or computer)
|
||||
advances a pawn across the board to the far row, that player wins. If
|
||||
a player has no legal moves (either by being blocked, or all their
|
||||
pieces having been captured), that player loses.
|
||||
|
||||
The original BASIC had 2 2-dimensional tables stored in DATA at the
|
||||
end of the program. This encoded all 19 different board configurations
|
||||
(Hexapawn is a small game), with reflections in one table, and then in
|
||||
a parallel table, for each of the 19 rows, a list of legal moves was
|
||||
encoded by turning them into 2-digit decimal numbers. As gameplay
|
||||
continued, the AI would overwrite losing moves with 0 in the second
|
||||
array.
|
||||
|
||||
My port takes this "parallel array" structure and turns that
|
||||
information into a small Python class, BoardLayout. BoardLayout stores
|
||||
the board description and legal moves, but stores the moves as (row,
|
||||
column) 2-tuples, which is easier to read. The logic for checking if a
|
||||
BoardLayout matches the current board, as well as removing losing move
|
||||
have been moved into methods of this class.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import random
|
||||
|
||||
@@ -23,12 +55,19 @@ HUMAN_PIECE = 1
|
||||
EMPTY_SPACE = 0
|
||||
COMPUTER_PIECE = -1
|
||||
|
||||
ComputerMove = collections.namedtuple('ComputerMove', ['x', 'y', 'm1', 'm2'])
|
||||
ComputerMove = collections.namedtuple(
|
||||
"ComputerMove", ["board_index", "move_index", "m1", "m2"]
|
||||
)
|
||||
|
||||
wins = 0
|
||||
losses = 0
|
||||
|
||||
|
||||
def print_centered(msg):
|
||||
spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
|
||||
print(spaces + msg)
|
||||
|
||||
|
||||
def print_header(title):
|
||||
print_centered(title)
|
||||
print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
@@ -36,8 +75,10 @@ def print_header(title):
|
||||
print()
|
||||
print()
|
||||
|
||||
|
||||
def print_instructions():
|
||||
print("""
|
||||
print(
|
||||
"""
|
||||
THIS PROGRAM PLAYS THE GAME OF HEXAPAWN.
|
||||
HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.
|
||||
THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO
|
||||
@@ -67,7 +108,8 @@ YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION
|
||||
'YOUR MOVE ?'. SINCE I'M A GOOD SPORT, YOU'LL ALWAYS
|
||||
GO FIRST.
|
||||
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def prompt_yes_no(msg):
|
||||
@@ -79,208 +121,239 @@ def prompt_yes_no(msg):
|
||||
elif response[0] == "N":
|
||||
return False
|
||||
|
||||
def reverse_board_position(x):
|
||||
assert(x >= 1 and x < 10)
|
||||
|
||||
score = {1: 3,
|
||||
2: 2,
|
||||
3: 1,
|
||||
4: 6,
|
||||
5: 5,
|
||||
6: 4,
|
||||
7: 9,
|
||||
8: 8,
|
||||
9: 7}
|
||||
return score[x]
|
||||
|
||||
def get_b(x, y):
|
||||
data = [[-1, -1, -1, 1, 0, 0, 0, 1, 1],
|
||||
[-1, -1, -1, 0, 1, 0, 1, 0, 1],
|
||||
[-1, 0, -1, -1, 1, 0, 0, 0, 1],
|
||||
[ 0, -1, -1, 1, -1, 0, 0, 0, 1],
|
||||
[-1, 0, -1, 1, 1, 0, 0, 1, 0],
|
||||
[-1, -1, 0, 1, 0, 1, 0, 0, 1],
|
||||
[ 0, -1, -1, 0, -1, 1, 1, 0, 0],
|
||||
[ 0, -1, -1, -1, 1, 1, 1, 0, 0],
|
||||
[-1, 0, -1, -1, 0, 1, 0, 1, 0],
|
||||
[ 0, -1, -1, 0, 1, 0, 0, 0, 1],
|
||||
[ 0, -1, -1, 0, 1, 0, 1, 0, 0],
|
||||
[-1, 0, -1, 1, 0, 0, 0, 0, 1],
|
||||
[ 0, 0, -1, -1, -1, 1, 0, 0, 0],
|
||||
[-1, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||
[ 0, -1, 0, -1, 1, 1, 0, 0, 0],
|
||||
[-1, 0, 0, -1, -1, 1, 0, 0, 0],
|
||||
[ 0, 0, -1, -1, 1, 0, 0, 0, 0],
|
||||
[ 0, -1, 0, 1, -1, 0, 0, 0, 0],
|
||||
[-1, 0, 0, -1, 1, 0, 0, 0, 0]]
|
||||
def reverse_space_name(space_name):
|
||||
# reverse a space name in the range 1-9 left to right
|
||||
assert 1 <= space_name <= 9
|
||||
|
||||
assert(x >= 1 and x < 20)
|
||||
assert(y >= 1 and y < 10)
|
||||
reflections = {1: 3, 2: 2, 3: 1, 4: 6, 5: 5, 6: 4, 7: 9, 8: 8, 9: 7}
|
||||
return reflections[space_name]
|
||||
|
||||
return data[x-1][y-1]
|
||||
|
||||
m_data = [[24, 25, 36, 0],
|
||||
[14, 15, 36, 0],
|
||||
[15, 35, 36, 47],
|
||||
[36, 58, 59, 0],
|
||||
[15, 35, 36, 0],
|
||||
[24, 25, 26, 0],
|
||||
[26, 57, 58, 0],
|
||||
[26, 35, 0, 0],
|
||||
[47, 48, 0, 0],
|
||||
[35, 36, 0, 0],
|
||||
[35, 36, 0, 0],
|
||||
[36, 0, 0, 0],
|
||||
[47, 58, 0, 0],
|
||||
[15, 0, 0, 0],
|
||||
[26, 47, 0, 0],
|
||||
[47, 58, 0, 0],
|
||||
[35, 36, 47, 0],
|
||||
[28, 58, 0, 0],
|
||||
[15, 47, 0, 0]]
|
||||
def is_space_in_center_column(space_name):
|
||||
return reverse_space_name(space_name) == space_name
|
||||
|
||||
def get_m(x, y):
|
||||
assert(x >= 1 and x < 20)
|
||||
assert(y >= 1 and y < 5)
|
||||
|
||||
return m_data[x-1][y-1]
|
||||
class BoardLayout:
|
||||
def __init__(self, cells, move_list):
|
||||
self.cells = cells
|
||||
self.moves = move_list
|
||||
|
||||
def _check_match_no_mirror(self, cell_list):
|
||||
for space_index, board_contents in enumerate(self.cells):
|
||||
if board_contents != cell_list[space_index]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _check_match_with_mirror(self, cell_list):
|
||||
for space_index, board_contents in enumerate(self.cells):
|
||||
reversed_space_index = reverse_space_name(space_index + 1) - 1
|
||||
if board_contents != cell_list[reversed_space_index]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_match(self, cell_list):
|
||||
if self._check_match_with_mirror(cell_list):
|
||||
return True, True
|
||||
elif self._check_match_no_mirror(cell_list):
|
||||
return True, False
|
||||
return False, None
|
||||
|
||||
def get_random_move(self, reverse_board):
|
||||
if not self.moves:
|
||||
return None
|
||||
move_index = random.randrange(len(self.moves))
|
||||
|
||||
m1, m2 = self.moves[move_index]
|
||||
if reverse_board:
|
||||
m1 = reverse_space_name(m1)
|
||||
m2 = reverse_space_name(m2)
|
||||
|
||||
return move_index, m1, m2
|
||||
|
||||
|
||||
boards = [
|
||||
BoardLayout([-1, -1, -1, 1, 0, 0, 0, 1, 1], [(2, 4), (2, 5), (3, 6)]),
|
||||
BoardLayout([-1, -1, -1, 0, 1, 0, 1, 0, 1], [(1, 4), (1, 5), (3, 6)]),
|
||||
BoardLayout([-1, 0, -1, -1, 1, 0, 0, 0, 1], [(1, 5), (3, 5), (3, 6), (4, 7)]),
|
||||
BoardLayout([0, -1, -1, 1, -1, 0, 0, 0, 1], [(3, 6), (5, 8), (5, 9)]),
|
||||
BoardLayout([-1, 0, -1, 1, 1, 0, 0, 1, 0], [(1, 5), (3, 5), (3, 6)]),
|
||||
BoardLayout([-1, -1, 0, 1, 0, 1, 0, 0, 1], [(2, 4), (2, 5), (2, 6)]),
|
||||
BoardLayout([0, -1, -1, 0, -1, 1, 1, 0, 0], [(2, 6), (5, 7), (5, 8)]),
|
||||
BoardLayout([0, -1, -1, -1, 1, 1, 1, 0, 0], [(2, 6), (3, 5)]),
|
||||
BoardLayout([-1, 0, -1, -1, 0, 1, 0, 1, 0], [(4, 7), (4, 8)]),
|
||||
BoardLayout([0, -1, -1, 0, 1, 0, 0, 0, 1], [(3, 5), (3, 6)]),
|
||||
BoardLayout([0, -1, -1, 0, 1, 0, 1, 0, 0], [(3, 5), (3, 6)]),
|
||||
BoardLayout([-1, 0, -1, 1, 0, 0, 0, 0, 1], [(3, 6)]),
|
||||
BoardLayout([0, 0, -1, -1, -1, 1, 0, 0, 0], [(4, 7), (5, 8)]),
|
||||
BoardLayout([-1, 0, 0, 1, 1, 1, 0, 0, 0], [(1, 5)]),
|
||||
BoardLayout([0, -1, 0, -1, 1, 1, 0, 0, 0], [(2, 6), (4, 7)]),
|
||||
BoardLayout([-1, 0, 0, -1, -1, 1, 0, 0, 0], [(4, 7), (5, 8)]),
|
||||
BoardLayout([0, 0, -1, -1, 1, 0, 0, 0, 0], [(3, 5), (3, 6), (4, 7)]),
|
||||
BoardLayout([0, -1, 0, 1, -1, 0, 0, 0, 0], [(2, 8), (5, 8)]),
|
||||
BoardLayout([-1, 0, 0, -1, 1, 0, 0, 0, 0], [(1, 5), (4, 7)]),
|
||||
]
|
||||
|
||||
|
||||
def get_move(board_index, move_index):
|
||||
assert board_index >= 0 and board_index < len(boards)
|
||||
board = boards[board_index]
|
||||
|
||||
assert move_index >= 0 and move_index < len(board.moves)
|
||||
|
||||
return board.moves[move_index]
|
||||
|
||||
|
||||
def remove_move(board_index, move_index):
|
||||
assert board_index >= 0 and board_index < len(boards)
|
||||
board = boards[board_index]
|
||||
|
||||
assert move_index >= 0 and move_index < len(board.moves)
|
||||
|
||||
del board.moves[move_index]
|
||||
|
||||
def set_m(x, y, value):
|
||||
m_data[x-1][y-1] = value
|
||||
|
||||
def init_board():
|
||||
return ([COMPUTER_PIECE] * 3 +
|
||||
[EMPTY_SPACE] * 3 +
|
||||
[HUMAN_PIECE] * 3)
|
||||
return [COMPUTER_PIECE] * 3 + [EMPTY_SPACE] * 3 + [HUMAN_PIECE] * 3
|
||||
|
||||
|
||||
def print_board(board):
|
||||
piece_dict = {COMPUTER_PIECE: 'X',
|
||||
EMPTY_SPACE: '.',
|
||||
HUMAN_PIECE: 'O'}
|
||||
piece_dict = {COMPUTER_PIECE: "X", EMPTY_SPACE: ".", HUMAN_PIECE: "O"}
|
||||
|
||||
space = " "*10
|
||||
space = " " * 10
|
||||
print()
|
||||
for i in range(3):
|
||||
for row in range(3):
|
||||
line = ""
|
||||
for j in range(3):
|
||||
for column in range(3):
|
||||
line += space
|
||||
space_number = i * 3 + j
|
||||
space_number = row * 3 + column
|
||||
space_contents = board[space_number]
|
||||
line += piece_dict[space_contents]
|
||||
print(line)
|
||||
print()
|
||||
|
||||
|
||||
def get_coordinates():
|
||||
while True:
|
||||
try:
|
||||
print ("YOUR MOVE?")
|
||||
print("YOUR MOVE?")
|
||||
response = input()
|
||||
m1, m2 = [int(c) for c in response.split(',')]
|
||||
m1, m2 = [int(c) for c in response.split(",")]
|
||||
return m1, m2
|
||||
except ValueError as ve:
|
||||
print_illegal()
|
||||
|
||||
|
||||
def print_illegal():
|
||||
print("ILLEGAL MOVE.")
|
||||
|
||||
|
||||
def board_contents(board, space_number):
|
||||
return board[space_number - 1]
|
||||
|
||||
|
||||
def set_board(board, space_number, new_value):
|
||||
board[space_number - 1] = new_value
|
||||
|
||||
def is_legal_move(board, m1, m2):
|
||||
|
||||
def is_legal_human_move(board, m1, m2):
|
||||
if board_contents(board, m1) != HUMAN_PIECE:
|
||||
# Start space doesn't contain player's piece
|
||||
return False
|
||||
if board_contents(board, m2) == HUMAN_PIECE:
|
||||
# Destination space contains player's piece (can't capture your own piece)
|
||||
return False
|
||||
# line 160
|
||||
is_capture = (m2-m1 != -3)
|
||||
|
||||
is_capture = m2 - m1 != -3
|
||||
if is_capture and board_contents(board, m2) != COMPUTER_PIECE:
|
||||
# Destination does not contain computer piece
|
||||
return False
|
||||
# line 170
|
||||
|
||||
if m2 > m1:
|
||||
# can't move backwards
|
||||
return False
|
||||
# line 180
|
||||
|
||||
if (not is_capture) and board_contents(board, m2) != EMPTY_SPACE:
|
||||
# Destination is not open
|
||||
return False
|
||||
# line 185
|
||||
if m2-m1 < -4:
|
||||
|
||||
if m2 - m1 < -4:
|
||||
# too far
|
||||
return False
|
||||
# line 186
|
||||
|
||||
if m1 == 7 and m2 == 3:
|
||||
# can't jump corner to corner (wrapping around the board)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def player_piece_on_back_row(board):
|
||||
for space in range(1,4):
|
||||
for space in range(1, 4):
|
||||
if board_contents(board, space) == HUMAN_PIECE:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def computer_piece_on_front_row(board):
|
||||
for space in range(7, 10):
|
||||
if board_contents(board, space) == COMPUTER_PIECE:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def all_human_pieces_captured(board):
|
||||
return len(list(get_human_spaces(board))) == 0
|
||||
|
||||
|
||||
def all_computer_pieces_captured(board):
|
||||
return len(list(get_computer_spaces(board))) == 0
|
||||
|
||||
|
||||
def human_win(last_computer_move):
|
||||
print("YOU WIN")
|
||||
set_m(last_computer_move.x, last_computer_move.y, 0)
|
||||
global l
|
||||
l += 1
|
||||
remove_move(last_computer_move.board_index, last_computer_move.move_index)
|
||||
global losses
|
||||
losses += 1
|
||||
|
||||
|
||||
def computer_win(has_moves):
|
||||
if has_moves:
|
||||
if not has_moves:
|
||||
msg = "YOU CAN'T MOVE, SO "
|
||||
else:
|
||||
msg = ""
|
||||
msg += "I WIN"
|
||||
print(msg)
|
||||
global w
|
||||
w += 1
|
||||
global wins
|
||||
wins += 1
|
||||
|
||||
|
||||
def show_scores():
|
||||
print(f"I HAVE WON {w} AND YOU {l} OUT OF {w+l} GAMES.")
|
||||
print(f"I HAVE WON {wins} AND YOU {losses} OUT OF {wins + losses} GAMES.")
|
||||
print()
|
||||
|
||||
|
||||
def human_has_move(board):
|
||||
# line 690
|
||||
for i in get_human_spaces(board):
|
||||
if board_contents(board, i-3) == EMPTY_SPACE:
|
||||
if board_contents(board, i - 3) == EMPTY_SPACE:
|
||||
# can move piece forward
|
||||
return True
|
||||
elif reverse_board_position(i) == i:
|
||||
# line 780
|
||||
# can capture from center
|
||||
if ((board_contents(board, i-2) == COMPUTER_PIECE) or
|
||||
(board_contents(board, i-4) == COMPUTER_PIECE)):
|
||||
elif is_space_in_center_column(i):
|
||||
if (board_contents(board, i - 2) == COMPUTER_PIECE) or (
|
||||
board_contents(board, i - 4) == COMPUTER_PIECE
|
||||
):
|
||||
# can capture from center
|
||||
return True
|
||||
else:
|
||||
continue
|
||||
continue
|
||||
elif i < 7:
|
||||
# Line 760
|
||||
assert((i == 4) or (i == 6))
|
||||
# can capture computer piece at 2
|
||||
assert (i == 4) or (i == 6)
|
||||
if board_contents(board, 2) == COMPUTER_PIECE:
|
||||
# can capture computer piece at 2
|
||||
return True
|
||||
else:
|
||||
continue
|
||||
elif board_contents(board, 5) == COMPUTER_PIECE:
|
||||
assert((i == 7) or (i == 9))
|
||||
assert (i == 7) or (i == 9)
|
||||
# can capture computer piece at 5
|
||||
return True
|
||||
else:
|
||||
@@ -289,38 +362,43 @@ def human_has_move(board):
|
||||
|
||||
|
||||
def get_board_spaces():
|
||||
""" generates the space names (1-9)"""
|
||||
yield from range(1, 10)
|
||||
|
||||
|
||||
def get_board_spaces_with(board, val):
|
||||
""" generates spaces containing pieces of type val"""
|
||||
for i in get_board_spaces():
|
||||
if board_contents(board, i) == val:
|
||||
yield i
|
||||
|
||||
|
||||
def get_human_spaces(board):
|
||||
yield from get_board_spaces_with(board, HUMAN_PIECE)
|
||||
|
||||
|
||||
def get_empty_spaces(board):
|
||||
yield from get_board_spaces_with(board, EMPTY_SPACE)
|
||||
|
||||
|
||||
def get_computer_spaces(board):
|
||||
yield from get_board_spaces_with(board, COMPUTER_PIECE)
|
||||
|
||||
|
||||
|
||||
def has_computer_move(board):
|
||||
for i in get_computer_spaces(board):
|
||||
found_move = False
|
||||
if board_contents(board, i+3) == EMPTY_SPACE:
|
||||
if board_contents(board, i + 3) == EMPTY_SPACE:
|
||||
# can move forward (down)
|
||||
return True
|
||||
|
||||
# line 260
|
||||
if reverse_board_position(i) == i:
|
||||
if is_space_in_center_column(i):
|
||||
# i is in the middle column
|
||||
if ((board_contents(board, i + 2) == HUMAN_PIECE) or
|
||||
(board_contents(board, i + 4) == HUMAN_PIECE)):
|
||||
if (board_contents(board, i + 2) == HUMAN_PIECE) or (
|
||||
board_contents(board, i + 4) == HUMAN_PIECE
|
||||
):
|
||||
return True
|
||||
else:
|
||||
# line 270
|
||||
if i > 3:
|
||||
# beyond the first row
|
||||
if board_contents(board, 8) == HUMAN_PIECE:
|
||||
@@ -329,7 +407,6 @@ def has_computer_move(board):
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
# line 280
|
||||
if board_contents(board, 5) == HUMAN_PIECE:
|
||||
# can capture on 5
|
||||
return True
|
||||
@@ -337,104 +414,48 @@ def has_computer_move(board):
|
||||
continue
|
||||
return False
|
||||
|
||||
def get_flipped_table(b_line): # TODO remove table altogether
|
||||
t = {}
|
||||
# line 360
|
||||
for row in range(1, 4):
|
||||
for column in range(1, 4):
|
||||
# line 380
|
||||
flipped_column = 4 - column
|
||||
|
||||
# fill out t to represent the data from b flipped left to right
|
||||
space = (row-1) * 3 + column
|
||||
flipped_space = (row - 1) * 3 + flipped_column
|
||||
|
||||
t[space] = get_b(b_line, flipped_space)
|
||||
return t
|
||||
|
||||
def board_matches_b(b_line, board):
|
||||
for s in get_board_spaces():
|
||||
if get_b(b_line, s) != board_contents(board, s):
|
||||
return False
|
||||
return True
|
||||
def find_board_index_that_matches_board(board):
|
||||
for board_index, board_layout in enumerate(boards):
|
||||
matches, is_reversed = board_layout.check_match(board)
|
||||
if matches:
|
||||
return board_index, is_reversed
|
||||
|
||||
def board_matches_flipped_b(b_line, board):
|
||||
flipped_table = get_flipped_table(b_line)
|
||||
|
||||
for s in get_board_spaces():
|
||||
if flipped_table[s] != board_contents(board, s):
|
||||
return False
|
||||
return True
|
||||
|
||||
def does_b_line_match(b_line, board):
|
||||
if board_matches_b(b_line, board):
|
||||
return True, False
|
||||
elif board_matches_flipped_b(b_line, board):
|
||||
return True, True
|
||||
else:
|
||||
return False, None
|
||||
|
||||
def has_any_m_table(x):
|
||||
for i in range(1,5):
|
||||
if get_m(x, i) != 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def pick_from_m_table(x):
|
||||
valid_y_list = [y for y in range(1,5) if get_m(x, y) != 0]
|
||||
assert(len(valid_y_list) > 0)
|
||||
return random.choice(valid_y_list)
|
||||
|
||||
|
||||
def get_move_for_b_line(b_line, reverse_board):
|
||||
# line 540
|
||||
x = b_line
|
||||
|
||||
if not has_any_m_table(x):
|
||||
return None
|
||||
|
||||
# line 600
|
||||
y = pick_from_m_table(x)
|
||||
|
||||
# line 610
|
||||
mxy = get_m(x, y)
|
||||
m1 = mxy // 10
|
||||
m2 = mxy % 10
|
||||
if reverse_board:
|
||||
m1 = reverse_board_position(m1)
|
||||
m2 = reverse_board_position(m2)
|
||||
|
||||
return ComputerMove(x, y, m1, m2)
|
||||
|
||||
|
||||
def find_b_line_that_matches_board(board):
|
||||
for b_line in range(1,20):
|
||||
matches, reverse_board = does_b_line_match(b_line, board)
|
||||
if matches:
|
||||
return b_line, reverse_board
|
||||
|
||||
# THE TERMINATION OF THIS LOOP IS IMPOSSIBLE
|
||||
print("ILLEGAL BOARD PATTERN.")
|
||||
assert(False)
|
||||
|
||||
|
||||
assert False
|
||||
|
||||
|
||||
def pick_computer_move(board):
|
||||
if not has_computer_move(board):
|
||||
# Line 340
|
||||
return None
|
||||
|
||||
# line 350
|
||||
b_line, reverse_board = find_b_line_that_matches_board(board)
|
||||
board_index, reverse_board = find_board_index_that_matches_board(board)
|
||||
|
||||
m = get_move_for_b_line(b_line, reverse_board)
|
||||
m = boards[board_index].get_random_move(reverse_board)
|
||||
|
||||
if m == None:
|
||||
if m is None:
|
||||
print("I RESIGN")
|
||||
return None
|
||||
|
||||
return m
|
||||
|
||||
|
||||
move_index, m1, m2 = m
|
||||
|
||||
return ComputerMove(board_index, move_index, m1, m2)
|
||||
|
||||
|
||||
def get_human_move(board):
|
||||
while True:
|
||||
m1, m2 = get_coordinates()
|
||||
|
||||
if not is_legal_human_move(board, m1, m2):
|
||||
print_illegal()
|
||||
else:
|
||||
return m1, m2
|
||||
|
||||
|
||||
def apply_move(board, m1, m2, piece_value):
|
||||
set_board(board, m1, EMPTY_SPACE)
|
||||
set_board(board, m2, piece_value)
|
||||
|
||||
|
||||
def play_game():
|
||||
@@ -444,149 +465,52 @@ def play_game():
|
||||
|
||||
while True:
|
||||
print_board(board)
|
||||
|
||||
has_legal_move = False
|
||||
while not has_legal_move:
|
||||
m1, m2 = get_coordinates()
|
||||
|
||||
if not is_legal_move(board, m1, m2):
|
||||
print_illegal()
|
||||
else:
|
||||
# otherwise, acceptable move
|
||||
has_legal_move = True
|
||||
|
||||
set_board(board, m1, 0)
|
||||
set_board(board, m2, 1)
|
||||
|
||||
# line 205
|
||||
|
||||
m1, m2 = get_human_move(board)
|
||||
|
||||
apply_move(board, m1, m2, HUMAN_PIECE)
|
||||
|
||||
print_board(board)
|
||||
|
||||
if (player_piece_on_back_row(board) or
|
||||
all_computer_pieces_captured(board)):
|
||||
|
||||
if player_piece_on_back_row(board) or all_computer_pieces_captured(board):
|
||||
human_win(last_computer_move)
|
||||
return
|
||||
|
||||
# line 230
|
||||
|
||||
computer_move = pick_computer_move(board)
|
||||
if computer_move is None:
|
||||
human_win(last_computer_move)
|
||||
return
|
||||
|
||||
last_computer_move = computer_move
|
||||
|
||||
|
||||
m1, m2 = last_computer_move.m1, last_computer_move.m2
|
||||
|
||||
|
||||
print(f"I MOVE FROM {m1} TO {m2}")
|
||||
set_board(board, m1, 0)
|
||||
set_board(board, m2, -1)
|
||||
|
||||
# line 640
|
||||
apply_move(board, m1, m2, COMPUTER_PIECE)
|
||||
|
||||
print_board(board)
|
||||
|
||||
if (computer_piece_on_front_row(board) or
|
||||
all_human_pieces_captured(board)):
|
||||
|
||||
if computer_piece_on_front_row(board):
|
||||
computer_win(True)
|
||||
return
|
||||
elif not human_has_move(board):
|
||||
elif (not human_has_move(board)) or (all_human_pieces_captured(board)):
|
||||
computer_win(False)
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
print_header("HEXAPAWN")
|
||||
if prompt_yes_no("INSTRUCTIONS (Y-N)?"):
|
||||
print_instructions()
|
||||
|
||||
global w, l
|
||||
w = 0
|
||||
l = 0
|
||||
global wins, losses
|
||||
wins = 0
|
||||
losses = 0
|
||||
|
||||
while True:
|
||||
play_game()
|
||||
show_scores()
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
"""
|
||||
230 FOR I=1 TO 9
|
||||
240 IF S(I)<>-1 THEN 330
|
||||
250 IF S(I+3)=0 THEN 350
|
||||
260 IF FNR(I)=I THEN 320
|
||||
270 IF I>3 THEN 300
|
||||
280 IF S(5)=1 THEN 350
|
||||
290 GOTO 330
|
||||
300 IF S(8)=1 THEN 350
|
||||
310 GOTO 330
|
||||
320 IF S(I+2)=1 OR S(I+4)=1 THEN 350
|
||||
330 NEXT I
|
||||
340 GOTO 820
|
||||
350 FOR I=1 TO 19
|
||||
360 FOR J=1 TO 3
|
||||
370 FOR K=3 TO 1 STEP -1
|
||||
380 T((J-1)*3+K)=B(I,(J-1)*3+4-K)
|
||||
390 NEXT K
|
||||
400 NEXT J
|
||||
410 FOR J=1 TO 9
|
||||
420 IF S(J)<>B(I,J) THEN 460
|
||||
430 NEXT J
|
||||
440 R=0
|
||||
450 GOTO 540
|
||||
460 FOR J=1 TO 9
|
||||
470 IF S(J)<>T(J) THEN 510
|
||||
480 NEXT J
|
||||
490 R=1
|
||||
500 GOTO 540
|
||||
510 NEXT I
|
||||
511 REMEMBER THE TERMINATION OF THIS LOOP IS IMPOSSIBLE
|
||||
512 PRINT "ILLEGAL BOARD PATTERN."
|
||||
530 STOP
|
||||
540 X=I
|
||||
550 FOR I=1 TO 4
|
||||
560 IF M(X,I)<>0 THEN 600
|
||||
570 NEXT I
|
||||
580 PRINT "I RESIGN."
|
||||
590 GOTO 820
|
||||
600 Y=INT(RND(1)*4+1)
|
||||
601 IF M(X,Y)=0 THEN 600
|
||||
610 IF R<>0 THEN 630
|
||||
620 PRINT "I MOVE FROM ";STR$(INT(M(X,Y)/10));" TO ";STR$(FNM(M(X,Y)))
|
||||
622 S(INT(M(X,Y)/10))=0
|
||||
623 S(FNM(M(X,Y)))=-1
|
||||
624 GOTO 640
|
||||
630 PRINT "I MOVE FROM ";STR$(FNR(INT(M(X,Y)/10)));" TO ";
|
||||
631 PRINT STR$(FNR(FNM(M(X,Y))))
|
||||
632 S(FNR(INT(M(X,Y)/10)))=0
|
||||
633 S(FNR(FNM(M(X,Y))))=-1
|
||||
640 GOSUB 1000
|
||||
641 IF S(7)=-1 OR S(8)=-1 OR S(9)=-1 THEN 870
|
||||
650 FOR I=1 TO 9
|
||||
660 IF S(I)=1 THEN 690
|
||||
670 NEXT I
|
||||
680 GOTO 870
|
||||
690 FOR I=1 TO 9
|
||||
700 IF S(I)<>1 THEN 790
|
||||
710 IF S(I-3)=0 THEN 120
|
||||
720 IF FNR(I)=I THEN 780
|
||||
730 IF I<7 THEN 760
|
||||
740 IF S(5)=-1 THEN 120
|
||||
750 GOTO 790
|
||||
760 IF S(2)=-1 THEN 120
|
||||
770 GOTO 790
|
||||
780 IF S(I-2)=-1 OR S(I-4)=-1 THEN 120
|
||||
790 NEXT I
|
||||
800 PRINT "YOU CAN'T MOVE, SO ";
|
||||
810 GOTO 870
|
||||
820 PRINT "YOU WIN."
|
||||
830 M(X,Y)=0
|
||||
840 L=L+1
|
||||
850 PRINT "I HAVE WON";W;"AND YOU";L;"OUT OF";L+W;"GAMES."
|
||||
851 PRINT
|
||||
860 GOTO 100
|
||||
870 PRINT "I WIN."
|
||||
880 W=W+1
|
||||
890 GOTO 850
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user