73 lines
2.5 KiB
Python
Executable File
73 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from contextlib import closing, suppress
|
|
from math import atan2, degrees, inf
|
|
from random import randrange, shuffle
|
|
from socket import socket
|
|
|
|
AROUND = [5, 2, 1, 0, 3, 6, 7, 8]
|
|
|
|
|
|
def get_moves(y, x):
|
|
"""Return tuple of encoded moves."""
|
|
return ((y - 1, x - 1), (y - 1, x), (y - 1, x + 1), # noqa
|
|
(y, x - 1), (y, x), (y, x + 1), # noqa
|
|
(y + 1, x - 1), (y + 1, x), (y + 1, x + 1)) # noqa
|
|
|
|
|
|
def is_wall(maze, y, x):
|
|
"""Return weather the cell (x, y) is wall."""
|
|
return maze[y][x] != '0'
|
|
|
|
|
|
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
|
|
|
|
|
|
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 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())
|