Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add team_8.py #1

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
be5a801
python to python3 for my machine
Aparna-Rajesh Sep 12, 2023
5a0b1e3
team8 player file with new empty functions
Aparna-Rajesh Sep 13, 2023
95e9b5c
Merge pull request #1 from pbluc/constraints-and-risk-1
pbluc Sep 13, 2023
51d1f22
Update team8_player.py
giancarlo-pereira Sep 13, 2023
2609862
Update team8_player.py
giancarlo-pereira Sep 13, 2023
95c3295
Update team8_player.py
giancarlo-pereira Sep 13, 2023
06af909
Update team8_player.py
giancarlo-pereira Sep 13, 2023
6b99d8b
Update team8_player.py
giancarlo-pereira Sep 13, 2023
d63ca5a
changes to Monte Carlo algorithm
giancarlo-pereira Sep 13, 2023
3cab4c1
initial changes to play() function
giancarlo-pereira Sep 17, 2023
22b98ae
copied score calculator from clock_fame.py into utility()
giancarlo-pereira Sep 17, 2023
93831b7
fixed identations issues
giancarlo-pereira Sep 17, 2023
6678ec7
changes in shellscript
giancarlo-pereira Sep 17, 2023
c5cf58f
pulling all commits from Akshay's branch
giancarlo-pereira Sep 17, 2023
e44c6ab
merged Akshay's changes into our branch
giancarlo-pereira Sep 17, 2023
d20d95b
made functions private and added self. calls for each
giancarlo-pereira Sep 17, 2023
ff32156
completed monte carlo skeleton structure and debugged code
giancarlo-pereira Sep 18, 2023
78c045f
added team8_player as option 8
giancarlo-pereira Sep 18, 2023
fc6848d
changed name of player file
giancarlo-pereira Sep 18, 2023
8176099
deleted old name file
giancarlo-pereira Sep 18, 2023
76f00a8
add constraint if have all letters
Aparna-Rajesh Sep 18, 2023
b26565d
rm all letters clause; add constraint if have >= 50% of letters
Aparna-Rajesh Sep 18, 2023
1985e59
Merge pull request #3 from pbluc/choose-discard-2
Aparna-Rajesh Sep 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clock_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from players.default_player import Player as p5
from players.default_player import Player as p6
from players.default_player import Player as p7
from players.default_player import Player as p8
from players.team8_player import Player as p8
from players.default_player import Player as p9
from players.default_player import Player as p10
from players.default_player import Player as p11
Expand Down
60 changes: 30 additions & 30 deletions log_moves.txt
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
The game.....has started.
Move 1 : player 1 ,time 0.001600027084350586s, O at 10
Move 2 : player 2 ,time 9.822845458984375e-05s, H at 1
Move 3 : player 3 ,time 8.606910705566406e-05s, J at 12
Move 1 : player 1 ,time 8.392333984375e-05s, V at 6
Move 2 : player 2 ,time 8.082389831542969e-05s, U at 9
Move 3 : player 3 ,time 7.796287536621094e-05s, Q at 10
Move 1 : player 1 ,time 7.987022399902344e-05s, M at 9
Move 2 : player 2 ,time 7.700920104980469e-05s, W at 1
Move 3 : player 3 ,time 7.295608520507812e-05s, T at 12
Move 1 : player 1 ,time 7.295608520507812e-05s, K at 5
Move 2 : player 2 ,time 7.414817810058594e-05s, P at 8
Move 3 : player 3 ,time 7.295608520507812e-05s, D at 11
Move 1 : player 1 ,time 7.295608520507812e-05s, C at 7
Move 2 : player 2 ,time 7.486343383789062e-05s, B at 3
Move 3 : player 3 ,time 7.319450378417969e-05s, F at 5
Move 1 : player 1 ,time 7.414817810058594e-05s, A at 7
Move 2 : player 2 ,time 7.200241088867188e-05s, I at 4
Move 3 : player 3 ,time 7.295608520507812e-05s, N at 6
Move 1 : player 1 ,time 7.176399230957031e-05s, S at 8
Move 2 : player 2 ,time 7.104873657226562e-05s, L at 2
Move 3 : player 3 ,time 7.390975952148438e-05s, G at 2
Move 1 : player 1 ,time 7.295608520507812e-05s, E at 11
Move 2 : player 2 ,time 7.104873657226562e-05s, R at 3
Move 3 : player 3 ,time 7.200241088867188e-05s, X at 4
Player 1 has score -4 with satistied constraints [] unsatisfied constraints ['B<E', 'U<X<L<T', 'W<O<A<M<Q', 'H<M'] and initial constraints ['B<E', 'U<O<C', 'U<X<L<T', 'W<O<A<M<Q', 'H<M']
Player 2 has score -2 with satistied constraints [] unsatisfied constraints ['R<S<K<I', 'E<Q'] and initial constraints ['W<F', 'H<A<W', 'R<S<K<I', 'U<E<N<H<G', 'E<Q']
Player 3 has score 6 with satistied constraints ['D<T', 'U<D<X<P'] unsatisfied constraints ['J<N'] and initial constraints ['D<T', 'R<A<I', 'U<D<X<P', 'C<Q<R<I<D', 'J<N']
Congratulations Player 3 you are the winner!!!
Time taken by player 1, 2 and 3 to choose : [0.0008177757263183594, 2.4080276489257812e-05, 3.2901763916015625e-05]
Total time taken by player 1, 2 and 3 to decide moves : [0.00212860107421875, 0.0006191730499267578, 0.0006020069122314453]
Move 1 : player 1 ,time 2.2174630165100098s, V at 11
Move 2 : player 2 ,time 0.0s, R at 4
Move 3 : player 3 ,time 0.0s, U at 3
Move 1 : player 1 ,time 2.062376022338867s, J at 11
Move 2 : player 2 ,time 0.015654563903808594s, M at 1
Move 3 : player 3 ,time 0.0s, T at 6
Move 1 : player 1 ,time 1.5478875637054443s, L at 9
Move 2 : player 2 ,time 0.0s, F at 10
Move 3 : player 3 ,time 0.0s, H at 6
Move 1 : player 1 ,time 1.2334678173065186s, C at 5
Move 2 : player 2 ,time 0.0s, I at 5
Move 3 : player 3 ,time 0.0s, K at 4
Move 1 : player 1 ,time 0.9440462589263916s, E at 9
Move 2 : player 2 ,time 0.0s, S at 7
Move 3 : player 3 ,time 0.0009980201721191406s, W at 2
Move 1 : player 1 ,time 0.7347574234008789s, Q at 10
Move 2 : player 2 ,time 0.0s, N at 8
Move 3 : player 3 ,time 0.0s, D at 12
Move 1 : player 1 ,time 0.5157630443572998s, P at 7
Move 2 : player 2 ,time 0.0s, O at 2
Move 3 : player 3 ,time 0.0s, G at 1
Move 1 : player 1 ,time 0.2427208423614502s, A at 12
Move 2 : player 2 ,time 0.0s, X at 8
Move 3 : player 3 ,time 0.0s, B at 3
Player 1 has score 11 with satistied constraints ['O<C<L<J<U'] unsatisfied constraints ['M<F'] and initial constraints ['M<F', 'O<U<J', 'G<P<T<L', 'O<C<L<J<U', 'J<R']
Player 2 has score -2 with satistied constraints ['I<L'] unsatisfied constraints ['L<R', 'E<I<Q', 'R<D<W<K<V'] and initial constraints ['L<R', 'E<I<Q', 'J<W<U<I', 'R<D<W<K<V', 'I<L']
Player 3 has score 0 with satistied constraints ['R<X'] unsatisfied constraints ['G<W<O<H<U'] and initial constraints ['X<U', 'H<Q<R', 'Q<U<W<H', 'G<W<O<H<U', 'R<X']
Congratulations Player 1 you are the winner!!!
Time taken by player 1, 2 and 3 to choose : [0.0010001659393310547, 0.0, 0.0]
Total time taken by player 1, 2 and 3 to decide moves : [9.49848198890686, 0.015654563903808594, 0.0009980201721191406]
231 changes: 231 additions & 0 deletions players/team_8.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
from dataclasses import dataclass
from tokenize import String
import numpy as np
import numpy.typing as npt
import random
import string
from typing import Tuple, List


@dataclass
class Node:
state: npt.ArrayLike
parent: "Node"
children: list["Node"]
hour: int
letter: str
score: int = 0
N: int = 0


class Tree:
def __init__(self, root: "Node"):
self.root = root
self.nodes = {root.state.tobytes(): root}
self.size = 1

def add(self, node: "Node"):
self.nodes[node.state.tobytes()] = node
parent = node.parent
parent.children.append(node)
self.size += 1

def get(self, state: list[str]):
flat_state = state.tobytes()
if flat_state not in self.nodes:
return None
return self.nodes[flat_state]


class Player:
def __init__(self, rng: np.random.Generator) -> None:
"""Initialise the player with given skill.

Args:
rng (np.random.Generator): numpy random number generator, use this for same player behvior across run
"""
self.rng = rng

# def choose_discard(self, cards: list[str], constraints: list[str]):
def choose_discard(self, cards, constraints):
"""Function in which we choose which cards to discard, and it also inititalises the cards dealt to the player at the game beginning

Args:
cards(list): A list of letters you have been given at the beginning of the game.
constraints(list(str)): The total constraints assigned to the given player in the format ["A<B<V","S<D","F<G<A"].

Returns:
list[int]: Return the list of constraint cards that you wish to keep. (can look at the default player logic to understand.)
"""
final_constraints = []

for constraint in constraints:
lst = constraint.split("<")
letters_in_constraint = set(lst)
num_letters_in_cards = sum(
1 for letter in letters_in_constraint if letter in cards)
pct = (num_letters_in_cards / len(letters_in_constraint))
if pct >= 0.5:
final_constraints.append(constraint)

return final_constraints

def __risky_versus_safe():
pass

def __utility(self, constraints: list[str], final_state: list[str]):
"""Utility function that returns player's score after a single monte carlo simulation

Args:
final_state (list(str)): The simulated letters at every hour of the 24 hour clock
constraints(list(str)): The constraints assigned to the given player

Returns:
int: player's core after a single monte carlo simulation
"""
score_value_list = [
1, 3, 6, 12] # points for satisfying constraints on different lengths
score = 0
for i in range(len(constraints)):
list_of_letters = constraints[i].split("<")
constraint_true_indic = True
for j in range(len(list_of_letters)-1):
distance_difference = (final_state.index(
list_of_letters[j+1]) % 12) - (final_state.index(list_of_letters[j]) % 12)
if distance_difference < 0:
distance_difference = distance_difference + 12
if not (distance_difference <= 5 and distance_difference > 0):
constraint_true_indic = False
if constraint_true_indic == False:
score = score - 1
else:
score = score + score_value_list[len(list_of_letters) - 2]
return score

def __select(self, tree: "Tree", state: list[str], alpha: float = 1):
"""Starting from state, move to child node with the
highest UCT value.

Args:
tree ("Tree"): the search tree
state (list[str]): the clock game state
alpha (float): exploration parameter [PERHAPS THIS CAN BE DETERMINED IN RISKY_VS_SAFE()?]
Returns:
state: the clock game state after best UCT move
"""

max_UCT = 0.0
move = state

for child_node in tree.root.children:
node_UCT = (child_node.score/child_node.N + alpha *
np.sqrt(tree.root.N/child_node.N))
if node_UCT > max_UCT:
max_UCT = node_UCT
move = child_node

return move

def __expand(self, tree: "Tree", cards: list[str], state: list[str]):
"""Add all children nodes of state into the tree and return
tree.

Args:
tree ("Tree"): the search tree
cards (list[str]): cards from our player
state (list[str]): the clock game state
Returns:
"Tree": the tree after insertion
"""

for letter in cards:
# add our letters in every hour available
for i in range(0, 12):
new_state = np.copy(state)
if new_state[i] == 'Z':
new_state[i] = letter
elif new_state[i+12] == 'Z':
# if hour already occupied, try index + 12
new_state[i+12] = letter
else:
# if both slots of hour already occupied, continue
continue
hour = 12 if i == 0 else i
tree.add(Node(np.array(new_state),
tree.root, [], hour, letter, 0, 1))
return tree

def __simulate(self, tree: "Tree", state: npt.ArrayLike, constraints: list[str], remaining_cards: list[str]):
"""Run one game rollout from state to a terminal state using random
playout policy and return the numerical utility of the result.

Args:
tree ("Tree"): the search tree
state (list[str]): the clock game state
constraints (list[str]): constraints our player wants to satisfy
remaining_cards (list[str]): cards from all players not yet played

Returns:
"Tree": the search tree with updated scores
"""
new_state = np.copy(state)
while len(remaining_cards):
rand_letter = remaining_cards.pop(
random.randint(0, len(remaining_cards) - 1))
available_hours = np.where(new_state == 'Z')
hour = random.choice(available_hours[0])
new_state[hour] = rand_letter

score = self.__utility(constraints, new_state.tolist())
cur_node = tree.get(state)
cur_node.score += score
cur_node.N += 1
tree.root.score += score
tree.root.N += 1

return tree

def __MCTS(self, cards: list[str], constraints: list[str], state: list[str], rollouts: int = 10000):
# MCTS main loop: Execute MCTS steps rollouts number of times
# Then return successor with highest number of rollouts
tree = Tree(Node(np.array(state), None, [], 24, 'Z', 0, 1))
tree = self.__expand(tree, cards, state)
shuffled_letters = list(self.rng.choice(
list(string.ascii_uppercase)[:24], 24, replace=False))
for letter in state:
if letter != 'Z':
shuffled_letters.remove(letter)

for i in range(rollouts):
available_letters = shuffled_letters.copy()
move = self.__select(tree, state)
available_letters.remove(move.letter)
tree = self.__simulate(
tree, move.state, constraints, available_letters)

nxt = None
plays = 0

for succ in tree.root.children:
if succ.N > plays:
plays = succ.N
nxt = succ
return nxt

# def play(self, cards: list[str], constraints: list[str], state: list[str], territory: list[int]) -> Tuple[int, str]:

def play(self, cards, constraints, state, territory):
"""Function which based n current game state returns the distance and angle, the shot must be played

Args:
score (int): Your total score including current turn
cards (list): A list of letters you have been given at the beginning of the game
state (list[str]): The current letters at every hour of the 24 hour clock
territory (list[int]): The current occupiers of every slot in the 24 hour clock. 1,2,3 for players 1,2 and 3. 4 if position unoccupied.
constraints(list[str]): The constraints assigned to the given player

Returns:
Tuple(int, str): Return a tuple of slot from 1-12 and letter to be played at that slot
"""
move = self.__MCTS(cards, constraints, state)
return move.hour, move.letter
10 changes: 5 additions & 5 deletions summary_log.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Final result is as follows :
Scores for players 1, 2 and 3 : [-4, -2, 6]
Satisfied constraints for players 1, 2 and 3 : [[], [], ['D<T', 'U<D<X<P']]
total time taken to finish the game : 0.006646871566772461s
Time taken by player 1, 2 and 3 to choose : [0.0008177757263183594, 2.4080276489257812e-05, 3.2901763916015625e-05]
Total time taken by player 1, 2 and 3 to decide moves : [0.00212860107421875, 0.0006191730499267578, 0.0006020069122314453]
Scores for players 1, 2 and 3 : [11, -2, 0]
Satisfied constraints for players 1, 2 and 3 : [['O<C<L<J<U'], ['I<L'], ['R<X']]
total time taken to finish the game : 9.531702995300293s
Time taken by player 1, 2 and 3 to choose : [0.0010001659393310547, 0.0, 0.0]
Total time taken by player 1, 2 and 3 to decide moves : [9.49848198890686, 0.015654563903808594, 0.0009980201721191406]