amanmoon commited on
Commit
afab5da
·
verified ·
1 Parent(s): 28a6716

Upload 52 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Alpha_MCTS.py +120 -0
  2. Alpha_MCTS_Parallel.py +128 -0
  3. Alpha_Zero.py +143 -0
  4. Games/2048/2048.py +41 -0
  5. Games/2048/2048NN.py +0 -0
  6. Games/Chess/Chess.py +41 -0
  7. Games/Chess/ChessNN.py +63 -0
  8. Games/Chess/Stokfish.py +1 -0
  9. Games/ConnectFour/ConnectFour.py +76 -0
  10. Games/ConnectFour/ConnectFourNN.py +61 -0
  11. Games/ConnectFour/__pycache__/ConnectFour.cpython-310.pyc +0 -0
  12. Games/ConnectFour/__pycache__/ConnectFour.cpython-311.pyc +0 -0
  13. Games/ConnectFour/__pycache__/ConnectFour.cpython-312.pyc +0 -0
  14. Games/ConnectFour/__pycache__/ConnectFour.cpython-313.pyc +0 -0
  15. Games/ConnectFour/__pycache__/ConnectFourNN.cpython-310.pyc +0 -0
  16. Games/ConnectFour/__pycache__/ConnectFourNN.cpython-311.pyc +0 -0
  17. Games/ConnectFour/__pycache__/ConnectFourNN.cpython-312.pyc +0 -0
  18. Games/ConnectFour/__pycache__/ConnectFourNN.cpython-313.pyc +0 -0
  19. Games/ConnectFour/models_n_optimizers/model.pt +3 -0
  20. Games/ConnectFour/models_n_optimizers/optimizer.pt +3 -0
  21. Games/TicTacToe/TicTacToe.py +59 -0
  22. Games/TicTacToe/TicTacToeNN.py +61 -0
  23. Games/TicTacToe/__pycache__/TicTacToe.cpython-310.pyc +0 -0
  24. Games/TicTacToe/__pycache__/TicTacToe.cpython-311.pyc +0 -0
  25. Games/TicTacToe/__pycache__/TicTacToe.cpython-313.pyc +0 -0
  26. Games/TicTacToe/__pycache__/TicTacToeNN.cpython-310.pyc +0 -0
  27. Games/TicTacToe/__pycache__/TicTacToeNN.cpython-311.pyc +0 -0
  28. Games/TicTacToe/__pycache__/TicTacToeNN.cpython-313.pyc +0 -0
  29. Games/TicTacToe/models_n_optimizers/model.pt +3 -0
  30. Games/TicTacToe/models_n_optimizers/model_non_parallel.pt +3 -0
  31. Games/TicTacToe/models_n_optimizers/optimizer.pt +3 -0
  32. Games/TicTacToe/models_n_optimizers/optimizer_non_parallel.pt +3 -0
  33. Games/game.py +41 -0
  34. MCTS.py +104 -0
  35. Play.py +86 -0
  36. Train.py +50 -0
  37. __pycache__/Alpha_MCTS.cpython-310.pyc +0 -0
  38. __pycache__/Alpha_MCTS.cpython-311.pyc +0 -0
  39. __pycache__/Alpha_MCTS.cpython-313.pyc +0 -0
  40. __pycache__/Alpha_MCTS_Parallel.cpython-310.pyc +0 -0
  41. __pycache__/Alpha_MCTS_Parallel.cpython-311.pyc +0 -0
  42. __pycache__/Alpha_MCTS_Parallel.cpython-313.pyc +0 -0
  43. __pycache__/Alpha_Zero.cpython-310.pyc +0 -0
  44. __pycache__/Alpha_Zero.cpython-311.pyc +0 -0
  45. __pycache__/Alpha_Zero.cpython-313.pyc +0 -0
  46. __pycache__/Alpha_Zero_Parallel.cpython-310.pyc +0 -0
  47. __pycache__/Alpha_Zero_Parallel.cpython-311.pyc +0 -0
  48. __pycache__/Alpha_Zero_Parallel.cpython-313.pyc +0 -0
  49. __pycache__/Arena.cpython-313.pyc +0 -0
  50. requirements.txt +64 -0
Alpha_MCTS.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import numpy as np
4
+
5
+ class Node:
6
+
7
+ def __init__(self, game, args, state, parent = None, action = None, prob = 0, visits = 0):
8
+ self.game = game
9
+ self.args = args
10
+ self.state = state
11
+ self.parent = parent
12
+ self.action = action
13
+ self.prob = prob
14
+
15
+ self.children = []
16
+ self.visits = visits
17
+ self.value = 0
18
+
19
+ def leaf_or_not(self):
20
+ return len(self.children) > 0
21
+
22
+ def search(self):
23
+ best_child = None
24
+ best_ucb = -np.inf
25
+ for child in self.children:
26
+ ucb = self.get_ucb(child)
27
+ if best_ucb < ucb:
28
+ best_ucb = ucb
29
+ best_child = child
30
+ return best_child
31
+
32
+ def get_ucb(self, child):
33
+ if child.visits == 0:
34
+ q_value = 0
35
+ else:
36
+ q_value = 1 - (((child.value / child.visits) + 1) / 2)
37
+
38
+ return q_value + self.args['EXPLORATION_CONSTANT'] * (math.sqrt(self.visits) / (child.visits + 1)) * child.prob
39
+
40
+ def expand(self, policy):
41
+
42
+ for move, prob in enumerate(policy):
43
+ if prob > 0:
44
+ child = self.state.copy()
45
+ child = self.game.make_move(child, move, 1)
46
+ if self.args["ADVERSARIAL"]:
47
+ child = self.game.change_perspective(child, player = -1)
48
+
49
+ child = Node(self.game, self.args, child, self, move, prob)
50
+ self.children.append(child)
51
+
52
+ def backpropagate(self,state_value):
53
+ self.value += state_value
54
+ self.visits += 1
55
+ if self.args["ADVERSARIAL"]:
56
+ state_value = self.game.get_opponent_value(state_value)
57
+ if self.parent is not None:
58
+ self.parent.backpropagate(state_value)
59
+
60
+
61
+ class Alpha_MCTS:
62
+
63
+ def __init__(self, game, args, model):
64
+ self.game = game
65
+ self.args = args
66
+ self.model = model
67
+
68
+ @torch.no_grad()
69
+ def search(self, state):
70
+ root = Node(self.game, self.args, state, visits = 1)
71
+
72
+ if self.args["ROOT_RANDOMNESS"]:
73
+ policy, _ = self.model(
74
+ torch.tensor(self.game.get_encoded_state(state), device = self.model.device
75
+ ).unsqueeze(0))
76
+
77
+ policy = torch.softmax(policy, axis = 1).squeeze(0).cpu().numpy()
78
+
79
+ policy = (1 - self.args["DIRICHLET_EPSILON"]) * policy + self.args["DIRICHLET_EPSILON"] * np.random.dirichlet([self.args["DIRICHLET_ALPHA"]] * self.game.possible_state)
80
+
81
+ valid_state = self.game.get_valid_moves(state)
82
+ policy *= valid_state
83
+ policy /= np.sum(policy)
84
+ root.expand(policy)
85
+
86
+ for _ in range(self.args["NO_OF_SEARCHES"]):
87
+ node = root
88
+ no_moves = 0
89
+ while node.leaf_or_not():
90
+ node = node.search()
91
+ no_moves += 1
92
+
93
+ is_terminal, value = self.game.know_terminal_value(node.state, node.action)
94
+
95
+ if self.args["ADVERSARIAL"]:
96
+ value = self.game.get_opponent_value(value)
97
+
98
+ if not is_terminal:
99
+
100
+ policy, value = self.model(
101
+ torch.tensor(self.game.get_encoded_state(node.state), device = self.model.device).unsqueeze(0)
102
+ )
103
+
104
+ valid_state = self.game.get_valid_moves(node.state)
105
+ policy = torch.softmax(policy, axis = 1).squeeze(0).cpu().numpy().astype(np.float64)
106
+
107
+ policy *= valid_state
108
+ policy /= np.sum(policy)
109
+
110
+ value = value.item()
111
+
112
+ node.expand(policy)
113
+
114
+ node.backpropagate(value)
115
+
116
+ move_probability = np.zeros(self.game.possible_state)
117
+ for children in root.children:
118
+ move_probability[children.action] = children.visits
119
+ move_probability /= np.sum(move_probability)
120
+ return move_probability
Alpha_MCTS_Parallel.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import numpy as np
4
+
5
+ class Node:
6
+
7
+ def __init__(self, game, args, state, parent = None, action = None, prob = 0, visits = 0):
8
+ self.game = game
9
+ self.args = args
10
+ self.state = state
11
+ self.parent = parent
12
+ self.action = action
13
+ self.prob = prob
14
+
15
+ self.children = []
16
+ self.visits = visits
17
+ self.value = 0
18
+
19
+ def leaf_or_not(self):
20
+ return len(self.children) > 0
21
+
22
+ def search(self):
23
+ best_child = None
24
+ best_ucb = -np.inf
25
+ for child in self.children:
26
+ ucb = self.get_ucb(child)
27
+ if best_ucb < ucb:
28
+ best_ucb = ucb
29
+ best_child = child
30
+ return best_child
31
+
32
+ def get_ucb(self, child):
33
+ if child.visits == 0:
34
+ q_value = 0
35
+ else:
36
+ q_value = 1 - ((child.value / child.visits) + 1) / 2
37
+
38
+ return q_value + self.args['EXPLORATION_CONSTANT'] * (math.sqrt(self.visits) / (child.visits + 1)) * child.prob
39
+
40
+ def expand(self, policy):
41
+
42
+ for move, prob in enumerate(policy):
43
+ if prob > 0:
44
+ child = self.state.copy()
45
+ child = self.game.make_move(child, move, 1)
46
+ if self.args["ADVERSARIAL"]:
47
+ child = self.game.change_perspective(child, player = -1)
48
+
49
+ child = Node(self.game, self.args, child, self, move, prob)
50
+ self.children.append(child)
51
+
52
+ def backpropagate(self,state_value):
53
+ self.value += state_value
54
+ self.visits += 1
55
+ if self.args["ADVERSARIAL"]:
56
+ state_value = self.game.get_opponent_value(state_value)
57
+ if self.parent is not None:
58
+ self.parent.backpropagate(state_value)
59
+
60
+
61
+ class Alpha_MCTS:
62
+
63
+ def __init__(self, game, args, model):
64
+ self.game = game
65
+ self.args = args
66
+ self.model = model
67
+
68
+ @torch.no_grad()
69
+ def search(self, states, spGames):
70
+
71
+ policy, _ = self.model(
72
+ torch.tensor(self.game.get_encoded_state(states), device = self.model.device
73
+ ))
74
+
75
+ policy = torch.softmax(policy, axis = 1).cpu().numpy()
76
+
77
+ if self.args["ROOT_RANDOMNESS"]:
78
+ policy = (1 - self.args["DIRICHLET_EPSILON"]) * policy + self.args["DIRICHLET_EPSILON"] * np.random.dirichlet([self.args["DIRICHLET_ALPHA"]] * self.game.possible_state, size = policy.shape[0])
79
+
80
+ for i, spg in enumerate(spGames):
81
+ spg_policy = policy[i]
82
+ valid_state = self.game.get_valid_moves(states[i])
83
+ spg_policy *= valid_state
84
+ spg_policy /= np.sum(spg_policy)
85
+
86
+ spg.root = Node(self.game, self.args, states[i], visits = 1)
87
+ spg.root.expand(spg_policy)
88
+
89
+ for _ in range(self.args["NO_OF_SEARCHES"]):
90
+
91
+ for spg in spGames:
92
+ spg.node = None
93
+ node = spg.root
94
+
95
+ while node.leaf_or_not():
96
+ node = node.search()
97
+
98
+ is_terminal, value = self.game.know_terminal_value(node.state, node.action)
99
+
100
+ if self.args["ADVERSARIAL"]:
101
+ value = self.game.get_opponent_value(value)
102
+
103
+ if is_terminal:
104
+ node.backpropagate(value)
105
+ else:
106
+ spg.node = node
107
+
108
+ expandabel_spgs = [mapping_index for mapping_index in range(len(spGames)) if spGames[mapping_index].node is not None]
109
+
110
+ if len(expandabel_spgs) > 0:
111
+ states = np.stack([spGames[mapping_index].node.state for mapping_index in expandabel_spgs])
112
+ policy, value = self.model(
113
+ torch.tensor(self.game.get_encoded_state(states), device = self.model.device)
114
+ )
115
+
116
+ policy = torch.softmax(policy, axis = 1).cpu().numpy().astype(np.float64)
117
+ value = value.cpu().numpy()
118
+
119
+ for i, mapping_index in enumerate(expandabel_spgs):
120
+ node = spGames[mapping_index].node
121
+ spg_policy, spg_value = policy[i], value[i]
122
+ valid_state = self.game.get_valid_moves(node.state)
123
+
124
+ spg_policy *= valid_state
125
+ spg_policy /= np.sum(spg_policy)
126
+
127
+ node.expand(spg_policy)
128
+ node.backpropagate(spg_value)
Alpha_Zero.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ import copy
4
+ import numpy as np
5
+
6
+ import torch
7
+ import torch.nn.functional as F
8
+
9
+ from tqdm import trange
10
+ from Alpha_MCTS import Alpha_MCTS
11
+ from Arena import Arena
12
+
13
+ class Colors:
14
+ RESET = "\033[0m"
15
+ RED = "\033[91m"
16
+ GREEN = "\033[92m"
17
+ YELLOW = "\033[93m"
18
+ BLUE = "\033[94m"
19
+ MAGENTA = "\033[95m"
20
+ CYAN = "\033[96m"
21
+ WHITE = "\033[97m"
22
+
23
+
24
+ class Alpha_Zero:
25
+
26
+ def __init__(self, game, args, model, optimizer):
27
+ self.game = game
28
+ self.args = args
29
+ self.model = model
30
+ self.optimizer = optimizer
31
+ self.mcts = Alpha_MCTS(game, args, model)
32
+
33
+ def self_play(self):
34
+
35
+ single_game_memory = []
36
+ player = 1
37
+ state = self.game.initialise_state()
38
+
39
+ while True:
40
+ neutral_state = self.game.change_perspective(state, player) if self.args["ADVERSARIAL"] else state
41
+ prob = self.mcts.search(neutral_state)
42
+
43
+ single_game_memory.append((neutral_state, prob, player))
44
+
45
+ temp_prob = prob ** (1 / self.args["TEMPERATURE"])
46
+
47
+ temp_prob[temp_prob == 0] = - np.inf
48
+
49
+ temp_prob = torch.softmax(torch.tensor(temp_prob), axis = 0).cpu().numpy()
50
+
51
+ move = np.random.choice(self.game.possible_state, p = temp_prob)
52
+
53
+ state = self.game.make_move(state, move, player)
54
+ is_terminal, value = self.game.know_terminal_value(state, move)
55
+
56
+ if is_terminal:
57
+ return_memory = []
58
+ for return_state, return_action_prob, return_player in single_game_memory:
59
+ if self.args["ADVERSARIAL"]:
60
+ return_value = value if return_player == player else self.game.get_opponent_value(value)
61
+ else:
62
+ return_value = value
63
+
64
+ return_memory.append((
65
+ self.game.get_encoded_state(return_state),
66
+ return_action_prob,
67
+ return_value
68
+ ))
69
+ return return_memory
70
+
71
+ if self.args["ADVERSARIAL"]:
72
+ player = self.game.get_opponent(player)
73
+
74
+ def train(self, memory):
75
+
76
+ random.shuffle(memory)
77
+
78
+ for batch_start in range(0, len(memory), self.args["BATCH_SIZE"]):
79
+ batch_end = batch_start + self.args["BATCH_SIZE"]
80
+
81
+ training_memory = memory[batch_start : batch_end]
82
+
83
+ state, action_prob, value = zip(*training_memory)
84
+
85
+ state, action_prob, value = np.array(state), np.array(action_prob), np.array(value).reshape(-1, 1)
86
+
87
+ state = torch.tensor(state, device = self.model.device, dtype=torch.float32)
88
+ policy_targets = torch.tensor(action_prob, device = self.model.device, dtype=torch.float32)
89
+ value_targets = torch.tensor(value, device = self.model.device, dtype=torch.float32)
90
+
91
+ out_policy, out_value = self.model(state)
92
+
93
+ policy_loss = F.cross_entropy(out_policy, policy_targets)
94
+ value_loss = F.mse_loss(out_value, value_targets)
95
+ loss = policy_loss + value_loss
96
+
97
+ self.optimizer.zero_grad()
98
+ loss.backward()
99
+ self.optimizer.step()
100
+
101
+ def learn(self):
102
+ try:
103
+ model_path = os.path.join(self.args["MODEL_PATH"], 'model.pt')
104
+ optimizer_path = os.path.join(self.args["MODEL_PATH"], 'optimizer.pt')
105
+
106
+ self.model.load_state_dict(torch.load(model_path))
107
+ self.optimizer.load_state_dict(torch.load(optimizer_path))
108
+ except:
109
+ print(Colors.RED + "UNABLE TO LOAD MODEL")
110
+ print(Colors.GREEN + "SETTING UP NEW MODEL..." + Colors.RESET)
111
+
112
+ else:
113
+ print(Colors.GREEN + "MODEL FOUND\nLOADING MODEL..." + Colors.RESET)
114
+ finally:
115
+
116
+ initial_model = copy.copy(self.model)
117
+
118
+ for iteration in range(self.args["NO_ITERATIONS"]):
119
+ memory = []
120
+
121
+ print(Colors.BLUE + "\nIteration no: " , iteration + 1, Colors.RESET)
122
+
123
+ print(Colors.YELLOW + "Self Play" + Colors.RESET)
124
+ self.model.eval()
125
+
126
+ for _ in trange(self.args["SELF_PLAY_ITERATIONS"]):
127
+ memory += self.self_play()
128
+
129
+ print(Colors.YELLOW + "Training..." + Colors.RESET)
130
+ self.model.train()
131
+ for _ in trange(self.args["EPOCHS"]):
132
+ self.train(memory)
133
+
134
+ print(Colors.YELLOW + "Testing..." + Colors.RESET)
135
+ self.model.eval()
136
+ wins, draws, defeats = Arena(self.game, self.args, self.model, initial_model)
137
+ print(Colors.GREEN + "Testing Completed" + Colors.WHITE + "\nTrained Model Stats:")
138
+ print(Colors.GREEN, "Wins: ", wins, Colors.RESET, "|", Colors.RED, "Loss: ", defeats, Colors.RESET, "|", Colors.WHITE," Draw: ", draws, Colors.RESET)
139
+
140
+ print(Colors.YELLOW + "Saving Model...")
141
+ torch.save(self.model.state_dict(), os.path.join(self.args["MODEL_PATH"], "model_non_parallel.pt"))
142
+ torch.save(self.optimizer.state_dict(), os.path.join(self.args["MODEL_PATH"], "optimizer_non_parallel.pt"))
143
+ print("Saved!" + Colors.RESET)
Games/2048/2048.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """NOTE : THIS IS THE FORMAT YOU SHOULD FOLLOW TO MAKE GAMES"""
2
+
3
+ class GAME:
4
+ def __init__(self):
5
+ self.row = 4
6
+ self.col = 4
7
+ self.possible_state = self.row * self.col # no of possible state game can have (no of possible moves)
8
+
9
+ def initialise_state(self):
10
+ """NOTE: this fuction creates starting position for your game"""
11
+
12
+ def get_valid_moves(self, state):
13
+ """ NOTE: inputs state and output all possible valid moves"""
14
+
15
+ def know_terminal_value(self, state, action):
16
+ """NOTE: input state and action and the output will be tuple True
17
+ if is terminal state and False if not and value 0 is
18
+ player lost and 1 if the player won the game"""
19
+
20
+ def make_move(self, state, action, player):
21
+ """NOTE: input a action and a state and a player, the
22
+ action is taken on given state and output is the final state"""
23
+
24
+ def get_encoded_state(self, state):
25
+ """input a state the output should be the encoded state that will be
26
+ given to the neural network"""
27
+
28
+ def get_opponent(self, player):
29
+ """NOTE: taking the input of current player this should change the
30
+ player to the opponent"""
31
+ return -1 * player
32
+
33
+ def get_opponent_value(self, value):
34
+ """this should switch the reward obtained from the know_terminal_state()
35
+ to the reward of the opponent"""
36
+ return -1 * value
37
+
38
+ def change_perspective(self, state, player = -1):
39
+ """this function taking input state and player flip the board and return
40
+ the game with the perspective of the opponent"""
41
+ return player * state
Games/2048/2048NN.py ADDED
File without changes
Games/Chess/Chess.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """NOTE : THIS IS THE FORMAT YOU SHOULD FOLLOW TO MAKE GAMES"""
2
+
3
+ class GAME:
4
+ def __init__(self):
5
+ self.row = 8
6
+ self.col = 8
7
+ self.possible_state = self.row * self.col
8
+
9
+ def initialise_state(self):
10
+ """NOTE: this fuction creates starting position for your game"""
11
+
12
+ def get_valid_moves(self, state):
13
+ """ NOTE: inputs state and output all possible valid moves"""
14
+
15
+ def know_terminal_value(self, state, action):
16
+ """NOTE: input state and action and the output will be tuple True
17
+ if is terminal state and False if not and value 0 is
18
+ player lost and 1 if the player won the game"""
19
+
20
+ def make_move(self, state, action, player):
21
+ """NOTE: input a action and a state and a player, the
22
+ action is taken on given state and output is the final state"""
23
+
24
+ def get_encoded_state(self, state):
25
+ """input a state the output should be the encoded state that will be
26
+ given to the neural network"""
27
+
28
+ def get_opponent(self, player):
29
+ """NOTE: taking the input of current player this should change the
30
+ player to the opponent"""
31
+ return -1 * player
32
+
33
+ def get_opponent_value(self, value):
34
+ """this should switch the reward obtained from the know_terminal_state()
35
+ to the reward of the opponent"""
36
+ return -1 * value
37
+
38
+ def change_perspective(self, state, player = -1):
39
+ """this function taking input state and player flip the board and return
40
+ the game with the perspective of the opponent"""
41
+ return player * state
Games/Chess/ChessNN.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+ import torch.nn.functional as F
3
+
4
+ class ResNet(nn.Module):
5
+ def __init__(self, game, num_resBlocks, num_hidden, device):
6
+ super().__init__()
7
+ self.device = device
8
+ self.startBlock = nn.Sequential(
9
+ nn.Conv2d(3, num_hidden, kernel_size=3, padding=1),
10
+ nn.BatchNorm2d(num_hidden),
11
+ nn.ReLU(),
12
+ nn.Conv2d(3, num_hidden, kernel_size=3, padding=1),
13
+ nn.BatchNorm2d(num_hidden),
14
+ nn.ReLU()
15
+ )
16
+
17
+ self.backBone = nn.ModuleList(
18
+ [ResBlock(num_hidden) for i in range(num_resBlocks)]
19
+ )
20
+
21
+ self.policyHead = nn.Sequential(
22
+ nn.Conv2d(num_hidden, 128, kernel_size=3, padding=1),
23
+ nn.BatchNorm2d(128),
24
+ nn.ReLU(),
25
+ nn.Flatten(),
26
+ nn.Linear(128 * game.row * game.col, game.possible_state)
27
+ )
28
+
29
+ self.valueHead = nn.Sequential(
30
+ nn.Conv2d(num_hidden, 3, kernel_size=3, padding=1),
31
+ nn.BatchNorm2d(3),
32
+ nn.ReLU(),
33
+ nn.Flatten(),
34
+ nn.Linear(3 * game.row * game.col, 1),
35
+ nn.Tanh()
36
+ )
37
+
38
+ self.to(device)
39
+
40
+ def forward(self, x):
41
+ x = self.startBlock(x)
42
+ for resBlock in self.backBone:
43
+ x = resBlock(x)
44
+ policy = self.policyHead(x)
45
+ value = self.valueHead(x)
46
+ return policy, value
47
+
48
+
49
+ class ResBlock(nn.Module):
50
+ def __init__(self, num_hidden):
51
+ super().__init__()
52
+ self.conv1 = nn.Conv2d(num_hidden, num_hidden, kernel_size=3, padding=1)
53
+ self.bn1 = nn.BatchNorm2d(num_hidden)
54
+ self.conv2 = nn.Conv2d(num_hidden, num_hidden, kernel_size=3, padding=1)
55
+ self.bn2 = nn.BatchNorm2d(num_hidden)
56
+
57
+ def forward(self, x):
58
+ residual = x
59
+ x = F.relu(self.bn1(self.conv1(x)))
60
+ x = self.bn2(self.conv2(x))
61
+ x += residual
62
+ x = F.relu(x)
63
+ return x
Games/Chess/Stokfish.py ADDED
@@ -0,0 +1 @@
 
 
1
+ import Stokfish
Games/ConnectFour/ConnectFour.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ class ConnectFour:
4
+ def __init__(self):
5
+ self.row = 6
6
+ self.col = 7
7
+ self.possible_state = self.col
8
+ self.in_a_row = 4
9
+
10
+ def __repr__(self):
11
+ return "ConnectFour"
12
+
13
+ def initialise_state(self):
14
+ return np.zeros((self.row, self.col))
15
+
16
+ def make_move(self, state, action, player):
17
+ row = np.max(np.where(state[:, action] == 0))
18
+ state[row, action] = player
19
+ return state
20
+
21
+ def get_valid_moves(self, state):
22
+ return (state[0] == 0).astype(np.uint8)
23
+
24
+ def check_win(self, state, action):
25
+ if action == None:
26
+ return False
27
+
28
+ row = np.min(np.where(state[:, action] != 0))
29
+ column = action
30
+ player = state[row][column]
31
+
32
+ def count(offset_row, offset_column):
33
+ for i in range(1, self.in_a_row):
34
+ r = row + offset_row * i
35
+ c = action + offset_column * i
36
+ if (
37
+ r < 0
38
+ or r >= self.row
39
+ or c < 0
40
+ or c >= self.col
41
+ or state[r][c] != player
42
+ ):
43
+ return i - 1
44
+ return self.in_a_row - 1
45
+
46
+ return (
47
+ count(1, 0) >= self.in_a_row - 1 # vertical
48
+ or (count(0, 1) + count(0, -1)) >= self.in_a_row - 1 # horizontal
49
+ or (count(1, 1) + count(-1, -1)) >= self.in_a_row - 1 # top left diagonal
50
+ or (count(1, -1) + count(-1, 1)) >= self.in_a_row - 1 # top right diagonal
51
+ )
52
+
53
+ def know_terminal_value(self, state, action):
54
+ if self.check_win(state, action):
55
+ return True, 1
56
+ if np.sum(self.get_valid_moves(state)) == 0:
57
+ return True, 0
58
+ return False, 0
59
+
60
+ def get_opponent(self, player):
61
+ return -player
62
+
63
+ def get_opponent_value(self, value):
64
+ return -value
65
+
66
+ def change_perspective(self, state, player):
67
+ return state * player
68
+
69
+ def get_encoded_state(self, state):
70
+ encoded_state = np.stack(
71
+ (state == -1, state == 0, state == 1)
72
+ ).astype(np.float32)
73
+ if len(state.shape) == 3:
74
+ encoded_state = np.swapaxes(encoded_state, 0, 1)
75
+
76
+ return encoded_state
Games/ConnectFour/ConnectFourNN.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+ import torch.nn.functional as F
3
+
4
+
5
+ class ResNet(nn.Module):
6
+ def __init__(self, game, num_resBlocks, num_hidden, device):
7
+ super().__init__()
8
+ self.device = device
9
+ self.startBlock = nn.Sequential(
10
+ nn.Conv2d(3, num_hidden, kernel_size=3, padding=1),
11
+ nn.BatchNorm2d(num_hidden),
12
+ nn.ReLU()
13
+ )
14
+
15
+ self.backBone = nn.ModuleList(
16
+ [ResBlock(num_hidden) for i in range(num_resBlocks)]
17
+ )
18
+
19
+ self.policyHead = nn.Sequential(
20
+ nn.Conv2d(num_hidden, 32, kernel_size=3, padding=1),
21
+ nn.BatchNorm2d(32),
22
+ nn.ReLU(),
23
+ nn.Flatten(),
24
+ nn.Linear(32 * game.row * game.col, game.possible_state)
25
+ )
26
+
27
+ self.valueHead = nn.Sequential(
28
+ nn.Conv2d(num_hidden, 3, kernel_size=3, padding=1),
29
+ nn.BatchNorm2d(3),
30
+ nn.ReLU(),
31
+ nn.Flatten(),
32
+ nn.Linear(3 * game.row * game.col, 1),
33
+ nn.Tanh()
34
+ )
35
+
36
+ self.to(device)
37
+
38
+ def forward(self, x):
39
+ x = self.startBlock(x)
40
+ for resBlock in self.backBone:
41
+ x = resBlock(x)
42
+ policy = self.policyHead(x)
43
+ value = self.valueHead(x)
44
+ return policy, value
45
+
46
+
47
+ class ResBlock(nn.Module):
48
+ def __init__(self, num_hidden):
49
+ super().__init__()
50
+ self.conv1 = nn.Conv2d(num_hidden, num_hidden, kernel_size=3, padding=1)
51
+ self.bn1 = nn.BatchNorm2d(num_hidden)
52
+ self.conv2 = nn.Conv2d(num_hidden, num_hidden, kernel_size=3, padding=1)
53
+ self.bn2 = nn.BatchNorm2d(num_hidden)
54
+
55
+ def forward(self, x):
56
+ residual = x
57
+ x = F.relu(self.bn1(self.conv1(x)))
58
+ x = self.bn2(self.conv2(x))
59
+ x += residual
60
+ x = F.relu(x)
61
+ return x
Games/ConnectFour/__pycache__/ConnectFour.cpython-310.pyc ADDED
Binary file (2.98 kB). View file
 
Games/ConnectFour/__pycache__/ConnectFour.cpython-311.pyc ADDED
Binary file (4.8 kB). View file
 
Games/ConnectFour/__pycache__/ConnectFour.cpython-312.pyc ADDED
Binary file (4.48 kB). View file
 
Games/ConnectFour/__pycache__/ConnectFour.cpython-313.pyc ADDED
Binary file (4.59 kB). View file
 
Games/ConnectFour/__pycache__/ConnectFourNN.cpython-310.pyc ADDED
Binary file (2.08 kB). View file
 
Games/ConnectFour/__pycache__/ConnectFourNN.cpython-311.pyc ADDED
Binary file (4.38 kB). View file
 
Games/ConnectFour/__pycache__/ConnectFourNN.cpython-312.pyc ADDED
Binary file (3.88 kB). View file
 
Games/ConnectFour/__pycache__/ConnectFourNN.cpython-313.pyc ADDED
Binary file (4 kB). View file
 
Games/ConnectFour/models_n_optimizers/model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5ecbcdf83dc322c859ab3188f11e2f7b25ee504515a8bcf2b84798be7b1b3eb7
3
+ size 10920462
Games/ConnectFour/models_n_optimizers/optimizer.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c7165fd808da4ff2c3535392d8cf651ee905b0d0a15aadbef7e2e8300a7387fd
3
+ size 21792762
Games/TicTacToe/TicTacToe.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ class TicTacToe:
4
+
5
+ def __init__(self):
6
+ self.col = 3
7
+ self.row = 3
8
+ self.possible_state = self.col * self.row
9
+
10
+ def initialise_state(self):
11
+ return np.zeros((self.row, self.col))
12
+
13
+ def get_valid_moves(self, state):
14
+ return (state.reshape(-1) == 0).astype(np.uint8)
15
+
16
+ def know_terminal_value(self, state, action):
17
+
18
+ if action is None:
19
+ return False, 0
20
+
21
+ row=action//3
22
+ col=action%3
23
+ player = state[row,col]
24
+
25
+ if (sum(state[row,:])==player*3
26
+ or sum(state[:,col])==player*3
27
+ or np.trace(state)==player*3
28
+ or np.trace(np.fliplr(state))==player*3):
29
+ return True, 1
30
+
31
+ if 0 not in state.reshape(-1):
32
+ return True, 0
33
+ else:
34
+ return False,0
35
+
36
+ def make_move(self, state, action, player):
37
+ row=action//3
38
+ col=action%3
39
+
40
+ state[row,col]=player
41
+
42
+ return state
43
+
44
+ def get_encoded_state(self, state):
45
+ encoded_state = np.stack(
46
+ (state == -1, state == 0, state == 1)
47
+ ).astype(np.float32)
48
+ if len(state.shape) == 3:
49
+ encoded_state = np.swapaxes(encoded_state, 0, 1)
50
+
51
+ return encoded_state
52
+ def get_opponent(self, player):
53
+ return -1 * player
54
+
55
+ def get_opponent_value(self, value):
56
+ return -1 * value
57
+
58
+ def change_perspective(self, state, player = -1):
59
+ return (player * state).astype(np.float32)
Games/TicTacToe/TicTacToeNN.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+ import torch.nn.functional as F
3
+
4
+ class ResNet(nn.Module):
5
+
6
+ def __init__(self, game, num_resBlocks, num_hidden, device):
7
+ super().__init__()
8
+ self.device = device
9
+ self.startBlock = nn.Sequential(
10
+ nn.Conv2d(3, num_hidden, kernel_size=3, padding=1),
11
+ nn.BatchNorm2d(num_hidden),
12
+ nn.ReLU()
13
+ )
14
+
15
+ self.backBone = nn.ModuleList(
16
+ [ResBlock(num_hidden) for i in range(num_resBlocks)]
17
+ )
18
+
19
+ self.policyHead = nn.Sequential(
20
+ nn.Conv2d(num_hidden, 32, kernel_size=3, padding=1),
21
+ nn.BatchNorm2d(32),
22
+ nn.ReLU(),
23
+ nn.Flatten(),
24
+ nn.Linear(32 * game.row * game.col, game.possible_state)
25
+ )
26
+
27
+ self.valueHead = nn.Sequential(
28
+ nn.Conv2d(num_hidden, 3, kernel_size=3, padding=1),
29
+ nn.BatchNorm2d(3),
30
+ nn.ReLU(),
31
+ nn.Flatten(),
32
+ nn.Linear(3 * game.row * game.col, 1),
33
+ nn.Tanh()
34
+ )
35
+
36
+ self.to(device)
37
+
38
+ def forward(self, x):
39
+ x = self.startBlock(x)
40
+ for resBlock in self.backBone:
41
+ x = resBlock(x)
42
+ policy = self.policyHead(x)
43
+ value = self.valueHead(x)
44
+ return policy, value
45
+
46
+
47
+ class ResBlock(nn.Module):
48
+ def __init__(self, num_hidden):
49
+ super().__init__()
50
+ self.conv1 = nn.Conv2d(num_hidden, num_hidden, kernel_size=3, padding=1)
51
+ self.bn1 = nn.BatchNorm2d(num_hidden)
52
+ self.conv2 = nn.Conv2d(num_hidden, num_hidden, kernel_size=3, padding=1)
53
+ self.bn2 = nn.BatchNorm2d(num_hidden)
54
+
55
+ def forward(self, x):
56
+ residual = x
57
+ x = F.relu(self.bn1(self.conv1(x)))
58
+ x = self.bn2(self.conv2(x))
59
+ x += residual
60
+ x = F.relu(x)
61
+ return x
Games/TicTacToe/__pycache__/TicTacToe.cpython-310.pyc ADDED
Binary file (2.27 kB). View file
 
Games/TicTacToe/__pycache__/TicTacToe.cpython-311.pyc ADDED
Binary file (3.56 kB). View file
 
Games/TicTacToe/__pycache__/TicTacToe.cpython-313.pyc ADDED
Binary file (3.36 kB). View file
 
Games/TicTacToe/__pycache__/TicTacToeNN.cpython-310.pyc ADDED
Binary file (2.06 kB). View file
 
Games/TicTacToe/__pycache__/TicTacToeNN.cpython-311.pyc ADDED
Binary file (4.38 kB). View file
 
Games/TicTacToe/__pycache__/TicTacToeNN.cpython-313.pyc ADDED
Binary file (4 kB). View file
 
Games/TicTacToe/models_n_optimizers/model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5877c49bfb164d48c9ccf7d165d9e647c14ed6956cb047e6f40b6e7237e9af2d
3
+ size 10900420
Games/TicTacToe/models_n_optimizers/model_non_parallel.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f4cefe7c002f47fe17ee7b6304bdd6f32b44191bc00090604923300803062740
3
+ size 10903056
Games/TicTacToe/models_n_optimizers/optimizer.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:38db7c19396de4e717b28891427dcf3ff4efc1451c3a0cc7baff70b3cc5824c5
3
+ size 21738002
Games/TicTacToe/models_n_optimizers/optimizer_non_parallel.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0f346133359c24c36ae633ab24f2e4c47773d5e40506c5f2fb64a06f8c54c7fa
3
+ size 21741505
Games/game.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """NOTE : THIS IS THE FORMAT YOU SHOULD FOLLOW TO MAKE GAMES"""
2
+
3
+ class GAME:
4
+ def __init__(self):
5
+ self.row = None
6
+ self.col = None
7
+ self.possible_state = self.row * self.col # no of possible state game can have (no of possible moves)
8
+
9
+ def initialise_state(self):
10
+ """NOTE: this fuction creates starting position for your game"""
11
+
12
+ def get_valid_moves(self, state):
13
+ """ NOTE: inputs state and output all possible valid moves"""
14
+
15
+ def know_terminal_value(self, state, action):
16
+ """NOTE: input state and action and the output will be tuple True
17
+ if is terminal state and False if not and value 0 is
18
+ player lost and 1 if the player won the game"""
19
+
20
+ def make_move(self, state, action, player):
21
+ """NOTE: input a action and a state and a player, the
22
+ action is taken on given state and output is the final state"""
23
+
24
+ def get_encoded_state(self, state):
25
+ """input a state the output should be the encoded state that will be
26
+ given to the neural network"""
27
+
28
+ def get_opponent(self, player):
29
+ """NOTE: taking the input of current player this should change the
30
+ player to the opponent"""
31
+ return -1 * player
32
+
33
+ def get_opponent_value(self, value):
34
+ """this should switch the reward obtained from the know_terminal_state()
35
+ to the reward of the opponent"""
36
+ return -1 * value
37
+
38
+ def change_perspective(self, state, player = -1):
39
+ """this function taking input state and player flip the board and return
40
+ the game with the perspective of the opponent"""
41
+ return player * state
MCTS.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import numpy as np
3
+
4
+ class Node:
5
+
6
+ def __init__(self, game, args, state, parent = None, action = None):
7
+ self.game = game
8
+ self.args = args
9
+ self.state = state
10
+ self.parent = parent
11
+ self.action = action
12
+
13
+ self.children = list()
14
+ self.expandable_moves = self.game.get_moves(self.state)
15
+ self.visits = 0
16
+ self.total_value = 0
17
+
18
+ def leaf_or_not(self):
19
+ return (len(self.children) > 0 and len(self.expandable_moves) == 0)
20
+
21
+ def search(self):
22
+ best_child = None
23
+ best_ucb = -np.inf
24
+ for child in self.children:
25
+ ucb = self.get_ucb(child)
26
+ if best_ucb < ucb:
27
+ best_ucb = ucb
28
+ best_child = child
29
+
30
+ return best_child
31
+
32
+ def get_ucb(self, child):
33
+ q_value = 1 - ((child.total_value / child.visits) + 1) / 2
34
+ return q_value + self.args["EXPLORATION_CONSTANT"] * math.sqrt(math.log(self.visits) / child.visits)
35
+
36
+ def expand(self):
37
+ rand_move = np.random.choice(self.expandable_moves)
38
+ self.expandable_moves.remove(rand_move)
39
+
40
+ child = self.game.make_move(self.state.copy(), rand_move, 1)
41
+ child = self.game.change_perspective(child)
42
+ child = Node(self.game, self.args, child, self, rand_move)
43
+
44
+ self.children.append(child)
45
+
46
+ return child
47
+
48
+ def simulate(self):
49
+ is_terminal, value = self.game.know_terminal_value(self.state, self.action)
50
+ value = self.game.get_opponent_value(value)
51
+
52
+ if is_terminal:
53
+ return value
54
+
55
+ state = self.state.copy()
56
+ player = 1
57
+ while True:
58
+ possible_moves = self.game.get_moves(state)
59
+ rand_move = np.random.choice(possible_moves)
60
+ state = self.game.make_move(state, rand_move, player)
61
+ is_terminal, value = self.game.know_terminal_value(state, rand_move)
62
+ if is_terminal:
63
+ if player == -1:
64
+ value = self.game.get_opponent_value(value)
65
+ return value
66
+ player = self.game.get_opponent(player)
67
+
68
+ def backpropagate(self,value):
69
+ self.total_value += value
70
+ self.visits += 1
71
+
72
+ value = self.game.get_opponent_value(value)
73
+ if self.parent is not None:
74
+ self.parent.backpropagate(value)
75
+
76
+
77
+ class MCTS:
78
+ def __init__(self, game, args):
79
+ self.game = game
80
+ self.args = args
81
+
82
+ def search(self, node):
83
+ root = Node(self.game, self.args, node)
84
+
85
+ for _ in range(self.args["NO_OF_SEARCHES"]):
86
+ node = root
87
+ while node.leaf_or_not():
88
+ node = node.search()
89
+
90
+ is_terminal, value = self.game.know_terminal_value(node.state, node.action)
91
+ value = self.game.get_opponent_value(value)
92
+
93
+ if not is_terminal:
94
+ node = node.expand()
95
+ value = node.simulate()
96
+
97
+ node.backpropagate(value)
98
+
99
+ move_probability = np.zeros(self.game.possible_state)
100
+ for children in root.children:
101
+ move_probability[children.action] = children.visits
102
+ move_probability /= np.sum(move_probability)
103
+
104
+ return move_probability
Play.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import numpy as np
4
+
5
+ import torch
6
+
7
+ from Games.ConnectFour.ConnectFour import ConnectFour
8
+ from Games.ConnectFour.ConnectFourNN import ResNet
9
+ from Alpha_MCTS import Alpha_MCTS
10
+
11
+ class Colors:
12
+ RESET = "\033[0m"
13
+ RED = "\033[91m"
14
+ GREEN = "\033[92m"
15
+ YELLOW = "\033[93m"
16
+ BLUE = "\033[94m"
17
+ MAGENTA = "\033[95m"
18
+ CYAN = "\033[96m"
19
+ WHITE = "\033[97m"
20
+
21
+ GAME = "ConnectFour"
22
+ args = {
23
+ "MODEL_PATH" : os.path.join(os.getcwd(), "Games", GAME, "models_n_optimizers"),
24
+
25
+ "ADVERSARIAL" : True,
26
+ "ROOT_RANDOMNESS": False,
27
+
28
+ "TEMPERATURE" : 1,
29
+
30
+ "NO_OF_SEARCHES" : 1200,
31
+ "EXPLORATION_CONSTANT" : 1,
32
+ }
33
+
34
+
35
+ game = ConnectFour()
36
+ device = torch.device("cuda" if torch.cuda.is_available else "cpu")
37
+
38
+ model = ResNet(game, 9, 128, device)
39
+ model.eval()
40
+
41
+ path = os.path.join(args["MODEL_PATH"], "model.pt")
42
+
43
+ try:
44
+ model.load_state_dict(torch.load(path))
45
+ print(Colors.GREEN, "Model Found\n Model Successfully Loaded", Colors.RESET)
46
+
47
+ except:
48
+ print(Colors.RED, "Model Not Found!!!", Colors.RESET)
49
+
50
+ finally:
51
+ mcts = Alpha_MCTS(game, args, model)
52
+
53
+ state = game.initialise_state()
54
+ player = -1
55
+
56
+ while True:
57
+ print(state)
58
+
59
+ if player == 1:
60
+ valid_moves = game.get_valid_moves(state)
61
+ print("valid_moves", [i for i in range(game.possible_state) if valid_moves[i] == 1])
62
+ action = int(input(f"{player}:"))
63
+
64
+ if valid_moves[action] == 0:
65
+ print("action not valid")
66
+ continue
67
+
68
+ else:
69
+ neutral_state = game.change_perspective(state, player)
70
+ mcts_probs = mcts.search(neutral_state)
71
+ print(Colors.GREEN, "MCTS Move Probabilities:", Colors.RESET,mcts_probs )
72
+ action = np.argmax(mcts_probs)
73
+
74
+ state = game.make_move(state, action, player)
75
+
76
+ is_terminal, value = game.know_terminal_value(state, action)
77
+
78
+ if is_terminal:
79
+ print(state)
80
+ if value == 1:
81
+ print(player, "won")
82
+ else:
83
+ print("draw")
84
+ break
85
+
86
+ player = game.get_opponent(player)
Train.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+
4
+ from Games.TicTacToe.TicTacToe import TicTacToe
5
+ from Games.TicTacToe.TicTacToeNN import ResNet
6
+ from Alpha_Zero_Parallel import Alpha_Zero
7
+
8
+ GAME = "TicTacToe"
9
+
10
+ args = {
11
+ "MODEL_PATH" : os.path.join(os.getcwd(), "Games", GAME, "models_n_optimizers"),
12
+ "SAVE_GAME_PATH" : os.path.join(os.getcwd(), "Games", GAME, "games"),
13
+
14
+ "EXPLORATION_CONSTANT" : 2,
15
+
16
+ "TEMPERATURE" : 2,
17
+
18
+ "DIRICHLET_EPSILON" : 0.25,
19
+ "DIRICHLET_ALPHA" : 0.3,
20
+ "ROOT_RANDOMNESS": True,
21
+
22
+ "ADVERSARIAL" : True,
23
+
24
+ "NO_OF_SEARCHES" : 800,
25
+ "NO_ITERATIONS" : 1,
26
+ "SELF_PLAY_ITERATIONS" : 3000,
27
+ "PARALLEL_PROCESS" : 500,
28
+ "EPOCHS" : 1,
29
+ "BATCH_SIZE" : 128,
30
+ "MODEL_CHECK_GAMES" : 200,
31
+ "WIN_RATIO_FOR_SAVING": 0.5,
32
+ }
33
+
34
+
35
+ game = TicTacToe()
36
+ torch.backends.cudnn.enabled = False
37
+
38
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
39
+
40
+ print(device, "in use")
41
+
42
+ model = ResNet(game, 9, 128, device)
43
+
44
+ optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay = 0.0001)
45
+
46
+ state = game.initialise_state()
47
+
48
+ alpha_zero = Alpha_Zero(game, args, model, optimizer)
49
+
50
+ alpha_zero.learn()
__pycache__/Alpha_MCTS.cpython-310.pyc ADDED
Binary file (3.47 kB). View file
 
__pycache__/Alpha_MCTS.cpython-311.pyc ADDED
Binary file (7.26 kB). View file
 
__pycache__/Alpha_MCTS.cpython-313.pyc ADDED
Binary file (7.27 kB). View file
 
__pycache__/Alpha_MCTS_Parallel.cpython-310.pyc ADDED
Binary file (3.9 kB). View file
 
__pycache__/Alpha_MCTS_Parallel.cpython-311.pyc ADDED
Binary file (8.2 kB). View file
 
__pycache__/Alpha_MCTS_Parallel.cpython-313.pyc ADDED
Binary file (7.7 kB). View file
 
__pycache__/Alpha_Zero.cpython-310.pyc ADDED
Binary file (4.13 kB). View file
 
__pycache__/Alpha_Zero.cpython-311.pyc ADDED
Binary file (13.7 kB). View file
 
__pycache__/Alpha_Zero.cpython-313.pyc ADDED
Binary file (11.4 kB). View file
 
__pycache__/Alpha_Zero_Parallel.cpython-310.pyc ADDED
Binary file (5.64 kB). View file
 
__pycache__/Alpha_Zero_Parallel.cpython-311.pyc ADDED
Binary file (14 kB). View file
 
__pycache__/Alpha_Zero_Parallel.cpython-313.pyc ADDED
Binary file (13.7 kB). View file
 
__pycache__/Arena.cpython-313.pyc ADDED
Binary file (3.8 kB). View file
 
requirements.txt ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ altair==6.0.0
2
+ attrs==25.4.0
3
+ blinker==1.9.0
4
+ cachetools==7.0.5
5
+ certifi==2026.2.25
6
+ charset-normalizer==3.4.5
7
+ click==8.3.1
8
+ cuda-bindings==12.9.4
9
+ cuda-pathfinder==1.4.2
10
+ filelock==3.25.2
11
+ fsspec==2026.2.0
12
+ gitdb==4.0.12
13
+ GitPython==3.1.46
14
+ idna==3.11
15
+ Jinja2==3.1.6
16
+ jsonschema==4.26.0
17
+ jsonschema-specifications==2025.9.1
18
+ MarkupSafe==3.0.3
19
+ mpmath==1.3.0
20
+ narwhals==2.18.0
21
+ networkx==3.6.1
22
+ numpy==2.4.3
23
+ nvidia-cublas-cu12==12.8.4.1
24
+ nvidia-cuda-cupti-cu12==12.8.90
25
+ nvidia-cuda-nvrtc-cu12==12.8.93
26
+ nvidia-cuda-runtime-cu12==12.8.90
27
+ nvidia-cudnn-cu12==9.10.2.21
28
+ nvidia-cufft-cu12==11.3.3.83
29
+ nvidia-cufile-cu12==1.13.1.3
30
+ nvidia-curand-cu12==10.3.9.90
31
+ nvidia-cusolver-cu12==11.7.3.90
32
+ nvidia-cusparse-cu12==12.5.8.93
33
+ nvidia-cusparselt-cu12==0.7.1
34
+ nvidia-nccl-cu12==2.27.5
35
+ nvidia-nvjitlink-cu12==12.8.93
36
+ nvidia-nvshmem-cu12==3.4.5
37
+ nvidia-nvtx-cu12==12.8.90
38
+ packaging==26.0
39
+ pandas==2.3.3
40
+ pillow==12.1.1
41
+ protobuf==6.33.5
42
+ pyarrow==23.0.1
43
+ pydeck==0.9.1
44
+ python-dateutil==2.9.0.post0
45
+ pytz==2026.1.post1
46
+ referencing==0.37.0
47
+ requests==2.32.5
48
+ rpds-py==0.30.0
49
+ setuptools==82.0.1
50
+ six==1.17.0
51
+ smmap==5.0.3
52
+ streamlit==1.55.0
53
+ sympy==1.14.0
54
+ tenacity==9.1.4
55
+ toml==0.10.2
56
+ torch==2.10.0
57
+ torchvision==0.25.0
58
+ tornado==6.5.5
59
+ tqdm==4.67.3
60
+ triton==3.6.0
61
+ typing_extensions==4.15.0
62
+ tzdata==2025.3
63
+ urllib3==2.6.3
64
+ watchdog==6.0.0