Joe Jordan :: jbot2.py (v4)

This bot has played 1250 games (264 wins / 8 draws / 978 losses).

Play against this bot as X or as O.

These bots have done best aganist jbot2.py...

Bot P W D L Points Size From beginner One hit wonder Goldfish
Jon Bannister : : anybot_r282.py (v5) 10 10 0 0 10 974 False False True
Daniel Patrick : : error_unable_to_connect4.py (v2) 10 10 0 0 10 757 False False True
Ian Ozsvald : : ian12.py 10 10 0 0 10 943 False False True
Robert Seaman : : not_minimax.py (v25) 10 10 0 0 10 3501 False False True
Séverin Hatt : : romuald_no_last_check.py (v1) 10 10 0 0 10 1598 False False True

...and these bots have done worst

Bot P W D L Points Size From beginner One hit wonder Goldfish
house : : centrist.py 10 0 0 10 -10 None None None None
James Campbell : : horrible.py (v4) 10 0 0 10 -10 246 False False True
Ronan Murphy : : loser.py 10 0 0 10 -10 105 False False True
Luke Spademan : : lossingbot.py (v3) 10 0 0 10 -10 129 False False True
house : : opportunist.py 10 0 0 10 -10 None None None None

All standings against jbot2.py

The code

      
import random
from botany_connectfour import game


def diagonal_generator():
    for j in range(4):
        for i in range(4):
            yield [(0+i, 0+j), (1+i, 1+j), (2+i, 2+j), (3+i, 3+j)]
            yield [(3+i, 0+j), (2+i, 1+j), (1+i, 2+j), (0+i, 3+j)]


def decide_strategy(board, token, old_state):
    other_token = 'O' if token == 'X' else 'X'

    # horizontal (along the bottom)
    if all(col[0] != other_token for col in board):
        return [(2, 0), (3, 0), (4, 0), (5, 0)]

    # vertical
    for i, col in enumerate(board):
        if other_token not in col:
            return [(i, 0), (i, 1), (i, 2), (i, 3)]

    if not old_state['no_possible_diagonals']:
        # diagonals
        for line in diagonal_generator():
            if all(board[i][j] != other_token for i, j in line):
                return line
    old_state['no_possible_diagonals'] = True

    for i in range(1, 7):
        for j in range(4):
            if other_token not in "".join(board[j+k][i] for k in range(5)):
                return [(0+j, i), (1+j, i), (2+j, i), (3+j, i)]

    return []


def get_new_strategy(board, token, old_state):
    line = decide_strategy(board, token, old_state)
    return {
        'line': line,
        'next_move': next_move_for_line(board, line, token),
        'no_possible_diagonals': old_state['no_possible_diagonals']
    }


def next_move_for_line(board, line, token):
    if not line:
        return random.choice([col for col in range(7) if board[col][-1] == '.'])
    for i, j in line:
        state = board[i][j]
        if state == token:
            continue
        elif state == '.':
            return i
        else:
            return None


def get_next_move(board, token, state=None):
    try:
        if state is None:
            state = {'no_possible_diagonals': False}
            state = get_new_strategy(board, token, state)
        else:
            state['next_move'] = next_move_for_line(board, state['line'], token)

        if state['next_move'] is None:
            state = get_new_strategy(board, token, state)

        other_token = 'O' if token == 'X' else 'X'

        for col in range(7):
            try:
                i, j = (col, [i for i, char in enumerate(board[col]) if char == '.'][0])
                board[i][j] = other_token
                if game.check_winner(board) is not None:
                    return col, state
                board[i][j] = '.'
            except IndexError:
                continue

        return state['next_move'], state
    except:
        return random.choice([col for col in range(7) if board[col][-1] == '.'])