forked from KeepCoding/Connecta
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplayer.py
150 lines (105 loc) · 3.99 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from oracle import BaseOracle, ColumnClassification, ColumnRecommendation
import random
from list_utils import all_same
from move import Move
from settings import DEBUG, BOARD_LENGTH
from beautifultable import BeautifulTable
class Player():
"""
Juega en un tablero después de preguntar a un oráculo
"""
def __init__(self, name, char = None, opponent = None, oracle=BaseOracle()) -> None:
self.name = name
self.char = char
self._oracle = oracle
self.opponent = opponent
self.last_moves = []
@property
def opponent(self):
return self._opponent
@opponent.setter
def opponent(self, other):
self._opponent = other
if other != None:
assert other.char != self.char
other._opponent = self
def play(self, board):
"""
Elige la mejor columna de aquellas que recomienda el oráculo
"""
# Pregunto al oráculo
(best, recommendations) = self._ask_oracle(board)
# juego en la mejor
self._play_on(board, best.index, recommendations)
def display_recommendations(self, board):
recs = map(lambda x: str(x.classification).split('.')[
1].lower(), self._oracle.get_recommendation(board, self))
bt = BeautifulTable()
bt.rows.append(recs)
bt.columns.header = [str(i) for i in range(BOARD_LENGTH)]
print(bt)
def on_win(self):
pass
def on_lose(self):
pass
def _play_on(self, board, position, recommendations):
# imprimo recs en caso de debug
if DEBUG:
self.display_recommendations(board)
# juega en la pos
board.add(self.char, position)
# guarda la última jugada (siempre al principio de la lista)
self.last_moves.insert(0, Move(position, board.as_code(), recommendations, self))
def _ask_oracle(self, board):
"""
Pregunta al oráculo y devuielve la mejor opción
"""
# obtenemos las recommendaciones
recommendations = self._oracle.get_recommendation(board, self)
# seleccionamos la mejro
best = self._choose(recommendations)
return (best, recommendations)
def _choose(self, recommendations):
# quitamos las no validas
valid = list(filter(lambda x: x.classification !=
ColumnClassification.FULL, recommendations))
# ordenamos por el valor de clasificación
valid = sorted(valid, key=lambda x : x.classification.value, reverse=True)
# si son todas iguales, pillo una al azar
if all_same(valid):
return random.choice(valid)
else:
# si no lo son, pillo la más deseable (que será la primera)
return valid[0]
class HumanPlayer(Player):
def __init__(self, name, char = None):
super().__init__(name, char)
def _ask_oracle(self, board):
"""
Le pido al humano que es mi oráculo
"""
while True:
# pedimos columna al humano
raw = input('Select a column, puny human: ')
# verificamos que su respuesta no sea una idiotez
if _is_int(raw) and _is_within_column_range(board, int(raw)) and _is_non_full_column(board, int(raw)):
# si no lo es, jugamos donde ha dicho y salimos del bucle
pos = int(raw)
return (ColumnRecommendation(pos, None), None)
class ReportingPlayer(Player):
def on_lose(self):
"""
Le pide al oráculo que revise sus recomendaciones
"""
self._oracle.backtrack(self.last_moves)
# funciones de validación de índice de columna
def _is_non_full_column(board, num):
return not board._columns[num].is_full()
def _is_within_column_range(board, num):
return num >= 0 and num < len(board)
def _is_int(aString):
try:
num = int(aString)
return True
except:
return False