Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
khaderp, the Rocket Scissors Spacegoo bruteforce bot
import socket, json
import random, pprint
import sys
import math
import re
class arith_list(list):
def __add__(self, other):
return arith_list([x + y for x, y in zip(self, other)])
def __sub__(self, other):
return arith_list([x - y for x, y in zip(self, other)])
def __rmul__(self, other):
return arith_list([x * other for x in self])
class Planet:
def __init__(self, json):
self.player_id = json['owner_id']
self.ships = arith_list(json['ships'])
self.production = arith_list(json['production'])
self.x = json['x']
self.y = json['y']
self.id = json['id']
self.incoming_fleets = []
def __repr__(self):
return "<id {}, own {}, ships {}, prod {}>".format(self.id, self.player_id, self.ships, self.production)
def dist(self, other):
return int(math.ceil(math.sqrt((self.x-other.x)**2 + (self.y-other.y)**2)))
def add_incoming_fleet(self, fleet):
self.incoming_fleets.append(fleet)
def flyto(self, other, ships):
return ("send %s %s %d %d %d" % (self.id, other.id, ships[0], ships[1], ships[2]))
class Fleet:
def __init__(self, json, planets):
self.id = json['id']
self.player_id = json['owner_id']
target_string = json['target']
origin_string = json['origin']
self.target = [planet for planet in planets if planet.id == target_string][0]
self.origin = [planet for planet in planets if planet.id == origin_string][0]
self.ships = arith_list(json['ships'])
self.eta = json['eta']
def can_intercept(self, origin_planet, current_round):
combined_ships = origin_planet.ships
for i in range(0, len(self.target.ships)):
combined_ships[i] += self.target.ships[i]
return (origin_planet.ships[0] > 0 or origin_planet.ships[1] > 0 or origin_planet.ships[2] > 0 ) and origin_planet.dist(self.target) < (self.eta - current_round) and self.battle(self.ships, combined_ships)
def will_conquer_target(self):
return sum(self.battle(self.ships, self.target.ships)[1]) == 0
@staticmethod
def battle(s1,s2):
ships1 = s1[::]
ships2 = s2[::]
while sum(ships1) > 0 and sum(ships2) >0:
new1 = Fleet.battle_round(ships2,ships1)
ships2 = Fleet.battle_round(ships1,ships2)
ships1 = new1
#print ships1,ships2
ships1 = arith_list(map(int,ships1))
ships2 = arith_list(map(int,ships2))
#print ships1,ships2
return ships1, ships2
@staticmethod
def battle_round(attacker,defender):
#nur eine asymmetrische runde. das hier muss mal also zweimal aufrufen.
numships = len(attacker)
defender = defender[::]
for def_type in range(0,numships):
for att_type in range(0,numships):
multiplier = 0.1
absolute = 1
if (def_type-att_type)%numships == 1:
multiplier = 0.25
absolute = 2
if (def_type-att_type)%numships == numships-1:
multiplier = 0.01
defender[def_type] -= (attacker[att_type]*multiplier) + (attacker[att_type] > 0) * absolute
defender[def_type] = max(0,defender[def_type])
return defender
class State:
def __init__(self, json):
self.planets = [Planet(p) for p in json['planets']]
self.fleets = [Fleet(p, self.planets) for p in json['fleets']]
for f in self.fleets:
f.target.add_incoming_fleet(f)
self.player_id = json['player_id']
self.round = json['round']
def my(self, thing):
return thing.player_id == self.player_id
@property
def my_planets(self):
return [p for p in self.planets if self.my(p)]
@property
def neutral_planets(self):
return [p for p in self.planets if p.player_id == 0]
@property
def enemy_planets(self):
return [p for p in self.planets if p.player_id != 0 and not self.my(p)]
def play(user, password, ai):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('spacegoo.gpn.entropia.de', 6000))
io = s.makefile('rw')
def write(data):
io.write('%s\n' % (data,))
io.flush()
write('login %s %s' % (user, password))
elo_diff = 0
while True:
data = io.readline().strip()
if not data:
return
if data[0] == "{":
state = json.loads(data)
if state['winner'] is not None:
break
s = State(state)
s.game_id = game_id
write(ai(s))
print("\r[{}/{}] {} - {} - {} ".format(state['round'], state['max_rounds'],
sum([sum(planet.ships) for planet in s.my_planets]) + sum([sum(fleet.ships) for fleet in s.fleets if
fleet.player_id == s.player_id]),
sum([sum(planet.ships) for planet in s.neutral_planets]),
sum([sum(planet.ships) for planet in s.enemy_planets]) + sum([sum(fleet.ships) for fleet in s.fleets if
not fleet.player_id == s.player_id])),
end='')
elif re.match('command received|welcome|calculating|waiting for', data):
pass
elif re.match('game ended', data):
print()
msg = data.replace('player 1', 'YOU' if s.player_id == 1 else 'enemy')
msg = msg.replace('player 2', 'YOU' if s.player_id == 2 else 'enemy')
print(msg)
m = re.search('(-?\\d+(\\.\\d+)?) ELO', data)
return float(m.group(1)) if m else None
elif re.match('game (\\d+) starts', data):
m = re.match('game (\\d+) starts', data)
game_id = m.group(1)
print(data)
else:
print(data)
#! /usr/bin/env python3
from client import *
import time
import os
# ==== Versionsverwaltung mit vim ====
# 1. Commit: Kommentar im Header hinzufügen
# 2. Revert: Im vim-Undo-Tree nach dem Change suchen, der den Kommentar hunzugefügt hat
# 3. Profit
# 1.0!!!!
# 2.0!!!!
# 530!!!!
# 644!
# 700.
USERNAME = "khaderp"
PASSWORD = "balloonicorn"
f = None
def log(*args):
print(*args, file=f)
def maxby(xs):
m = (None,None)
for x in xs:
if m[0] is None or x[0] > m[0]:
m = x
return m[1]
def simulate(state, p, add, ships=None):
"""
Simulate production of and fights on 'p' including all incoming
fleets plus all fleets in 'add'.
Returns player's win to loss in ships minus the enemy's ship delta.
"""
incoming =\
[(f.eta, f.ships, f.player_id) for f in p.incoming_fleets] +\
[(state.round + q.dist(p), ships, state.player_id) for q, ships in add]
incoming.sort(key=lambda f: f[0])
incoming.append((state.round + 50, None, None))
now = state.round
owner = p.player_id
ships = ships or p.ships
delta = [0, 0, 0]
for eta, iships, iowner in incoming:
if owner != 0:
ships = ships + (eta - now) * p.production
delta[owner] += sum((eta - now) * p.production)
if iowner == None:
break
if owner == iowner:
ships = ships + iships
else:
ships2, iships2 = Fleet.battle(ships, iships)
delta[owner] -= sum(ships) - sum(ships2)
delta[iowner] -= sum(iships) - sum(iships2)
if sum(ships2) == 0:
ships = iships2
owner = iowner
else:
ships = ships2
now = eta
#log(delta)
return delta[state.player_id] - delta[1 if state.player_id == 2 else 2]
def shipments(ships):
""" Try some combinations of ships to be sent to attack """
r = [0.0, 1.0]
for a in r:
for b in r:
for c in r:
yield arith_list([a* ships[0], b* ships[1], c* ships[2]])
def round(state):
#global f
#if not os.path.exists('logs/{}'.format(state.game_id)):
# try:
# os.mkdir('logs/{}'.format(state.game_id))
# except: pass
#f = open('logs/{}/{}'.format(state.game_id, state.round), 'w')
my_fleet = \
sum([sum(planet.ships) for planet in state.my_planets]) + sum([sum(fleet.ships) for fleet in state.fleets if
fleet.player_id == state.player_id])
your_fleet = \
(sum([sum(planet.ships) for planet in state.enemy_planets]) + sum([sum(fleet.ships) for fleet in state.fleets if not fleet.player_id == state.player_id]))
def scores():
""" for each possible move compute the score difference between executing it and nopping """
old_ds = [(simulate(state, p, []), p) for p in state.my_planets]
old_as = [(simulate(state, q, []), q) for q in state.planets]
for old_d, p in old_ds:
for old_a, q in old_as:
if q != p:
#log(p, q)
#old_d = simulate(state, p, [])
#old_a = simulate(state, q, [])
for ships in shipments(p.ships):
new_d = simulate(state, p, [], p.ships - ships)
new_a = simulate(state, q, [(p, ships)])
score = new_a - old_a + new_d - old_d
yield score, (p, q, ships)
sc = list(scores())
#log("I AM", state.player_id)
#for s in sorted(sc, key=lambda s:s[0]):
#log(s)
if not sc:
#log("nop")
return "nop"
source, target, ships = maxby(sc)
#log("old_d:", simulate(state, source, []))
#log("old_a:", simulate(state, target, []))
#log("new_d:", simulate(state, source, [], source.ships - ships))
#log("new_a:", simulate(state, target, [(source, ships)]))
#log(source.flyto(target, ships))
return source.flyto(target, ships)
elo_diff = 0
while True:
d2 = play(USERNAME, PASSWORD, round)
if d2:
elo_diff += d2
print("elo_diff: {:.2f}".format(elo_diff))
time.sleep(3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.