about summary refs log tree commit diff homepage
path: root/client-examples/hit-and-run.py
diff options
context:
space:
mode:
Diffstat (limited to 'client-examples/hit-and-run.py')
-rwxr-xr-xclient-examples/hit-and-run.py101
1 files changed, 50 insertions, 51 deletions
diff --git a/client-examples/hit-and-run.py b/client-examples/hit-and-run.py
index ef90276..7959315 100755
--- a/client-examples/hit-and-run.py
+++ b/client-examples/hit-and-run.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
+from contextlib import closing, suppress
 from math import inf, atan2, degrees
-from random import randrange
+from random import randrange, shuffle
 from socket import socket
 
 AROUND = [5, 2, 1, 0, 3, 6, 7, 8]
@@ -18,56 +19,54 @@ def is_wall(maze, y, x):
     return maze[y][x] != '0'
 
 
-clientsocket = socket()
-clientsocket.connect(('localhost', 8089))
-corners, sides = [0, 2, 6, 8], [1, 3, 5, 7]
-around, move = [0, 1, 2, 3, 5, 6, 7, 8], 4
-while True:
-    length = clientsocket.recv(7).decode()
-    if length in ('', '0000000'): break     # connection closed or game over
-    data = iter(clientsocket.recv(int(length)).decode().split())
-    nh, ne, nb, score = (int(next(data)) for _ in range(4))
-    maze = [list(next(data)) for _ in range(nh)]
-    hp = (lambda c: 0 if c == 48 else 123 - c)(ord(next(data)))
-    hx, hy, ha = (int(next(data)) for _ in range(3))
-    attackable, heal = (bool(int(next(data))) for _ in range(2))
+def get_move(maze, move):
+    """Return an outstanding move."""
+    moves, around = get_moves(len(maze) // 2, len(maze[0]) // 2), AROUND[:]
+    if move != 4 and not is_wall(maze, *moves[move]): return move
+    if move == 4:
+        shuffle(around)
+    else:
+        idx = AROUND.index(move)
+        around.sort(key=lambda i: abs(abs(abs(AROUND.index(i)-idx)-4)-4))
+    for move in around:
+        idx = AROUND.index(move)
+        if all(not is_wall(maze, *moves[i])
+               for i in (move, AROUND[idx - 1], AROUND[idx - 7])):
+            return move
+    return 4
 
-    if nh:
-        moves = get_moves(len(maze) // 2, len(maze[0]) // 2)
-        if move == 4 or is_wall(maze, *moves[move]):
-            try:
-                idx = AROUND.index(move)
-            except ValueError:
-                pass
-            else:
-                around.sort(key=(lambda i: (lambda x: min(x, 8 - x))(
-                    abs(AROUND.index(i) - idx))))
-            for move in around:
-                idx = AROUND.index(move)
-                if all(map(
-                    (lambda i: not is_wall(maze, *moves[i])),
-                    (move, AROUND[idx - 1], AROUND[idx - 7]))):
-                    break
-            else:
-                move = 4
 
-    angle, shortest = ha, inf
-    for _ in range(ne):
-        p = 3 - (ord(next(data)) - 97)%3
-        x, y, a = (int(next(data)) for _ in range(3))
-        d = ((x - hx)**2 + (y - hy)**2)**0.5
-        if d < shortest:
-            shortest = d
-            b = degrees(atan2(y - hy, x - hx))
-            angle = round(b + 360 if b < 0 else b)
+with suppress(KeyboardInterrupt), closing(socket()) as sock:
+    sock.connect(('localhost', 42069))
+    move = 4
+    while True:
+        length = sock.recv(7).decode()
+        # connection closed or game over
+        if length in ('', '0000000'): break
+        data = iter(sock.recv(int(length)).decode().split())
+        nh, ne, nb, score = (int(next(data)) for i in range(4))
+        maze = [list(next(data)) for i in range(nh)]
+        hp = (lambda c: 0 if c == 48 else 123 - c)(ord(next(data)))
+        hx, hy, ha = (int(next(data)) for i in range(3))
+        attackable, heal = (bool(int(next(data))) for i in range(2))
 
-    if hp <= 2 and heal:
-        move, attack = 4, 2
-    elif not ne:
-        attack = randrange(3) * (attackable and hp > 2)
-    elif shortest < 160:
-        move, angle, attack = AROUND[round(angle/45 - 0.5) - 4], ha, 2
-    else:
-        attack = 1
-    clientsocket.send('{} {} {}'.format(move, angle, attack).encode())
-clientsocket.close()
+        if nh: move = get_move(maze, move)
+        angle, shortest = ha, inf
+        for i in range(ne):
+            p = 3 - (ord(next(data)) - 97)%3
+            x, y, a = (int(next(data)) for j in range(3))
+            d = ((x - hx)**2 + (y - hy)**2)**0.5
+            if d < shortest:
+                shortest = d
+                b = degrees(atan2(y - hy, x - hx))
+                angle = round(b + 360 if b < 0 else b)
+
+        if hp <= 2 and heal:
+            move, attack = 4, 2
+        elif not ne:
+            attack = randrange(3) * (attackable and hp > 2)
+        elif shortest < 160:
+            move, angle, attack = AROUND[round(angle/45 - 0.5) - 4], ha, 2
+        else:
+            attack = 1
+        sock.send(f'{move} {angle} {attack}'.encode())