public
Created

khaderp, the Rocket Scissors Spacegoo bruteforce bot

  • Download Gist
client.py
Python
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
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)
khaderp.py
Python
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
#! /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)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.