network.py 4.77 KB
Newer Older
Sam Moore's avatar
Sam Moore committed
1
import socket
Sam Moore's avatar
Sam Moore committed
2 3 4 5
import select

network_timeout_start = -1.0 # Timeout in seconds to wait for the start of a message
network_timeout_delay = 1.0 # Maximum time between two characters being received
Sam Moore's avatar
Sam Moore committed
6 7 8 9

class Network():
	def __init__(self, colour, address = None):
		self.socket = socket.socket()
Sam Moore's avatar
Sam Moore committed
10
		#self.socket.setblocking(0)
Sam Moore's avatar
Sam Moore committed
11 12

		if colour == "white":
Sam Moore's avatar
Sam Moore committed
13
			self.port = 4562
Sam Moore's avatar
Sam Moore committed
14
		else:
Sam Moore's avatar
Sam Moore committed
15
			self.port = 4563
Sam Moore's avatar
Sam Moore committed
16 17 18

		self.src = None

Sam Moore's avatar
Sam Moore committed
19 20
	#	print str(self) + " listens on port " + str(self.port)

Sam Moore's avatar
Sam Moore committed
21
		if address == None:
Sam Moore's avatar
Sam Moore committed
22
			self.host = socket.gethostname()
Sam Moore's avatar
Sam Moore committed
23 24 25 26
			self.socket.bind((self.host, self.port))
			self.socket.listen(5)	

			self.src, self.address = self.socket.accept()
Sam Moore's avatar
Sam Moore committed
27 28 29
			self.src.send("ok\n")
			if self.get_response() == "QUIT":
				self.src.close()
Sam Moore's avatar
Sam Moore committed
30 31
		else:
			self.host = address
Sam Moore's avatar
Sam Moore committed
32
			self.socket.connect((address, self.port))
Sam Moore's avatar
Sam Moore committed
33
			self.src = self.socket
Sam Moore's avatar
Sam Moore committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
			self.src.send("ok\n")
			if self.get_response() == "QUIT":
				self.src.close()

	def get_response(self):
		# Timeout the start of the message (first character)
		if network_timeout_start > 0.0:
			ready = select.select([self.src], [], [], network_timeout_start)[0]
		else:
			ready = [self.src]
		if self.src in ready:
			s = self.src.recv(1)
		else:
			raise Exception("UNRESPONSIVE")

Sam Moore's avatar
Sam Moore committed
49 50

		while s[len(s)-1] != '\n':
Sam Moore's avatar
Sam Moore committed
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
			# Timeout on each character in the message
			if network_timeout_delay > 0.0:
				ready = select.select([self.src], [], [], network_timeout_delay)[0]
			else:
				ready = [self.src]
			if self.src in ready:
				s += self.src.recv(1) 
			else:
				raise Exception("UNRESPONSIVE")

		return s.strip(" \r\n")

	def send_message(self,s):
		if network_timeout_start > 0.0:
			ready = select.select([], [self.src], [], network_timeout_start)[1]
		else:
			ready = [self.src]

		if self.src in ready:
			self.src.send(s + "\n")
		else:
			raise Exception("UNRESPONSIVE")

	def check_quit(self, s):
		s = s.split(" ")
		if s[0] == "QUIT":
			with game.lock:
				game.final_result = " ".join(s[1:]) + " " + str(opponent(self.colour))
			game.stop()
			return True
Sam Moore's avatar
Sam Moore committed
81 82 83 84

		

class NetworkSender(Player,Network):
Sam Moore's avatar
Sam Moore committed
85
	def __init__(self, base_player, address = None):
Sam Moore's avatar
Sam Moore committed
86 87 88
		self.base_player = base_player
		Player.__init__(self, base_player.name, base_player.colour)

Sam Moore's avatar
Sam Moore committed
89 90 91 92 93 94
		self.address = address

	def connect(self):
		Network.__init__(self, self.base_player.colour, self.address)


Sam Moore's avatar
Sam Moore committed
95 96 97 98 99

	def select(self):
		[x,y] = self.base_player.select()
		choice = self.board.grid[x][y]
		s = str(x) + " " + str(y)
Sam Moore's avatar
Sam Moore committed
100 101
		#print str(self) + ".select sends " + s
		self.send_message(s)
Sam Moore's avatar
Sam Moore committed
102 103 104 105 106
		return [x,y]

	def get_move(self):
		[x,y] = self.base_player.get_move()
		s = str(x) + " " + str(y)
Sam Moore's avatar
Sam Moore committed
107 108
		#print str(self) + ".get_move sends " + s
		self.send_message(s)
Sam Moore's avatar
Sam Moore committed
109 110 111 112 113 114 115 116 117 118
		return [x,y]

	def update(self, s):
		self.base_player.update(s)
		s = s.split(" ")
		[x,y] = map(int, s[0:2])
		selected = self.board.grid[x][y]
		if selected != None and selected.colour == self.colour and len(s) > 2 and not "->" in s:
			s = " ".join(s[0:3])
			for i in range(2):
119
				if selected.types[i][0] == '?':
Sam Moore's avatar
Sam Moore committed
120 121 122
					s += " " + str(selected.types[i])
				else:
					s += " unknown"
Sam Moore's avatar
Sam Moore committed
123 124
			#print str(self) + ".update sends " + s
			self.send_message(s)
Sam Moore's avatar
Sam Moore committed
125 126 127 128
				

	def quit(self, final_result):
		self.base_player.quit(final_result)
Sam Moore's avatar
Sam Moore committed
129
		#self.src.send("QUIT " + str(final_result) + "\n")
Sam Moore's avatar
Sam Moore committed
130 131 132
		self.src.close()

class NetworkReceiver(Player,Network):
Sam Moore's avatar
Sam Moore committed
133
	def __init__(self, colour, address=None):
Sam Moore's avatar
Sam Moore committed
134
		
Sam Moore's avatar
Sam Moore committed
135
		Player.__init__(self, "NetworkReceiver", colour)
Sam Moore's avatar
Sam Moore committed
136

Sam Moore's avatar
Sam Moore committed
137 138 139
		self.address = address

		self.board = None
Sam Moore's avatar
Sam Moore committed
140

Sam Moore's avatar
Sam Moore committed
141 142
	def connect(self):
		Network.__init__(self, self.colour, self.address)
Sam Moore's avatar
Sam Moore committed
143 144 145
			

	def select(self):
Sam Moore's avatar
Sam Moore committed
146 147 148 149 150 151 152 153 154 155
		
		s = self.get_response()
		#print str(self) + ".select gets " + s
		[x,y] = map(int,s.split(" "))
		if x == -1 and y == -1:
			#print str(self) + ".select quits the game"
			with game.lock:
				game.final_state = "network terminated " + self.colour
			game.stop()
		return [x,y]
Sam Moore's avatar
Sam Moore committed
156
	def get_move(self):
Sam Moore's avatar
Sam Moore committed
157 158 159 160 161 162 163 164 165
		s = self.get_response()
		#print str(self) + ".get_move gets " + s
		[x,y] = map(int,s.split(" "))
		if x == -1 and y == -1:
			#print str(self) + ".get_move quits the game"
			with game.lock:
				game.final_state = "network terminated " + self.colour
			game.stop()
		return [x,y]
Sam Moore's avatar
Sam Moore committed
166 167 168 169 170 171 172

	def update(self, result):
		
		result = result.split(" ")
		[x,y] = map(int, result[0:2])
		selected = self.board.grid[x][y]
		if selected != None and selected.colour == self.colour and len(result) > 2 and not "->" in result:
Sam Moore's avatar
Sam Moore committed
173 174
			s = self.get_response()
			#print str(self) + ".update - receives " + str(s)
Sam Moore's avatar
Sam Moore committed
175 176 177 178 179
			s = s.split(" ")
			selected.choice = int(s[2])
			for i in range(2):
				selected.types[i] = str(s[3+i])
				if s[3+i] == "unknown":
180
					selected.types[i] = '?'+selected.types[i]
Sam Moore's avatar
Sam Moore committed
181
				else:
182
					selected.types[i] = selected.types[i][1:]
Sam Moore's avatar
Sam Moore committed
183 184
			selected.current_type = selected.types[selected.choice]	
		else:
Sam Moore's avatar
Sam Moore committed
185 186
			pass
			#print str(self) + ".update - ignore result " + str(result)			
Sam Moore's avatar
Sam Moore committed
187 188 189 190 191
		

	def quit(self, final_result):
		self.src.close()