Skip to content

Instantly share code, notes, and snippets.

@staydecent
Last active December 16, 2015 04:19
Show Gist options
  • Save staydecent/47b92ddf2796801b6cc6 to your computer and use it in GitHub Desktop.
Save staydecent/47b92ddf2796801b6cc6 to your computer and use it in GitHub Desktop.
#
# 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