# Checker

## Game logic

<details>

<summary>Game Logic code</summary>

```python
def init_game(game_settings):
    init_board = [
            -1, 1, -1, 1, -1, 1, -1, 1, 
            1, -1, 1, -1, 1, -1, 1, -1, 
            -1, 1, -1, 1, -1, 1, -1, 1, 
            -1, -1, -1, -1, -1, -1, -1, -1, 
            -1, -1, -1, -1, -1, -1, -1, -1, 
            0, -1, 0, -1, 0, -1, 0, -1, 
            -1, 0, -1, 0, -1, 0, -1, 0, 
            0, -1, 0, -1, 0, -1, 0, -1
        ]
    return {
        "player_turn_idx": 0,
        "board": init_board,
        "valid_moves": _get_all_valid_moves(init_board, 0),
        "no_piece_taken_count": 0
    }

def move(state, start, end):
    board = state['board']
    if start < 0 or start >= 64:
        raise InvalidActionError("Starting position is out of bound")
    if end < 0 or end >= 64:
        raise InvalidActionError("Ending position is out of bound")
    if not _is_empty(board, end):
        raise InvalidActionError("Ending position is not empty")
    valid_moves = state['valid_moves']
    valid_move_tuples = [(move['start'], move['end']) for move in valid_moves]
    if (start, end) not in valid_move_tuples:
        raise InvalidActionError("Not a valid move")

    player_idx = state['player_turn_idx']
    is_piece_taken = False
    if abs(end - start) > 10: # jumped over something
        state['board'][end] = state['board'][start]
        state['board'][start] = -1
        state['board'][int((start + end)/2)] = -1
        is_piece_taken = True
    else: # did not jump over something
        state['board'][end] = state['board'][start]
        state['board'][start] = -1
        state['player_turn_idx'] = (player_idx + 1) % 2
    if player_idx == 0:
        if not _is_king(state['board'], end) and end <= 7:
            state['board'][end] += 2
    else:
        if not _is_king(state['board'], end) and end >= 56:
            state['board'][end] += 2
    
    if is_piece_taken:
        moves_after_jumping = _valid_move(state['board'], end, player_idx)
        more_jump_moves = []
        for next_move_end in moves_after_jumping:
            if _is_jump_move(next_move_end, end):
                more_jump_moves.append({
                    'start': end,
                    'end': next_move_end
                    })
        if len(more_jump_moves) > 0:
            state['valid_moves'] = more_jump_moves
        else:
            state['player_turn_idx'] = (player_idx + 1) % 2
            state['valid_moves'] = _get_all_valid_moves(state['board'], state['player_turn_idx'])
        state['no_piece_taken_count'] = 0
    else:
        state['no_piece_taken_count'] += 1
        state['valid_moves'] = _get_all_valid_moves(state['board'], state['player_turn_idx'])
        
    return state

def get_game_result(state):
    if len(state['valid_moves']) == 0:
        return {
            "game_result": "Winner",
            "winner_idx": 0 if state['player_turn_idx'] == 1 else 0
        }
    if state['no_piece_taken_count'] >= 40:
        return {
            "game_result": "Draw"
        }
    return {
            "game_result": "NoWinnerYet"
        }

def _is_player1_piece(board, index):
    return board[index] == 0 or board[index] == 2

def _is_player2_piece(board, index):
    return board[index] == 1 or board[index] == 3

def _is_empty(board, index):
    return board[index] == -1

def _is_king(board, index):
    return board[index] >= 2

def _index_to_row_column(index):
    return (int(index / 8), index % 8)

def _to_index(row, column):
    return row * 8 + column

def _is_jump_move(start, end):
    return abs(start - end) > 10

def _valid_move(board, start, player_idx):
    if _is_king(board, start):
        directions = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
    elif player_idx == 0:
        directions = [(-1, 1), (-1, -1)]
    else:
        directions = [(1, 1), (1, -1)]

    def _within_bound(row, column):
        return row >= 0 and column >= 0 and row < 8 and column < 8

    def is_opponent(index):
        if player_idx == 0:
            return _is_player2_piece(board, index)
        else:
            return _is_player1_piece(board, index)

    start_r, start_c = _index_to_row_column(start)
    valid_ends = []
    for d_r, d_c in directions:
        if _within_bound(start_r + d_r, start_c + d_c):
            end = _to_index(start_r + d_r, start_c + d_c)
            if _is_empty(board, end):
                valid_ends.append(end)
        if _within_bound(start_r + d_r*2, start_c + d_c*2):
            mid = _to_index(start_r + d_r, start_c + d_c)
            end = _to_index(start_r + d_r*2, start_c + d_c*2)
            if _is_empty(board, end) and is_opponent(mid):
                valid_ends.append(end)
    return valid_ends

def _get_all_valid_moves(board, player_idx):
    is_player1 = (player_idx == 0)
    is_self_func = _is_player1_piece if is_player1 else _is_player2_piece
    moves = []
    for i in range(64):
        if is_self_func(board, i):
            valid_ends = _valid_move(board, i, player_idx)
            for end in valid_ends:
                moves.append({
                    'start': i,
                    'end': end
                    })
    jump_moves = []
    for move in moves:
        if _is_jump_move(move['start'], move['end']):
            jump_moves.append(move)
    if len(jump_moves) > 0:
        return jump_moves
    return moves
```

</details>

## Game state schema

```protobuf
message State {
  string user1 = 1;
  string user2 = 2;
  string user_turn = 3;
  repeated int32 board = 4;
  repeated ValidMove valid_moves = 5;
  int32 no_piece_taken_count = 6;
}
```

```protobuf
message ValidMove {
  int32 start = 1;
  int32 end = 2;
}
```

## Action schema

```javascript
move(int start, int end)
```

[Start building now](https://botpot.ai/game/checker)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://doc.botpot.ai/games/explore/checker.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
