player.py 6.93 KB
Newer Older
Sam Moore's avatar
Sam Moore committed
1
import subprocess
Sam Moore's avatar
Sam Moore committed
2 3
import select
import platform
4
import re
5

Sam Moore's avatar
Sam Moore committed
6 7
agent_timeout = -1.0 # Timeout in seconds for AI players to make moves
			# WARNING: Won't work for windows based operating systems
Sam Moore's avatar
Sam Moore committed
8

Sam Moore's avatar
Sam Moore committed
9 10
if platform.system() == "Windows":
	agent_timeout = -1 # Hence this
Sam Moore's avatar
Sam Moore committed
11 12 13 14 15 16 17

# A player who can't play
class Player():
	def __init__(self, name, colour):
		self.name = name
		self.colour = colour

Sam Moore's avatar
Sam Moore committed
18 19 20
	def update(self, result):
		pass

Sam Moore's avatar
Sam Moore committed
21 22 23
	def reset_board(self, s):
		pass

Sam Moore's avatar
Sam Moore committed
24
# Player that runs from another process
Sam Moore's avatar
Sam Moore committed
25
class ExternalAgent(Player):
Sam Moore's avatar
Sam Moore committed
26 27


Sam Moore's avatar
Sam Moore committed
28 29
	def __init__(self, name, colour):
		Player.__init__(self, name, colour)
Sam Moore's avatar
Sam Moore committed
30
		self.p = subprocess.Popen(name,bufsize=0,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True,universal_newlines=True)
Sam Moore's avatar
Sam Moore committed
31 32 33 34 35 36 37 38 39
		
		self.send_message(colour)

	def send_message(self, s):
		if agent_timeout > 0.0:
			ready = select.select([], [self.p.stdin], [], agent_timeout)[1]
		else:
			ready = [self.p.stdin]
		if self.p.stdin in ready:
Sam Moore's avatar
Sam Moore committed
40
			#sys.stderr.write("Writing \'" + s + "\' to " + str(self.p) + "\n")
Sam Moore's avatar
Sam Moore committed
41 42 43 44 45
			try:
				self.p.stdin.write(s + "\n")
			except:
				raise Exception("UNRESPONSIVE")
		else:
Sam Moore's avatar
Sam Moore committed
46
			raise Exception("TIMEOUT")
Sam Moore's avatar
Sam Moore committed
47 48 49 50 51 52 53

	def get_response(self):
		if agent_timeout > 0.0:
			ready = select.select([self.p.stdout], [], [], agent_timeout)[0]
		else:
			ready = [self.p.stdout]
		if self.p.stdout in ready:
Sam Moore's avatar
Sam Moore committed
54
			#sys.stderr.write("Reading from " + str(self.p) + " 's stdout...\n")
Sam Moore's avatar
Sam Moore committed
55
			try:
56
				result = self.p.stdout.readline().strip(" \t\r\n")
Sam Moore's avatar
Sam Moore committed
57 58
				#sys.stderr.write("Read \'" + result + "\' from " + str(self.p) + "\n")
				return result
Sam Moore's avatar
Sam Moore committed
59 60 61
			except: # Exception, e:
				raise Exception("UNRESPONSIVE")
		else:
Sam Moore's avatar
Sam Moore committed
62
			raise Exception("TIMEOUT")
Sam Moore's avatar
Sam Moore committed
63 64

	def select(self):
Sam Moore's avatar
Sam Moore committed
65 66 67

		self.send_message("SELECTION?")
		line = self.get_response()
Sam Moore's avatar
Sam Moore committed
68 69
		
		try:
70 71
			m = re.match("\s*(\d+)\s+(\d+)\s*", line)
			result = map(int, [m.group(1), m.group(2)])
Sam Moore's avatar
Sam Moore committed
72 73 74 75 76 77
		except:
			raise Exception("GIBBERISH \"" + str(line) + "\"")
		return result

	def update(self, result):
		#print "Update " + str(result) + " called for AgentPlayer"
Sam Moore's avatar
Sam Moore committed
78 79
		self.send_message(result)

Sam Moore's avatar
Sam Moore committed
80 81 82

	def get_move(self):
		
Sam Moore's avatar
Sam Moore committed
83 84 85
		self.send_message("MOVE?")
		line = self.get_response()
		
Sam Moore's avatar
Sam Moore committed
86
		try:
87 88 89
			m = re.match("\s*(\d+)\s+(\d+)\s*", line)
			result = map(int, [m.group(1), m.group(2)])

Sam Moore's avatar
Sam Moore committed
90 91 92 93
		except:
			raise Exception("GIBBERISH \"" + str(line) + "\"")
		return result

Sam Moore's avatar
Sam Moore committed
94 95 96 97 98 99
	def reset_board(self, s):
		self.send_message("BOARD")
		for line in s.split("\n"):
			self.send_message(line.strip(" \r\n"))
		self.send_message("END BOARD")

Sam Moore's avatar
Sam Moore committed
100 101
	def quit(self, final_result):
		try:
Sam Moore's avatar
Sam Moore committed
102
			self.send_message("QUIT " + final_result)
Sam Moore's avatar
Sam Moore committed
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 151 152 153 154 155
		except:
			self.p.kill()

# So you want to be a player here?
class HumanPlayer(Player):
	def __init__(self, name, colour):
		Player.__init__(self, name, colour)
		
	# Select your preferred account
	def select(self):
		if isinstance(graphics, GraphicsThread):
			# Basically, we let the graphics thread do some shit and then return that information to the game thread
			graphics.cond.acquire()
			# We wait for the graphics thread to select a piece
			while graphics.stopped() == False and graphics.state["select"] == None:
				graphics.cond.wait() # The difference between humans and machines is that humans sleep
			select = graphics.state["select"]
			
			
			graphics.cond.release()
			if graphics.stopped():
				return [-1,-1]
			return [select.x, select.y]
		else:
			# Since I don't display the board in this case, I'm not sure why I filled it in...
			while True:
				sys.stdout.write("SELECTION?\n")
				try:
					p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
				except:
					sys.stderr.write("ILLEGAL GIBBERISH\n")
					continue
	# It's your move captain
	def get_move(self):
		if isinstance(graphics, GraphicsThread):
			graphics.cond.acquire()
			while graphics.stopped() == False and graphics.state["dest"] == None:
				graphics.cond.wait()
			graphics.cond.release()
			
			return graphics.state["dest"]
		else:

			while True:
				sys.stdout.write("MOVE?\n")
				try:
					p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
				except:
					sys.stderr.write("ILLEGAL GIBBERISH\n")
					continue

	# Are you sure you want to quit?
	def quit(self, final_result):
Sam Moore's avatar
Sam Moore committed
156 157
		if graphics == None:		
			sys.stdout.write("QUIT " + final_result + "\n")
Sam Moore's avatar
Sam Moore committed
158 159 160 161 162 163 164 165 166

	# Completely useless function
	def update(self, result):
		if isinstance(graphics, GraphicsThread):
			pass
		else:
			sys.stdout.write(result + "\n")	


Sam Moore's avatar
Sam Moore committed
167 168
# Default internal player (makes random moves)
class InternalAgent(Player):
Sam Moore's avatar
Sam Moore committed
169 170 171 172 173 174
	def __init__(self, name, colour):
		Player.__init__(self, name, colour)
		self.choice = None

		self.board = Board(style = "agent")

Sam Moore's avatar
Sam Moore committed
175 176 177 178 179 180 181


	def update(self, result):
		
		self.board.update(result)
		self.board.verify()

Sam Moore's avatar
Sam Moore committed
182 183 184
	def reset_board(self, s):
		self.board.reset_board(s)

Sam Moore's avatar
Sam Moore committed
185 186 187 188 189 190 191
	def quit(self, final_result):
		pass

class AgentRandom(InternalAgent):
	def __init__(self, name, colour):
		InternalAgent.__init__(self, name, colour)

Sam Moore's avatar
Sam Moore committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
	def select(self):
		while True:
			self.choice = self.board.pieces[self.colour][random.randint(0, len(self.board.pieces[self.colour])-1)]
			all_moves = []
			# Check that the piece has some possibility to move
			tmp = self.choice.current_type
			if tmp == "unknown": # For unknown pieces, try both types
				for t in self.choice.types:
					if t == "unknown":
						continue
					self.choice.current_type = t
					all_moves += self.board.possible_moves(self.choice)
			else:
				all_moves = self.board.possible_moves(self.choice)
			self.choice.current_type = tmp
			if len(all_moves) > 0:
				break
		return [self.choice.x, self.choice.y]

	def get_move(self):
		moves = self.board.possible_moves(self.choice)
		move = moves[random.randint(0, len(moves)-1)]
		return move


Sam Moore's avatar
Sam Moore committed
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
# Terrible, terrible hacks

def run_agent(agent):
	#sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n")
	while True:
		line = sys.stdin.readline().strip(" \r\n")
		if line == "SELECTION?":
			#sys.stderr.write(sys.argv[0] + " : Make selection\n")
			[x,y] = agent.select() # Gets your agent's selection
			#sys.stderr.write(sys.argv[0] + " : Selection was " + str(agent.choice) + "\n")
			sys.stdout.write(str(x) + " " + str(y) + "\n")				
		elif line == "MOVE?":
			#sys.stderr.write(sys.argv[0] + " : Make move\n")
			[x,y] = agent.get_move() # Gets your agent's move
			sys.stdout.write(str(x) + " " + str(y) + "\n")
		elif line.split(" ")[0] == "QUIT":
			#sys.stderr.write(sys.argv[0] + " : Quitting\n")
			agent.quit(" ".join(line.split(" ")[1:])) # Quits the game
			break
Sam Moore's avatar
Sam Moore committed
236 237 238 239 240 241 242 243
		elif line.split(" ")[0] == "BOARD":
			s = ""
			line = sys.stdin.readline().strip(" \r\n")
			while line != "END BOARD":
				s += line + "\n"
				line = sys.stdin.readline().strip(" \r\n")
			agent.board.reset_board(s)
			
Sam Moore's avatar
Sam Moore committed
244 245 246 247 248 249 250 251 252
		else:
			agent.update(line) # Updates agent.board
	return 0


# Sort of works?

class ExternalWrapper(ExternalAgent):
	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))\""
Sam Moore's avatar
Sam Moore committed
254 255
		# str(run)
		ExternalAgent.__init__(self, run, agent.colour)
256

Sam Moore's avatar
Sam Moore committed
257
	
258