Ejemplo n.º 1
0
class BoardTest(unittest.TestCase):

    def setUp(self):
        self._board = Board()

    def test__get_top_row(self):
        self._board.play_move(BoardTag.CPU, 0)
        self.assertEqual(self._board._get_top_row(0), 0)
        self._board.play_move(BoardTag.HUMAN, 0)
        self.assertEqual(self._board._get_top_row(0), 1)
        self.assertEqual(self._board._get_top_row(1), None)

    def test__check_column_access(self):
        self.assertTrue(self._board._check_column_access(0, False))
        self.assertTrue(self._board._check_column_access(6, False))
        self.assertFalse(self._board._check_column_access(-1, False))
        self.assertFalse(self._board._check_column_access(7, False))

    def test__check_row_access(self):
        self.assertTrue(self._board._check_row_access(0, False))
        self.assertTrue(self._board._check_row_access(5, False))
        self.assertFalse(self._board._check_row_access(-1, False))
        self.assertFalse(self._board._check_row_access(6, False))
        # Add moves to the same column to increase board row by 1
        for x in xrange(7):
            self._board.play_move(BoardTag.CPU, 0)
        self.assertTrue(self._board._check_row_access(6, False))

    def test_play_move(self):
        self._board.play_move(BoardTag.CPU, 0)
        self.assertEqual(self._board._board[0][0], BoardTag.CPU)
        self._board.play_move(BoardTag.HUMAN, 0)
        self.assertEqual(self._board._board[1][0], BoardTag.HUMAN)

    def test_reverse_move(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.HUMAN, 1)
        self._board.play_move(BoardTag.CPU, 0)

        self._board.reverse_move(1)
        self.assertEqual(self._board._board[0][1], BoardTag.EMPTY)
        self.assertEqual(self._board._board[0][0], BoardTag.CPU)
        self.assertEqual(self._board._board[1][0], BoardTag.CPU)

        self._board.reverse_move(0)
        self.assertEqual(self._board._board[1][0], BoardTag.EMPTY)
        self.assertEqual(self._board._board[0][0], BoardTag.CPU)

    def test__get_row_tags_1(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.HUMAN, 1)
        self._board.play_move(BoardTag.CPU, 2)
        self._board.play_move(BoardTag.CPU, 3)

        row_tags = self._board._get_row_tags(0, 0)
        self.assertSequenceEqual(row_tags, [BoardTag.CPU, BoardTag.HUMAN, BoardTag.CPU, BoardTag.CPU])

    def test__get_row_tags_2(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.CPU, 6)
        self._board.play_move(BoardTag.CPU, 3)

        row_tags = self._board._get_row_tags(0, 3)
        self.assertSequenceEqual(row_tags, [BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY,
                                            BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY,  BoardTag.CPU])

    def test__get_column_tags_1(self):
        self._board.play_move(BoardTag.CPU, 0)
        column_tags = self._board._get_column_tags(0, 0)
        self.assertSequenceEqual(column_tags, [BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.EMPTY])

    def test__get_column_tags_2(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.HUMAN, 0)
        column_tags = self._board._get_column_tags(3, 0)
        self.assertSequenceEqual(column_tags, [BoardTag.CPU, BoardTag.HUMAN, BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.EMPTY])

    def test__get_diagonal_tags_left_1(self):
        self._board.play_move(BoardTag.CPU, 6)
        self._board.play_move(BoardTag.HUMAN, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)

        left_diagonal_tags = self._board._get_diagonal_tags(0, 6)
        self.assertSequenceEqual(left_diagonal_tags, [BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.CPU])

    def test__get_diagonal_tags_left_2(self):
        self._board.play_move(BoardTag.CPU, 6)
        self._board.play_move(BoardTag.HUMAN, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)

        left_diagonal_tags = self._board._get_diagonal_tags(3, 3)
        self.assertSequenceEqual(left_diagonal_tags, [BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.CPU])

    def test__get_diagonal_tags_right_1(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.HUMAN, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)

        right_diagonal_tags = self._board._get_diagonal_tags(0, 0, True)
        self.assertSequenceEqual(right_diagonal_tags, [BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.CPU])

    def test__get_diagonal_tags_right_2(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.HUMAN, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.CPU, 3)

        right_diagonal_tags = self._board._get_diagonal_tags(3, 3, True)
        self.assertSequenceEqual(right_diagonal_tags, [BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY, BoardTag.CPU, BoardTag.EMPTY, BoardTag.EMPTY])

    def test__check4_in_row(self):
        test_row_1 = [BoardTag.CPU, BoardTag.CPU, BoardTag.CPU, BoardTag.CPU]
        self.assertTrue(Board._check4_in_list(test_row_1, BoardTag.CPU))

        test_row_2 = [BoardTag.EMPTY, BoardTag.CPU, BoardTag.CPU, BoardTag.CPU, BoardTag.CPU, BoardTag.EMPTY]
        self.assertTrue(Board._check4_in_list(test_row_2, BoardTag.CPU))

        test_row_3 = [BoardTag.CPU, BoardTag.CPU, BoardTag.EMPTY, BoardTag.CPU, BoardTag.CPU]
        self.assertFalse(Board._check4_in_list(test_row_3, BoardTag.CPU))

    def test_check_if_finished_row(self):
        self._board.play_move(BoardTag.CPU, 0)

        finished_1 = self._board.check_if_finished(0)
        self.assertFalse(finished_1[0])

        self._board.play_move(BoardTag.CPU, 1)
        self._board.play_move(BoardTag.CPU, 3)
        self._board.play_move(BoardTag.HUMAN, 1)
        self._board.play_move(BoardTag.CPU, 2)

        finished_2 = self._board.check_if_finished(2)
        self.assertTrue(finished_2[0])
        self.assertEqual(finished_2[1], BoardTag.CPU)

    def test_check_if_finished_column(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.CPU, 0)

        finished = self._board.check_if_finished(0)
        self.assertTrue(finished[0])
        self.assertEqual(finished[1], BoardTag.CPU)

    def test_check_if_finished_diagonal(self):
        self._board.play_move(BoardTag.CPU, 0)
        self._board.play_move(BoardTag.HUMAN, 1)
        self._board.play_move(BoardTag.CPU, 1)
        self._board.play_move(BoardTag.HUMAN, 2)
        self._board.play_move(BoardTag.HUMAN, 2)
        self._board.play_move(BoardTag.CPU, 2)

        finished_1 = self._board.check_if_finished(2)
        self.assertFalse(finished_1[0])

        self._board.play_move(BoardTag.HUMAN, 3)
        self._board.play_move(BoardTag.HUMAN, 3)
        self._board.play_move(BoardTag.HUMAN, 3)
        self._board.play_move(BoardTag.CPU, 3)

        finished_2 = self._board.check_if_finished(3)
        self.assertTrue(finished_2[0])
        self.assertEqual(finished_2[1], BoardTag.CPU)
Ejemplo n.º 2
0
class Master():

    def __init__(self, measuring):
        self._measuring = measuring
        self._board = Board()
        self._taskPool = TaskPool()
        self._log = Log('Master')
        self._log.debug('init')

    def work(self):
        self._log.debug('work')

        while self._move_cycle(): pass

        self._stop_workers()

    def _move_cycle(self):
            self._taskPool = TaskPool()

            self._print('CPU is thinking...')
            start_time = time.time()

            # Broadcast board data
            self._broadcast_board()

            # Send tasks to workers on request
            self._serve_tasks()

            column_quality = self._taskPool.calculate_quality()
            best_column_move = max(enumerate(column_quality), key=lambda x: x[1])[0]

            end_time = time.time() - start_time
            print (end_time if self._measuring else 'Thinking done in: %f\n' % end_time)

            # Print column quality
            for idx, quality in enumerate(column_quality):
                self._print('Column %d quality: %f' % (idx+1, quality))
            self._print('Best column move %d\n' % (best_column_move+1))

            # In case we are just measuring 1st move by CPU
            if self._measuring:
                self._stop_workers()
                return False

            self._board.play_move(BoardTag.CPU, best_column_move)
            self._board.print_board()
            self._print('')

            if self._board.check_if_finished(best_column_move)[0]:
                self._print_winner(BoardTag.CPU)
                return False

            human_column_move = self._human_turn()
            if human_column_move == -1: return False
            if self._board.check_if_finished(human_column_move)[0]:
                self._print_winner(BoardTag.HUMAN)
                return False

            return True

    def _broadcast_board(self):
        message = {'type': MessageType.BOARD_DATA, 'board': self._board}
        for x in xrange(1, comm_size):
            self._log.debug('BOARD_DATA to %d' % x)
            comm.send(message, dest=x)

    def _serve_tasks(self):
        active_workers = comm_size - 1
        finished = False
        while not finished:
            self._log.debug('waiting for DATA_REQUEST')
            # Send tasks upon request
            message_status = MPI.Status()
            message = comm.recv(source=MPI.ANY_SOURCE, status=message_status)
            message_source = message_status.Get_source()

            if message['type'] == MessageType.TASK_REQUEST:
                self._log.debug('receives TASK_REQUEST from %d' % message_source)
                task = self._taskPool.next_task()
                if task is not None:
                    message = {'type': MessageType.TASK_DATA, 'task': task}
                    self._log.debug('sends TASK_DATA to %d' % message_source)
                    comm.send(message, dest=message_source)

                else:
                    self._log.debug('sends WAIT to %d' % message_source)
                    comm.send({'type': MessageType.WAIT}, dest=message_source)
                    active_workers -= 1
                    if active_workers == 0:
                        finished = True

            elif message['type'] == MessageType.TASK_RESULT:
                self._log.debug('receives TASK_RESULT from %d' % message_source)
                self._taskPool.update_task(message['task'], message['result'])

    def _stop_workers(self):
        for x in xrange(1, comm_size):
            self._log.debug('STOP to %d' % x)
            comm.send({'type': MessageType.STOP}, dest=x)

    def _human_turn(self):
        # Take player move
        human_input = self._read_human_input()-1
        if human_input == -1:
            print 'Human gave up! CPU WINS!'
            return human_input

        # play
        self._board.play_move(BoardTag.HUMAN, human_input)
        self._board.print_board()
        print

        return human_input

    @staticmethod
    def _read_human_input():
        while True:
            print 'Human move:',
            human_input = raw_input()
            try:
                human_input = int(human_input)
                if human_input < 0 or human_input > 7:
                    raise ValueError()
                return human_input
            except ValueError:
                print 'Invalid input! Enter 1-7 for column or 0 for end'

    @staticmethod
    def _print_winner(player):
        player_label = 'CPU' if player == BoardTag.CPU else 'Human'
        print '%s won!' % player_label

    def _print(self, message):
        if not self._measuring:
            print message
Ejemplo n.º 3
0
class Worker():

    def __init__(self, worker_depth):
        self._board = Board()       # This will be overwritten when BOARD_DATA is received
        self._worker_depth = worker_depth
        self._log = Log('Worker %d' % rank)
        self._log.debug('init')

    def work(self):
        self._log.debug('work')

        # Move cycle
        while True:
            message = comm.recv(source=0)

            if message['type'] == MessageType.BOARD_DATA:
                self._log.debug('receives BOARD_DATA')
                self._board = message['board']
            elif message['type'] == MessageType.STOP:
                self._log.debug('receives STOP')
                break

            # Start requesting tasks
            while self._request_task(): pass

    def _request_task(self):
        self._log.debug('sends TASK_REQUEST')
        message = {'type': MessageType.TASK_REQUEST}
        comm.send(message, dest=0)

        message = comm.recv(source=0)
        if message['type'] == MessageType.WAIT:
            self._log.debug('receives WAIT')
            return False

        task = message['task']
        self._log.debug('receives TASK_DATA {0}'.format(task))

        # CPU first move
        if self._play_cpu(task): return True

        # Human move
        if self._play_human(task): return True

        # Evaluate in depth
        result = self._evaluate(BoardTag.CPU, task[1], self._worker_depth)

        self._board.reverse_move(task[1])
        self._board.reverse_move(task[0])

        self._log.debug('sends TASK_RESULT')
        message = {'type': MessageType.TASK_RESULT, 'task': task, 'result': result}
        comm.send(message, dest=0)

        return True

    def _play_cpu(self, task):
        self._board.play_move(BoardTag.CPU, task[0])
        if self._board.check_if_finished(task[0])[0]:
            result = 1
            self._board.reverse_move(task[0])
            message = {'type': MessageType.TASK_RESULT, 'task': task, 'result': result}
            comm.send(message, dest=0)
            return True

    def _play_human(self, task):
        self._board.play_move(BoardTag.HUMAN, task[1])
        if self._board.check_if_finished(task[1])[0]:
            result = -1
            self._board.reverse_move(task[1])
            self._board.reverse_move(task[0])
            message = {'type': MessageType.TASK_RESULT, 'task': task, 'result': result}
            comm.send(message, dest=0)
            return True

    def _evaluate(self, current_player, last_played_column, depth):
        end_check = self._board.check_if_finished(last_played_column)
        if end_check[0]:
            return 1 if end_check[1] == BoardTag.CPU else -1

        if depth == 0: return 0

        total_result = 0.0
        all_child_loses = True
        all_child_wins = True
        for column in xrange(7):
            self._board.play_move(current_player, column)
            next_player = BoardTag.HUMAN if current_player == BoardTag.CPU else BoardTag.CPU
            result = self._evaluate(next_player, column, depth-1)
            self._board.reverse_move(column)

            if result > -1: all_child_loses = False
            if result != 1: all_child_wins = False
            if result == 1 and current_player == BoardTag.HUMAN: return 1   # if win is discovered before human turn
            if result == -1 and current_player == BoardTag.CPU: return -1   # if lost is discovered before cpu turn
            total_result += result

        return 1 if all_child_wins else -1 if all_child_loses else total_result / 7