File size: 4,559 Bytes
6bc2b54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import streamlit as st
import numpy as np
from object_9x9 import Player, HumanPlayer

# Create RL bot player and human player
p1 = Player("9x9_p1")
human_player = HumanPlayer("p2")

def handle_click(i, j):
    if (i, j) not in check_available_moves(extra=True):
        st.session_state.warning = True
    elif not st.session_state.winner:
        st.session_state.warning = False
        st.session_state.board[i, j] = st.session_state.player
        winner = check_win(st.session_state.board)
        if winner:
            st.session_state.winner = winner
            if st.session_state.opponent == 'Computer':
                # Give reward to the RL bot and update its policy
                if winner == 'X':
                    p1.feedReward(1)
                elif winner == 'O':
                    p1.feedReward(0)
                else:
                    p1.feedReward(0.1)
                
                # Save the RL bot's policy
                p1.savePolicy()
        
        # Toggle the player's turn
        st.session_state.player = "O" if st.session_state.player == "X" else "X"

def init(post_init=False):
    if not post_init:
        st.session_state.win = {'X': 0, 'O': 0}
        st.session_state.opponent = 'Computer'  # Initialize the opponent attribute
    st.session_state.board = np.full((9, 9), '.', dtype=str)
    st.session_state.player = 'X'
    st.session_state.warning = False
    st.session_state.winner = None
    st.session_state.over = False

def check_available_moves(extra=False) -> list:
    raw_moves = [row for col in st.session_state.board.tolist() for row in col]
    num_moves = [i for i, spot in enumerate(raw_moves) if spot == '.']
    if extra:
        return [(i // 9, i % 9) for i in num_moves]
    return num_moves

def check_win(board):
    # Check for a winner by checking rows, columns, and diagonals for three linked points
    for i in range(9):
        for j in range(9):
            if board[i, j] != '.':
                symbol = board[i, j]
                # Check horizontally
                if j + 2 < 9 and board[i, j + 1] == board[i, j + 2] == symbol:
                    return symbol
                # Check vertically
                if i + 2 < 9 and board[i + 1, j] == board[i + 2, j] == symbol:
                    return symbol
                # Check diagonally (top-left to bottom-right)
                if i + 2 < 9 and j + 2 < 9 and board[i + 1, j + 1] == board[i + 2, j + 2] == symbol:
                    return symbol
                # Check diagonally (top-right to bottom-left)
                if i + 2 < 9 and j - 2 >= 0 and board[i + 1, j - 1] == board[i + 2, j - 2] == symbol:
                    return symbol
    return None

def computer_player():
    moves = check_available_moves(extra=True)
    if moves:
        # Use p1 to choose the action
        positions = check_available_moves(extra=True)
        p1_action = p1.chooseAction(positions, st.session_state.board, -1)
        
        # Check if the chosen action is valid and make the move
        if p1_action in moves:
            i, j = p1_action
            handle_click(i, j)

def main():
    st.write(
        """
        # ❎🅾️ Tic Tac Toe (9x9)
        """
    )

    if "board" not in st.session_state:
        init()

    reset, score, player = st.columns([0.5, 0.6, 1])
    reset.button('New game', on_click=init, args=(True,))

    for i, row in enumerate(st.session_state.board):
        cols = st.columns([5] + [1] * 9 + [5])
        for j, field in enumerate(row):
            if st.session_state.player == 'X' and not st.session_state.winner:
                # Only allow human player to make a move if it's their turn and the game is not over
                cols[j + 1].button(
                    field,
                    key=f"{i}-{j}",
                    on_click=lambda i=i, j=j: handle_click(i, j)  # Use lambda to pass arguments
                )
            else:
                # If it's not the human player's turn or the game is over, let the bot play
                computer_player()

    if st.session_state.winner:
        st.success(f"Congrats! {st.session_state.winner} won the game! 🎈")
    elif not check_available_moves():
        st.info(f"It's a tie 📍")

    score.button(f'❌{st.session_state.win["X"]} 🆚 {st.session_state.win["O"]}⭕')
    player.button(
        f'{"❌" if st.session_state.player == "X" else "⭕"}\'s turn'
        if not st.session_state.winner
        else f'🏁 Game finished'
    )

if __name__ == '__main__':
    main()