Last active
December 16, 2015 04:19
-
-
Save staydecent/47b92ddf2796801b6cc6 to your computer and use it in GitHub Desktop.
This file contains 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
# | |
# The Churros | |
# by @staydecent | |
# | |
# combo of some fine open-source species, | |
# with some of the custom Dormant Penguin love | |
# | |
speed_change_fear = 60.0 | |
my_start_pos = null | |
min_tot_weight = .07 | |
aggressiveness = 6 | |
threat_thresh = 2 | |
ai.step = (o) -> | |
threats = get_threats(o) | |
{new_target, label} = find_ideal_position(o, threats) | |
{torque, thrust} = o.lib.targeting.simpleTarget(o.me, new_target) | |
if threats[0].threat_factor < threat_thresh | |
thrust = 1.0 | |
console.log(threats[0].threat_factor) | |
else | |
thrust *= aggressiveness | |
return { torque, thrust, label } | |
get_threats = (o) -> | |
threats = [] | |
# nearest moon | |
threats.push { | |
pos: o.moons[0].pos | |
vel: o.moons[0].vel | |
dist: o.moons[0].dist - o.moons[0].radius # the surface of the moon | |
type: 'moon' | |
} | |
# nearest ship | |
for s in o.ships | |
sType = if s.friendly and s.queen | |
'friendly_queen' | |
else if !s.friendly and s.queen | |
'enemy_queen' | |
else if s.friendly | |
'friendly_ship' | |
else | |
'enemy_ship' | |
if sType is 'enemy_queen' | |
#speed_change_fear = 100 | |
aggressiveness = 1 | |
if o.ships.length == 1 | |
aggressiveness = 10 | |
threats.push { | |
pos: s.pos | |
dist: s.dist | |
vel: s.vel | |
type: sType | |
} | |
# nearest edge of board | |
[radius, angle] = o.lib.vec.toPolar o.me.pos | |
edge = o.lib.vec.fromPolar [o.game.moon_field, angle] | |
threats.push { | |
pos: edge | |
dist: o.lib.vec.dist o.me.pos, edge | |
vel: [0,0] | |
type: 'edge' | |
} | |
# edge of board heading towards | |
exit = get_board_exit_pos o | |
threats.push { | |
pos: exit | |
dist: o.lib.vec.dist o.me.pos, exit | |
vel: [0,0] | |
type: 'exit' | |
} | |
# where I started, so I disperse | |
if not my_start_pos? then my_start_pos = o.me.pos | |
threats.push { | |
pos: my_start_pos | |
dist: o.lib.vec.dist o.me.pos, my_start_pos | |
vel: [0,0] | |
type: 'start_pos' | |
} | |
# now for each threat, figure out some more stuff | |
for t in threats | |
t.rel_vel = o.lib.vec.diff(o.me.vel, t.vel) | |
t.speed_toward = o.lib.physics.speedToward(t.rel_vel, o.me.pos, t.pos) + speed_change_fear | |
t.time_threat = if t.speed_toward > 0 then t.dist / t.speed_toward else Infinity | |
t.threat_factor = threat_factor(t, aggressiveness) | |
threats.sort (a,b) -> b.threat_factor - a.threat_factor | |
threat_factor = (t, a) -> | |
res = 1 / t.time_threat | |
res = res * res | |
if t.type is "moon" then res *= 12 # moons also suck us in | |
else if t.type is "moonsCentre" then res *= 3 | |
else if t.type is "friendly_queen" then res /= 6 | |
else if t.type is "enemy_ship" then res /= 8*a # hitting a ship isn't the end of the world | |
else if t.type is "friendly_ship" then res /= 20*a # hitting a ship isn't the end of the world | |
else if t.type is "start_pos" then res = 0 | |
else if t.type is "enemy_queen" then res = -1 | |
return res | |
find_ideal_position = (o, threats) -> | |
total_weight = 0 | |
target = [0,0] | |
label = null | |
for t in threats | |
# chill | |
if t.threat_factor != -1 | |
target_diff = o.lib.vec.diff(o.me.pos, t.pos) | |
n_diff = o.lib.vec.normalized(target_diff) | |
diff = o.lib.vec.times(n_diff, t.threat_factor) | |
# attack | |
else if t.dist < 25 and !o.me.queen | |
target_diff = o.lib.vec.diff(t.pos, o.me.pos) | |
n_diff = o.lib.vec.normalized(target_diff) | |
diff = o.lib.vec.times(n_diff, aggressiveness) | |
return { | |
new_target: o.lib.vec.sum(o.me.pos, diff) | |
label: "attack!" | |
} | |
# still chill | |
else | |
target_diff = o.lib.vec.diff(o.me.pos, t.pos) | |
n_diff = o.lib.vec.normalized(target_diff) | |
diff = o.lib.vec.times(n_diff, t.threat_factor) | |
total_weight += t.threat_factor | |
target[0] += diff[0] | |
target[1] += diff[1] | |
if total_weight < min_tot_weight | |
total_weight = min_tot_weight | |
target[0] /= total_weight | |
target[1] /= total_weight | |
return { | |
new_target: o.lib.vec.sum(o.me.pos, target) | |
label: label | |
} | |
get_board_exit_pos = (o) -> | |
t = 0 | |
dt = 0.05 | |
ddt = 0.025 | |
maxt = 10 | |
[vx,vy] = o.me.vel | |
[px,py] = o.me.pos | |
rad_sq = o.game.moon_field * o.game.moon_field | |
while (t < maxt) and (px * px + py * py < rad_sq) | |
t += dt | |
px += vx * dt | |
py += vy * dt | |
dt += ddt | |
return [px,py] | |
get_moons_centre = (o) -> | |
moonsLen = o.moons.length | |
centerX = 0 | |
centerY = 0 | |
for m in o.moons | |
centerX += m.pos[0] | |
centerY += m.pos[1] | |
return [ | |
centerX / moonsLen, | |
centerY / moonsLen | |
] | |
### | |
Return the firing solution for a projectile starting at 'src' with | |
velocity 'v', to hit a target, 'dst'. | |
@param Vector src position of shooter | |
@param Vector pos position of target | |
@param Vector vel velocity of target | |
@param Scalar v speed of projectile | |
@return Vector Coordinate at which to fire (and where intercept occurs) | |
E.g. | |
>>> intercept([2, 4], [5, 7], [2, 1], 5) | |
= [8, 8.5] | |
### | |
intercept = (src, pos, vel, v) -> | |
tx = pos[0] - src[0] | |
ty = pos[1] - src[1] | |
tvx = vel[0] | |
tvy = vel[1] | |
# Get quadratic equation components | |
a = tvx * tvx + tvy * tvy - v * v | |
b = 2 * (tvx * tx + tvy * ty) | |
c = tx * tx + ty * ty | |
# Solve quadratic | |
ts = quad(a, b, c) # See quad(), below | |
# Find smallest positive solution | |
sol = null | |
if ts | |
t0 = ts[0] | |
t1 = ts[1] | |
t = Math.min(t0, t1) | |
t = Math.max(t0, t1) if t < 0 | |
if t > 0 | |
sol = [ | |
dst.x + dst.vx * t, | |
dst.y + dst.vy * t | |
] | |
return sol | |
### | |
Return solutions for quadratic | |
### | |
quad = (a, b, c) -> | |
sol = null | |
if Math.abs(a) < 1e-6 | |
if Math.abs(b) < 1e-6 | |
sol = (if Math.abs(c) < 1e-6 then [0, 0] else null) | |
else | |
sol = [-c / b, -c / b] | |
else | |
disc = b * b - 4 * a * c | |
if disc >= 0 | |
disc = Math.sqrt(disc) | |
a = 2 * a | |
sol = [(-b - disc) / a, (-b + disc) / a] | |
return sol | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment