class TestBoard: def setup_method(self, method): self.b = Board() self.valid_pos = {'row': 0, 'col': 1} self.invalid_pos = {'row': 0, 'col': -5} self.color = 'red' def test_default_board_size(self): assert len(self.b.grid) == 3 def test_board_is_seeded_with__none(self): flat_grid = self.b.flattened_grid() assert all(val is None for val in flat_grid) def test_board_set_with_invalid_pos(self): with pytest.raises(InvalidMoveError) as excinfo: self.b.set(self.invalid_pos, self.color) assert 'position is off the board' in str(excinfo.value) def test_board_set_valid(self): self.b.set(self.valid_pos, self.color) assert isinstance(self.b.get(self.valid_pos), Piece) def test_board_set_invalid(self): self.b.set(self.valid_pos, self.color) with pytest.raises(InvalidMoveError) as excinfo: self.b.set(self.valid_pos, self.color) assert 'Space allready occupied' in str(excinfo.value)
class Othello: def __init__(self): pyxel.init(SCREEN_WIDTH, SCREEN_HEIGHT, caption="Pyxel Othello") pyxel.mouse(True) self.board = Board() self.current = 'black' self.black_player = RandomPlayer(pyxel, self.board, 'black') self.white_player = RandomPlayer(pyxel, self.board, 'white') self.winner = None self.previous_frame_count = 0 pyxel.run(self.update, self.draw) def change_turn(self): """ 手番の変更 """ self.current = 'white' if self.current == 'black' else 'black' self.winner = self.board.winner() def current_player(self): """ 現在のプレイヤーを取得 """ return self.black_player if self.current == 'black' else self.white_player def update(self): """ フレームの更新 """ if pyxel.btnp(pyxel.KEY_Q): pyxel.quit() return if self.winner is not None: return if self.current_player().move(self.previous_frame_count): self.previous_frame_count = pyxel.frame_count self.change_turn() def draw(self): """ フレームの描画 """ # 盤面の描画 pyxel.cls(0) pyxel.rect(0, 0, SCREEN_WIDTH, SCREEN_WIDTH, 3) r_idx, c_idx = get_indices(pyxel.mouse_x, pyxel.mouse_y) # 配置できる場所だったらマスの色を変える if r_idx is not None and c_idx is not None and self.board.can_move( ROWS[r_idx], COLS[c_idx], self.current): pyxel.rect(SQUARE_SIZE * r_idx, SQUARE_SIZE * c_idx, SQUARE_SIZE, SQUARE_SIZE, 9) # 線の描画 for i in range(len(ROWS) + 1): pyxel.line(SQUARE_SIZE * i, 0, SQUARE_SIZE * i, 240, 0) pyxel.line(0, SQUARE_SIZE * i, 240, SQUARE_SIZE * i, 0) # 石の描画 for x, row in enumerate(ROWS): for y, col in enumerate(COLS): color = self.board.get(row, col) if color: code = 0 if color == 'black' else 7 pyxel.circ(SQUARE_SIZE * x + SQUARE_SIZE // 2, SQUARE_SIZE * y + SQUARE_SIZE // 2, 12, code) # パスボタンの描画 can_pass = self.winner is None and self.board.can_pass(self.current) pyxel.rect(PASS_BTN_X, PASS_BTN_Y, PASS_BTN_W, PASS_BTN_H, 9 if can_pass else 13) pyxel.text(PASS_BTN_X + 10, PASS_BTN_Y + 3, 'PASS', 7) # 現在のプレイヤー表示 pyxel.text( 4, SCREEN_WIDTH + 5, "Black's turn" if self.current == 'black' else "White's turn", 7) # ゲーム終了メッセージの描画 if self.winner: color = 'Black' if self.winner == 'black' else 'White' pyxel.text(SCREEN_WIDTH // 2 - 34, SCREEN_WIDTH + 5, "{} player wins!".format(color), 14)