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

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