summaryrefslogtreecommitdiff
path: root/simple.py
blob: 45f63fa653df9931766b958f1c300925da9fdfab (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
from collections import defaultdict

import random
import robots
from robots.constants import DIRECTIONS

def shuffled(items):
    items = list(items)
    random.shuffle(items)
    return items

def get_enemy_robots(me, players):
    robots = {}
    for name, info in players.items():
        if name != me:
            for x, y in info['robots']:
                robots[x, y] = name
    return robots

def paths_to_enemies(enemies, board, iterations=None):
    width = len(board[0])
    height = len(board)

    if iterations is None:
        iterations = 10
        iterations = width * height

    distances = []
    for y in range(height):
        distances.append([])
        for x in range(width):
            if (x, y) in enemies:
                value = (0, None, (x, y))
            else:
                value = (float('inf'), None, None)
            distances[-1].append(value)

    DIRECTION_ITEMS = shuffled(DIRECTIONS.items())
    for i in range(iterations):
        for y in range(height):
            for x in range(width):
                for move, (dx, dy) in DIRECTION_ITEMS:
                    nx = (x + dx) % width
                    ny = (y + dy) % height
                    if board[ny][nx] == '*':
                        continue

                    current_dist = distances[y][x][0]

                    this_dist, _, dest = distances[ny][nx]
                    this_dist += 1

                    if this_dist < current_dist:
                        distances[y][x] = (this_dist, move, dest)

    return distances

def attacker(whoami, players, board):
    width = len(board[0])
    height = len(board)

    my_robots = players[whoami]['robots']
    enemies = get_enemy_robots(whoami, players)
    paths = paths_to_enemies(enemies, board)

    allocations = defaultdict(list)
    for x, y in my_robots:
        dist, dir, dest = paths[y][x]
        allocations[dest].append((dist, dir, (x, y)))

    searchers = int(len(my_robots) * 0.7)

    assignments = {}
    for options in allocations.values():
        for dist, dir, robot in sorted(options)[:searchers]:
            assignments[robot] = dir

    results = []
    for x, y in my_robots:
        choice = assignments.get((x, y))
        if board[y][x] != whoami and (not choice or random.random() < 0.5):
            choice = 'P'
        elif choice:
            pass
        else:
            moves = []
            for dir, (dx, dy) in DIRECTIONS.items():
                nx = (x + dx) % width
                ny = (y + dy) % height
                if board[ny][nx] != '*':
                    moves.append(dir)
            choice = random.choice(moves or '-')
        results.append(choice)

    return ''.join(results)

def never_paint(whoami, players, board):
    my_robots = players[whoami]['robots']
    return ''.join(
        random.choice('ULD--')
        for _ in range(len(my_robots))
    )

def bot(whoami, state):
    my_robots = state.robots_by_player[whoami]
    return ''.join(
        random.choice('ULDRP-')
        for _ in range(len(my_robots))
    )

if __name__ == '__main__':
#    random.seed(42)
    map_ = robots.border_map(30, 10, 0)
    for y in range(8):
        map_[y][10] = 'X'
    for y in range(11, 2, -1):
        map_[y][20] = 'X'
    map_[5][5] = '1'
    map_[5][15] = '3'
    map_[5][25] = '2'

    for y in (2, 8):
        for x in (5, 15, 25):
            map_[y][x] = '+'

    game = robots.Game(map_)
    game.add_bot(bot, 'Alice')
    game.add_bot(bot, 'Bob')
    game.add_bot(bot, 'Charlie')
    viewer = robots.CursesViewer(game)
    viewer.run()