-
Notifications
You must be signed in to change notification settings - Fork 4
/
player.py
100 lines (80 loc) · 2.66 KB
/
player.py
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
import random
class BasePlayer:
def __init__(self, name):
self.name = name
self.position = None
self.pieces = []
self.history = []
self.heads = None
def step(self, heads):
should_pass = True
if -1 in heads:
# First move of the game
should_pass = False
else:
for piece in self.pieces:
if piece[0] in heads or piece[1] in heads:
should_pass = False
break
if should_pass:
# If player should pass because it doesn't have any valid piece
return None
self.heads = heads
piece, head = self.choice()
assert piece in self.pieces, f"Invalid piece: {piece}"
self.pieces.remove(piece)
return piece, head
def valid(self, piece, head):
"""
Check if `piece` can be put on head `head`
"""
return self.heads[head] == -1 or self.heads[head] in piece
def reset(self, position, pieces):
self.position = position
self.pieces = pieces
self.history.clear()
def log(self, data):
self.history.append(data)
def choice(self):
"""
Logic of each agent. This function will be called from `step` when
there is at least one valid piece. Notice that rules force player to
always make a move whenever is possible.
Player can access to current heads using `self.heads` or even full match history
through `self.history`
Return:
piece: (tuple<int>) Piece player is going to play. It must have it.
head: (int in {0, 1}) What head is it going to put the piece. This will be ignored in the first move.
"""
raise NotImplementedError()
def score(self):
"""
Score of current player relative to the weights of its pieces
"""
result = 0
for piece in self.pieces:
result += piece[0] + piece[1]
return result
@property
def me(self):
return self.position
@property
def partner(self, position=None):
if position is None:
position = self.me
return position ^ 2
@property
def team(self, position=None):
""" Players 0 and 2 belong to team 0
Players 1 and 3 belong to team 1
"""
if position is None:
position = self.me
return position & 1
@property
def next(self, position=None):
""" Next player to play
"""
if position is None:
position = self.me
return (position + 1) & 3