trttung1610 commited on
Commit
6ac8ae0
β€’
1 Parent(s): 849fda6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +152 -0
app.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import numpy as np
3
+ from objects import Player, HumanPlayer, State
4
+ import random
5
+ # Create RL bot players
6
+ p1 = Player("p1")
7
+ p2 = HumanPlayer("p2")
8
+
9
+ # Initialize the selected opponent in Session State
10
+ if "selected_opponent" not in st.session_state:
11
+ st.session_state.selected_opponent = 'Computer'
12
+
13
+ def handle_click(i, j):
14
+ if (i, j) not in check_available_moves(extra=True):
15
+ st.session_state.warning = True
16
+ elif not st.session_state.winner:
17
+ st.session_state.warning = False
18
+ st.session_state.board[i, j] = st.session_state.player
19
+ st.session_state.player = "O" if st.session_state.player == "X" else "X"
20
+ winner = check_win(st.session_state.board)
21
+ if winner != ".":
22
+ st.session_state.winner = winner
23
+ if st.session_state.opponent == 'Computer':
24
+ # Give reward to the RL bot and update its policy
25
+ if winner == 'X':
26
+ p1.feedReward(1)
27
+ elif winner == 'O':
28
+ p1.feedReward(0)
29
+ else:
30
+ p1.feedReward(0.1)
31
+
32
+ # Save the RL bot's policy
33
+ p1.savePolicy()
34
+
35
+
36
+ def init(post_init=False):
37
+ if not post_init:
38
+ st.session_state.opponent = 'Human'
39
+ st.session_state.win = {'X': 0, 'O': 0}
40
+ st.session_state.board = np.full((3, 3), '.', dtype=str)
41
+ st.session_state.player = 'X'
42
+ st.session_state.warning = False
43
+ st.session_state.winner = None
44
+ st.session_state.over = False
45
+
46
+ def check_available_moves(extra=False) -> list:
47
+ raw_moves = [row for col in st.session_state.board.tolist() for row in col]
48
+ num_moves = [i for i, spot in enumerate(raw_moves) if spot == '.']
49
+ if extra:
50
+ return [(i // 3, i % 3) for i in num_moves]
51
+ return num_moves
52
+
53
+ def check_rows(board):
54
+ for row in board:
55
+ if len(set(row)) == 1:
56
+ return row[0]
57
+ return None
58
+
59
+ def check_diagonals(board):
60
+ if len(set([board[i][i] for i in range(len(board))])) == 1:
61
+ return board[0][0]
62
+ if len(set([board[i][len(board) - i - 1] for i in range(len(board))])) == 1:
63
+ return board[0][len(board) - 1]
64
+ return None
65
+
66
+ def check_state():
67
+ if st.session_state.winner:
68
+ st.success(f"Congrats! {st.session_state.winner} won the game! 🎈")
69
+ if st.session_state.warning and not st.session_state.over:
70
+ st.warning('⚠️ This move already exists')
71
+ if st.session_state.winner and not st.session_state.over:
72
+ st.session_state.over = True
73
+ st.session_state.win[st.session_state.winner] = (
74
+ st.session_state.win.get(st.session_state.winner, 0) + 1
75
+ )
76
+ elif not check_available_moves() and not st.session_state.winner:
77
+ st.info(f"It's a tie πŸ“")
78
+ st.session_state.over = True
79
+
80
+ def check_win(board):
81
+ for new_board in [board, np.transpose(board)]:
82
+ result = check_rows(new_board)
83
+ if result:
84
+ return result
85
+ return check_diagonals(board)
86
+
87
+
88
+ def computer_player():
89
+ moves = check_available_moves(extra=True)
90
+ if moves:
91
+ # Use p1 to choose the action
92
+ positions = check_available_moves(extra=True)
93
+ p1_action = p1.chooseAction(positions, st.session_state.board, -1)
94
+
95
+ # Check if the chosen action is valid and make the move
96
+ if p1_action in moves:
97
+ i, j = p1_action
98
+ handle_click(i, j)
99
+
100
+
101
+ def on_opponent_selected():
102
+ st.session_state.selected_opponent = st.session_state.opponent
103
+ init(True)
104
+
105
+
106
+ def main():
107
+ st.write(
108
+ """
109
+ # βŽπŸ…ΎοΈ Tic Tac Toe
110
+ """
111
+ )
112
+
113
+ if "board" not in st.session_state:
114
+ init()
115
+
116
+ reset, score, player, settings = st.columns([0.5, 0.6, 1, 1])
117
+ reset.button('New game', on_click=init, args=(True,))
118
+
119
+ # Dynamically set the Expander label based on the selected opponent
120
+ with settings.expander(f'Opponent ({st.session_state.selected_opponent})'):
121
+ st.write('**Warning**: changing this setting will restart your game')
122
+ st.selectbox(
123
+ 'Set opponent',
124
+ ['Computer','Human'],
125
+ key='opponent',
126
+ on_change=on_opponent_selected,
127
+ )
128
+
129
+ for i, row in enumerate(st.session_state.board):
130
+ cols = st.columns([5, 1, 1, 1, 5])
131
+ for j, field in enumerate(row):
132
+ cols[j + 1].button(
133
+ field,
134
+ key=f"{i}-{j}",
135
+ on_click=handle_click
136
+ if st.session_state.player == 'X'
137
+ or st.session_state.opponent == 'Human'
138
+ else computer_player(),
139
+ args=(i, j),
140
+ )
141
+
142
+ check_state()
143
+
144
+ score.button(f'❌{st.session_state.win["X"]} πŸ†š {st.session_state.win["O"]}β­•')
145
+ player.button(
146
+ f'{"❌" if st.session_state.player == "X" else "β­•"}\'s turn'
147
+ if not st.session_state.winner
148
+ else f'🏁 Game finished'
149
+ )
150
+
151
+ if __name__ == '__main__':
152
+ main()