Skip to content

Instantly share code, notes, and snippets.

@Kha
Created June 2, 2013 11:22
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 Kha/5693348 to your computer and use it in GitHub Desktop.
Save Kha/5693348 to your computer and use it in GitHub Desktop.
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