Skip to content

Instantly share code, notes, and snippets.

@Robbe7730
Created October 25, 2023 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Robbe7730/0331e621a29724f71b3ac1a8751924c6 to your computer and use it in GitHub Desktop.
Save Robbe7730/0331e621a29724f71b3ac1a8751924c6 to your computer and use it in GitHub Desktop.
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