Ejemplo n.º 1
0
class Game:
    def __init__(self):
        self.side_names = ['BLACK', 'WHITE']

    def new_game(self):
        modes = [
            'Player vs Player', 'Player vs Computer', 'Computer vs Computer'
        ]
        mode = self.prompt('Welcome to checkers! Enter a number to continue.',
                           modes)
        if mode > 0:
            timelimit = self.prompt('Enter a time limit (<=20s) for the AI:')
            self.ai = AI(timelimit)
        if mode == 1:
            side = self.prompt('Select a side:', self.side_names)

        blank = Bitboard((0, 0, 0, 0))
        if self.prompt('Would you like to specify a starting board?',
                       ['No', 'Yes']):
            blank.print_board()
            black = self.prompt_list(
                'Specify whitespace delimited list of black pieces: ')
            white = self.prompt_list(
                'Specify whitespace delimited list of white pieces: ')
            kings = self.prompt_list(
                'Specify whitespace delimited list of kings: ')
            side = self.prompt('Specify starting side: ', ['BLACK', 'WHITE'])
            twokings = (2**0, 2**9 + 2**13, 2**0 + 2**9 + 2**13, 1)
            draw = (2**12, 2**21, 2**12 + 2**21, 1)
            self.board = Bitboard(
                (black, white, kings & (white | black), side))
        else:
            self.board = Bitboard()

        check_draws = self.prompt('Enable draw detection (experimental): ',
                                  ['No', 'Yes'])

        print('New game starting...')

        while (len(self.board.get_moves()) > 0):
            self.board.print_board()

            if mode == 0:
                self.player_move()
            elif mode == 1:
                if side == self.board.side:
                    self.player_move()
                else:
                    self.ai_move()
            elif mode == 2:
                self.ai_move()

            # Considered a draw if each side has one king and there is no jump
            if check_draws and self.is_draw():
                self.board.print_board()
                return self.prompt('Game ended in a draw.',
                                   ['Play again', 'Quit'])
        self.board.print_board()
        return self.prompt(
            '{} wins.'.format(self.side_names[~self.board.side]),
            ['Play again', 'Quit'])

    def player_move(self):
        moves = self.board.get_moves()
        i = self.prompt(
            '{}\'s turn, select a move'.format(
                self.side_names[self.board.side]),
            [self.board.format_move(m) for m in moves])
        self.board.make_move(moves[i])

    def ai_move(self):
        print('Finding best move for {}...'.format(
            self.side_names[self.board.side]))
        start = time.time()
        move = self.ai.iddfs(self.board)
        elapsed = time.time() - start
        print('  {} selected move {} in {:.3f}s'.format(
            self.side_names[self.board.side], self.board.format_move(move),
            elapsed))
        self.board.make_move(move)

    def is_draw(self):
        stuck = False
        if self.board.side == self.board.BLACK:
            stuck = self.board.black & ~0x00181800
        else:
            stuck = self.board.white & ~0x00181800

        return (count_bits(self.board.black) == 1
                and count_bits(self.board.white) == 1
                and self.board.black & self.board.kings
                and self.board.white & self.board.kings
                and len(self.board.get_moves()) > 1 and stuck)

    def get_custom_board(self):
        self.prompt()

    def prompt_list(self, message):
        while True:
            try:
                text = input(message).split()
                spaces = []
                for item in text:
                    if 0 <= int(item) < 32:
                        spaces.append(int(item))
                    else:
                        raise ValueError
                return sum([2**space for space in spaces])
            except ValueError:
                continue

    def prompt(self, message, options=[]):
        while True:
            try:
                selection = int(
                    input(message + '\n' + ''.join([
                        '  {!s:>2}.) {}\n'.format(i, o)
                        for i, o in enumerate(options)
                    ]) + '--> '))
            except ValueError:
                continue
            if not options:
                if selection <= 20:
                    return selection
                else:
                    continue
            elif 0 <= selection < len(options):
                return selection
            else:
                continue