Created
October 25, 2023 13:25
-
-
Save Robbe7730/0331e621a29724f71b3ac1a8751924c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import json | |
import random | |
import math | |
def debug(msg): | |
print(f"{turn_count} {msg}", file=sys.stderr, flush=True) | |
unions = {} | |
targets_at_war = set() | |
targets = {} | |
turn_count = 0 | |
def calculate_distance(planet_a, planet_b): | |
return ( | |
(planet_a["x"] - planet_b["x"]) ** 2 + | |
(planet_a["y"] - planet_b["y"]) ** 2 | |
) ** 0.5 | |
def calculate_defending_ships_on_arrival(source_planet, target_planet): | |
# TODO: air support | |
distance = calculate_distance(source_planet, target_planet) | |
ships_gained = int(distance) * (0 if target_planet["owner"] == None else 1) | |
return target_planet["ship_count"] + ships_gained | |
def calculate_ships_ready_to_fire(state, planet): | |
# Dit is niet helemaal proper, want als meerdere expeditites onderweg zijn gaat hij niet genoeg kunnen bijmaken | |
inbound_ships_enemy_turns = sum([ | |
max(0, e["ship_count"] - e["turns_remaining"]) | |
for e in state["expeditions"] | |
if e["destination"] == planet["name"] and e["owner"] != 1 | |
]) | |
return planet["ship_count"] - inbound_ships_enemy_turns - 1 | |
def find_target(planet, other_planets): | |
# Find a juicy new target | |
best_target = None | |
best_target_score = float('inf') | |
planet_name = planet["name"] | |
for possible_target in other_planets.values(): | |
distance = ( | |
(planet["x"] - possible_target["x"]) ** 2 + | |
(planet["y"] - possible_target["y"]) ** 2 | |
) ** 0.5 | |
current_ships = possible_target["ship_count"] | |
ships_gained = int(distance) * (0 if possible_target["owner"] == None else 1) | |
score = (current_ships + ships_gained) * distance | |
if score < best_target_score: | |
best_target = possible_target | |
best_target_score = score | |
best_target_name = best_target["name"] | |
if best_target_name not in unions: | |
unions[best_target_name] = set() | |
unions[best_target_name].add(planet_name) | |
targets[planet_name] = best_target_name | |
debug(f"<{planet_name}> I'm watching you, {best_target_name} 👀") | |
def get_moves(state): | |
global turn_count | |
moves = [] | |
my_planets = {p["name"]:p for p in state['planets'] if p['owner'] == 1} | |
other_planets = {p["name"]:p for p in state['planets'] if p['owner'] != 1} | |
if not other_planets or not my_planets: | |
return [] | |
# ----- REORGANIZE ----- | |
# Make sure we don't target our own planets | |
for planet in my_planets: | |
if planet in unions: | |
for member in unions[planet]: | |
del targets[member] | |
del unions[planet] | |
if planet in targets_at_war: | |
targets_at_war.remove(planet) | |
# Make sure there are no traitors | |
for other_planet in other_planets: | |
for target in unions: | |
if other_planet in unions[target]: | |
unions[target].remove(other_planet) | |
if other_planet in targets: | |
del targets[other_planet] | |
# ----- FIND A TARGET ----- | |
for planet_name, planet in my_planets.items(): | |
if planet_name not in targets: | |
find_target(planet, other_planets) | |
# ----- UNIONIZE ----- | |
for target, members in unions.items(): | |
target_planet = other_planets[target] | |
# Check if we can go to war | |
for member in members: | |
member_planet = my_planets[member] | |
defending_ships = calculate_defending_ships_on_arrival(member_planet, target_planet) | |
ships_ready_to_fire = calculate_ships_ready_to_fire(state, member_planet) | |
if defending_ships < ships_ready_to_fire: | |
debug(f"<{member}> Union Against {target}, ATTACK 🔫") | |
targets_at_war.add(target) | |
moves.append({ | |
'origin': member, | |
'destination': target, | |
'ship_count': defending_ships # No +1 as we send one in the "Support troops" step as well | |
}) | |
break | |
# Support troops | |
if target in targets_at_war: | |
# If we're at war, send our support to the battlefield | |
for member in members: | |
if calculate_ships_ready_to_fire(state, my_planets[member]) > 1: | |
moves.append({ | |
'origin': member, | |
'destination': target, | |
'ship_count': 1 | |
}) | |
else: | |
for member in members: | |
# If we're not at war, send our support to the closest planet in the union that is closer to the target | |
member_planet = my_planets[member] | |
member_target_distance = calculate_distance(member_planet, target_planet) | |
closest_planet = None | |
closest_planet_distance = float('inf') | |
for other_member in members: | |
other_member_planet = my_planets[other_member] | |
if other_member == member or calculate_distance(target_planet, other_member_planet) >= member_target_distance: | |
continue | |
distance = calculate_distance(member_planet, other_member_planet) | |
if distance < closest_planet_distance: | |
closest_planet = other_member_planet | |
closest_planet_distance = distance | |
if closest_planet != None and calculate_ships_ready_to_fire(state, member_planet) > 1: | |
moves.append({ | |
'origin': member, | |
'destination': closest_planet["name"], | |
'ship_count': 1 | |
}) | |
turn_count += 1 | |
return moves | |
random.seed(1337) | |
for line in sys.stdin: | |
print(json.dumps({ 'moves': get_moves(json.loads(line)) }), flush=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment