Skip to content

Commit 53e524b

Browse files
committed
Initial commit
0 parents  commit 53e524b

File tree

5 files changed

+225
-0
lines changed

5 files changed

+225
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache__
2+
.vscode
3+
/player.1.py

game.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from typing import List
2+
3+
def build_distance_map(zero_x: int, zero_y: int, floor_map: list):
4+
dist_map = [[None for y in range(len(floor_map[0]))] for x in range(len(floor_map))]
5+
def set_distance(x: int, y: int, floor_map: list, distance: int):
6+
if not floor_map[x][y] or (dist_map[x][y] != None and dist_map[x][y] <= distance):
7+
return
8+
9+
dist_map[x][y] = distance
10+
if x > 0:
11+
set_distance(x - 1, y, floor_map, distance + 1)
12+
if x < len(floor_map) - 1:
13+
set_distance(x + 1, y, floor_map, distance + 1)
14+
if y > 0:
15+
set_distance(x, y - 1, floor_map, distance + 1)
16+
if y < len(floor_map[0]) - 1:
17+
set_distance(x, y + 1, floor_map, distance + 1)
18+
19+
set_distance(zero_x, zero_y, floor_map, 0)
20+
return dist_map
21+
22+
class Unit:
23+
def __init__(self, input_unit):
24+
self.id: str = input_unit['id']
25+
self.power: int = input_unit['power']
26+
self.health: int = input_unit['health']
27+
self.x: int = input_unit['x']
28+
self.y: int = input_unit['y']
29+
self.dist_map: List[List[int]] = None
30+
31+
def get_distance(self, x: int, y: int, state):
32+
if self.dist_map == None:
33+
self.dist_map = build_distance_map(self.x, self.y, state.empty_map)
34+
35+
return self.dist_map[x][y]
36+
37+
class GameState:
38+
def __init__(self, input_state):
39+
self.unit = Unit(input_state['unit'])
40+
self.units: List[Unit] = [Unit(u) for u in input_state['units']]
41+
self.foes: List[Unit] = [Unit(u) for u in input_state['foes']]
42+
self.floor_map: List[List[bool]] = input_state['floorMap']
43+
self.empty_map: List[List[bool]] = [[square for square in col] for col in self.floor_map]
44+
45+
for unit in self.units:
46+
if unit.health > 0 and unit.id != self.unit.id:
47+
self.empty_map[unit.x][unit.y] = False
48+
for foe in self.foes:
49+
if foe.health > 0:
50+
self.empty_map[foe.x][foe.y] = False
51+
52+
class Action:
53+
def __init__(self, action_type: str, direction: str):
54+
self.type = action_type
55+
self.direction = direction
56+
57+
def is_empty(x: int, y: int, state: GameState):
58+
return state.empty_map[x][y]

main.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import tornado.ioloop
2+
import tornado.web
3+
from tornado.httpclient import HTTPClient, HTTPRequest
4+
import sys
5+
import json
6+
import importlib
7+
import os
8+
import threading
9+
import traceback
10+
from time import sleep
11+
12+
import player
13+
from game import GameState
14+
15+
running = True
16+
17+
def monitor_changes(port):
18+
last_write_time = os.path.getmtime('player.py')
19+
20+
while running:
21+
current_write_time = os.path.getmtime('player.py')
22+
if last_write_time != current_write_time:
23+
last_write_time = current_write_time
24+
print ('Change detected')
25+
importlib.reload(player)
26+
register_player(port)
27+
28+
sleep(1)
29+
30+
print('Stopping')
31+
32+
class MainHandler(tornado.web.RequestHandler):
33+
34+
def get(self):
35+
self.handle_method('GET')
36+
37+
def post(self):
38+
self.handle_method('POST')
39+
40+
def get_payload(self):
41+
42+
payload_len = int(self.request.headers.get('content-length', 0))
43+
if payload_len == 0:
44+
return None
45+
return tornado.escape.json_decode(self.request.body)
46+
47+
def handle_method(self, method):
48+
try:
49+
if method == 'GET':
50+
self.set_status(200)
51+
self.write('Please send POST with game data\n'.encode())
52+
else:
53+
payload = self.get_payload()
54+
response = ''
55+
if self.request.path == '/end':
56+
player.game_end()
57+
else:
58+
actions = player.get_actions(GameState(payload))
59+
response = json.dumps(list(map(lambda a : a.__dict__, actions)), sort_keys=True, indent=2).encode()
60+
self.set_status(200)
61+
self.set_header('Content-Type', 'application/json')
62+
self.write(response)
63+
64+
except Exception as e:
65+
print(e)
66+
print(traceback.format_exc())
67+
self.set_status(500)
68+
self.write('An error occured')
69+
70+
71+
poll_interval = 0.1
72+
73+
def make_app():
74+
return tornado.web.Application([
75+
(r"/.*", MainHandler),
76+
])
77+
78+
def start_server(port):
79+
'Starts the server on specified port'
80+
print('Starting HTTP server at port %d' % port)
81+
app = make_app()
82+
app.listen(port)
83+
try:
84+
tornado.ioloop.IOLoop.current().start()
85+
except KeyboardInterrupt:
86+
pass
87+
88+
def register_player(port):
89+
'Register the player with the game server'
90+
info = player.get_player_info()
91+
info["address"] = "http://10.0.75.1:" + str(port)
92+
http_client = HTTPClient()
93+
http_client.fetch(
94+
HTTPRequest(
95+
'http://localhost:8080/api/players',
96+
method="POST",
97+
headers={
98+
'Content-Type': 'application/json'
99+
},
100+
body=json.dumps(info, sort_keys=True, indent=2).encode()
101+
)
102+
)
103+
104+
if __name__ == '__main__':
105+
port = 9080
106+
register_player(port)
107+
monitor = threading.Thread(target=monitor_changes, args=(port,))
108+
monitor.start()
109+
start_server(port)
110+
running = False
111+
monitor.join()

player.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Logic for controlling units
2+
3+
from game import Action, is_empty, Unit, GameState, build_distance_map
4+
5+
def get_actions(state):
6+
return [
7+
Action('move', 'left')
8+
]
9+
10+
def get_player_info():
11+
return {
12+
"id": "cc9ddc91-2e0d-4565-af30-a39748f2344b",
13+
"name": "Swamp prawns"
14+
}
15+
16+
def game_end():
17+
pass

registerPlayers.ps1

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Invoke-WebRequest -Headers @{'Content-Type' = 'application/json'} `
2+
-Method Post `
3+
-Uri 'http://localhost:8080/api/players' `
4+
-Body '{
5+
"id": "a9cd1ada-c81a-463a-b997-b6ef8ee57da9",
6+
"name": "Giant Wipeout",
7+
"address": "http://10.0.75.1:9080"
8+
}'
9+
10+
11+
Invoke-WebRequest -Headers @{'Content-Type' = 'application/json'} `
12+
-Method Post `
13+
-Uri 'http://localhost:8080/api/players' `
14+
-Body '{
15+
"id": "7c3c1128-792c-46b2-afa1-1de3e55974e2",
16+
"name": "Purple spawn",
17+
"address": "http://10.0.75.1:9080"
18+
}'
19+
20+
Invoke-WebRequest -Headers @{'Content-Type' = 'application/json'} `
21+
-Method Post `
22+
-Uri 'http://localhost:8080/api/players' `
23+
-Body '{
24+
"id": "cc9ddc91-2e0d-4565-af30-a39748f2344b",
25+
"name": "Swamp prawns",
26+
"address": "http://10.0.75.1:9080"
27+
}'
28+
29+
Invoke-WebRequest -Headers @{'Content-Type' = 'application/json'} `
30+
-Method Post `
31+
-Uri 'http://localhost:8080/api/players' `
32+
-Body '{
33+
"id": "414d3aef-a0a4-4f1b-b2d7-b77d52df9c40",
34+
"name": "Blank pixies",
35+
"address": "http://10.0.75.1:9080"
36+
}'

0 commit comments

Comments
 (0)