d0f6cfb8d8c66c16e989666759b933283cb97f4c
[progcomp2013.git] / qchess / src / player.py
1 import subprocess
2 import select
3 import platform
4 import re
5
6 agent_timeout = -1.0 # Timeout in seconds for AI players to make moves
7                         # WARNING: Won't work for windows based operating systems
8
9 if platform.system() == "Windows":
10         agent_timeout = -1 # Hence this
11
12 # A player who can't play
13 class Player():
14         def __init__(self, name, colour):
15                 self.name = name
16                 self.colour = colour
17
18         def update(self, result):
19                 pass
20
21         def reset_board(self, s):
22                 pass
23
24 # Player that runs from another process
25 class ExternalAgent(Player):
26
27
28         def __init__(self, name, colour):
29                 Player.__init__(self, name, colour)
30                 self.p = subprocess.Popen(name,bufsize=0,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True,universal_newlines=True)
31                 
32                 self.send_message(colour)
33
34         def send_message(self, s):
35                 if agent_timeout > 0.0:
36                         ready = select.select([], [self.p.stdin], [], agent_timeout)[1]
37                 else:
38                         ready = [self.p.stdin]
39                 if self.p.stdin in ready:
40                         #sys.stderr.write("Writing \'" + s + "\' to " + str(self.p) + "\n")
41                         try:
42                                 self.p.stdin.write(s + "\n")
43                         except:
44                                 raise Exception("UNRESPONSIVE")
45                 else:
46                         raise Exception("TIMEOUT")
47
48         def get_response(self):
49                 if agent_timeout > 0.0:
50                         ready = select.select([self.p.stdout], [], [], agent_timeout)[0]
51                 else:
52                         ready = [self.p.stdout]
53                 if self.p.stdout in ready:
54                         #sys.stderr.write("Reading from " + str(self.p) + " 's stdout...\n")
55                         try:
56                                 result = self.p.stdout.readline().strip(" \t\r\n")
57                                 #sys.stderr.write("Read \'" + result + "\' from " + str(self.p) + "\n")
58                                 return result
59                         except: # Exception, e:
60                                 raise Exception("UNRESPONSIVE")
61                 else:
62                         raise Exception("TIMEOUT")
63
64         def select(self):
65
66                 self.send_message("SELECTION?")
67                 line = self.get_response()
68                 
69                 try:
70                         m = re.match("\s*(\d+)\s+(\d+)\s*", line)
71                         result = map(int, [m.group(1), m.group(2)])
72                 except:
73                         raise Exception("GIBBERISH \"" + str(line) + "\"")
74                 return result
75
76         def update(self, result):
77                 #print "Update " + str(result) + " called for AgentPlayer"
78                 self.send_message(result)
79
80
81         def get_move(self):
82                 
83                 self.send_message("MOVE?")
84                 line = self.get_response()
85                 
86                 try:
87                         m = re.match("\s*(\d+)\s+(\d+)\s*", line)
88                         result = map(int, [m.group(1), m.group(2)])
89
90                 except:
91                         raise Exception("GIBBERISH \"" + str(line) + "\"")
92                 return result
93
94         def reset_board(self, s):
95                 self.send_message("BOARD")
96                 for line in s.split("\n"):
97                         self.send_message(line.strip(" \r\n"))
98                 self.send_message("END BOARD")
99
100         def quit(self, final_result):
101                 try:
102                         self.send_message("QUIT " + final_result)
103                 except:
104                         self.p.kill()
105
106 # So you want to be a player here?
107 class HumanPlayer(Player):
108         def __init__(self, name, colour):
109                 Player.__init__(self, name, colour)
110                 
111         # Select your preferred account
112         def select(self):
113                 if isinstance(graphics, GraphicsThread):
114                         # Basically, we let the graphics thread do some shit and then return that information to the game thread
115                         graphics.cond.acquire()
116                         # We wait for the graphics thread to select a piece
117                         while graphics.stopped() == False and graphics.state["select"] == None:
118                                 graphics.cond.wait() # The difference between humans and machines is that humans sleep
119                         select = graphics.state["select"]
120                         
121                         
122                         graphics.cond.release()
123                         if graphics.stopped():
124                                 return [-1,-1]
125                         return [select.x, select.y]
126                 else:
127                         # Since I don't display the board in this case, I'm not sure why I filled it in...
128                         while True:
129                                 sys.stdout.write("SELECTION?\n")
130                                 try:
131                                         p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
132                                 except:
133                                         sys.stderr.write("ILLEGAL GIBBERISH\n")
134                                         continue
135         # It's your move captain
136         def get_move(self):
137                 if isinstance(graphics, GraphicsThread):
138                         graphics.cond.acquire()
139                         while graphics.stopped() == False and graphics.state["dest"] == None:
140                                 graphics.cond.wait()
141                         graphics.cond.release()
142                         
143                         return graphics.state["dest"]
144                 else:
145
146                         while True:
147                                 sys.stdout.write("MOVE?\n")
148                                 try:
149                                         p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
150                                 except:
151                                         sys.stderr.write("ILLEGAL GIBBERISH\n")
152                                         continue
153
154         # Are you sure you want to quit?
155         def quit(self, final_result):
156                 if graphics == None:            
157                         sys.stdout.write("QUIT " + final_result + "\n")
158
159         # Completely useless function
160         def update(self, result):
161                 if isinstance(graphics, GraphicsThread):
162                         pass
163                 else:
164                         sys.stdout.write(result + "\n") 
165
166
167 # Default internal player (makes random moves)
168 class InternalAgent(Player):
169         def __init__(self, name, colour):
170                 Player.__init__(self, name, colour)
171                 self.choice = None
172
173                 self.board = Board(style = "agent")
174
175
176
177         def update(self, result):
178                 
179                 self.board.update(result)
180                 self.board.verify()
181
182         def reset_board(self, s):
183                 self.board.reset_board(s)
184
185         def quit(self, final_result):
186                 pass
187
188 class AgentRandom(InternalAgent):
189         def __init__(self, name, colour):
190                 InternalAgent.__init__(self, name, colour)
191
192         def select(self):
193                 while True:
194                         self.choice = self.board.pieces[self.colour][random.randint(0, len(self.board.pieces[self.colour])-1)]
195                         all_moves = []
196                         # Check that the piece has some possibility to move
197                         tmp = self.choice.current_type
198                         if tmp == "unknown": # For unknown pieces, try both types
199                                 for t in self.choice.types:
200                                         if t == "unknown":
201                                                 continue
202                                         self.choice.current_type = t
203                                         all_moves += self.board.possible_moves(self.choice)
204                         else:
205                                 all_moves = self.board.possible_moves(self.choice)
206                         self.choice.current_type = tmp
207                         if len(all_moves) > 0:
208                                 break
209                 return [self.choice.x, self.choice.y]
210
211         def get_move(self):
212                 moves = self.board.possible_moves(self.choice)
213                 move = moves[random.randint(0, len(moves)-1)]
214                 return move
215
216
217 # Terrible, terrible hacks
218
219 def run_agent(agent):
220         #sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n")
221         while True:
222                 line = sys.stdin.readline().strip(" \r\n")
223                 if line == "SELECTION?":
224                         #sys.stderr.write(sys.argv[0] + " : Make selection\n")
225                         [x,y] = agent.select() # Gets your agent's selection
226                         #sys.stderr.write(sys.argv[0] + " : Selection was " + str(agent.choice) + "\n")
227                         sys.stdout.write(str(x) + " " + str(y) + "\n")                          
228                 elif line == "MOVE?":
229                         #sys.stderr.write(sys.argv[0] + " : Make move\n")
230                         [x,y] = agent.get_move() # Gets your agent's move
231                         sys.stdout.write(str(x) + " " + str(y) + "\n")
232                 elif line.split(" ")[0] == "QUIT":
233                         #sys.stderr.write(sys.argv[0] + " : Quitting\n")
234                         agent.quit(" ".join(line.split(" ")[1:])) # Quits the game
235                         break
236                 elif line.split(" ")[0] == "BOARD":
237                         s = ""
238                         line = sys.stdin.readline().strip(" \r\n")
239                         while line != "END BOARD":
240                                 s += line + "\n"
241                                 line = sys.stdin.readline().strip(" \r\n")
242                         agent.board.reset_board(s)
243                         
244                 else:
245                         agent.update(line) # Updates agent.board
246         return 0
247
248
249 # Sort of works?
250
251 class ExternalWrapper(ExternalAgent):
252         def __init__(self, agent):
253                 run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.stdin.readline();sys.exit(run_agent(agent))\""
254                 # str(run)
255                 ExternalAgent.__init__(self, run, agent.colour)
256
257         
258

UCC git Repository :: git.ucc.asn.au