#side Active 6 #author Warren #color f08 #seed 2 1 1 1 1 1 Changes from version 5 to 6 include: * Constructors are now in a separate type * Better missiles from Walled City (20021231) Improved eat-and-move copied from haystack. (Devon 20030104) Only make missiles when populous. (20030502) Shorter range, and more energy storage. More cautious about crusades, and more prone to running away. More position slop. Added decorations. (Devon 20030627) Switched to shieldless missiles. (Warren 2006 0314) Made constructor and fighter/gatherer separate types A predator with active dodging. Does badly against missiles and short-ranged enemies. #code ;;;;;;;; Shared code block ;;;;;;;;;;;;; ;message-passing channels #const TARGET_CHANNEL 1 #const HUNGRY_CHANNEL 7 #const FIGHTER_TYPE 1 #const PREGNANT_TYPE 2 #const MISSILE_TYPE 3 #const FOOD_CLAIM_BASE 1 #const NUM_FOOD_CLAIMS 100 #const FOOD_CLAIM_SIZE 2 ;So 1-200 are food claims ;;;;;; END Shared code ;;;;;; #type Dodger #decoration fcc cross #color fff #hardware energy 500 100 armor 200 processor 35 ;to dodge in 2 frames radio send receive eater 1.8 engine 0.15 robot-sensor 10 2 shot-sensor 7 4 food-sensor 8 5 ;;constructor 0.9 repair-rate 0.05 grenades 35 9 25 ;blaster 0.1 5 3 syphon 1 10 #code ;communication with Dodge-and-move: #vector desired-velocity 0 0 #var speed-slop 0.01 ;communication with Eat-and-move: #var position-slop 3 #vector desired-position ;Feeding #vector hungry-position #var hungry-time -999 #var hungry-energy-wanted 10 random-position: 0 world-width random 0 world-height random return ;returns distance to nearest wall wall-distance: ; -> dist position min world-size position v- min min return ;food-sense: ;t -> ;food-sensor-time food-sensor-time -1000 ifev + time < if ; ;too old ; fire-food-sensor sync ; return ;else return ;previous sensing is new enough ;then restrict-location: ;x y -> x y world-height min 0 max swap world-width min 0 max swap return ;based vaguely on tutorial food-hashing code from Frog Celestial #var food-hash #var food-y claim-food: ;#const FOOD_CLAIM_BASE 1 ;#const NUM_FOOD_CLAIMS 100 ;first time, then y food-position food-y! world-width / ;stack: between 0 and 1 NUM_FOOD_CLAIMS * floor ;stack: probably between 0 inclusive and NUM_FOOD_CLAIMS exclusive 0 max NUM_FOOD_CLAIMS 1 - min FOOD_CLAIM_SIZE * FOOD_CLAIM_BASE + food-hash! sync food-hash read dup 0 > swap time 300 - > and if ;valid time claim already 0 ;TODO: check y else ;claim expired time food-hash write food-y food-hash 1 + write 1 then return feed-hungry: ;;HUNGRY_CHANNEL messages 5 - 0 max 0 random-int TARGET_CHANNEL skip-messages do HUNGRY_CHANNEL receive while ;stack: x y energy time 2swap 2dup position syphon-range in-range if hungry-position! hungry-time! hungry-energy-wanted! else 2drop 2drop then loop hungry-position position syphon-range in-range if energy max-energy 0.4 * > and-if syphon-max-rate negate syphon-rate! hungry-position position v- rect-to-polar syphon-direction! syphon-distance! else 0 syphon-rate! then return ;in: desired-position, position-slop ;out: desired-velocity, speed-slop #vector current-food #var have-current-food 0 #const MAX_SPEED 0.15 #vector wander-loc #var wander-time eat-and-move: ;check if current food is ok have-current-food if current-food desired-position position-slop in-range if position current-food radius in-range not eaten or and-if ;current food is ok else 0 have-current-food! then then feed-hungry& call have-current-food not if food-sensor-time 25 + time < and-if position-slop 0.5 > and-if ;don't waste sensor firing if pos-slop tiny desired-position position position-slop in-range and-if desired-position position-slop food-sensor-range min 0.5 * random-angle polar-to-rect v+ ;add a little randomness position v- rect-to-polar food-sensor-focus-direction! food-sensor-focus-distance! fire-food-sensor sync food-found if Food-check-loop: food-position desired-position dist position-slop < if claim-food& call and-if food-position current-food! 1 have-current-food! else next-food Food-check-loop& ifg then then ;food-found then ;time to fire have-current-food if current-food else position-slop food-sensor-range > if ;no point wandering if we can see it already energy 20 > and-if desired-position wander-loc dist position-slop > wander-loc position 2 in-range wander-time 400 + time < or or if position-slop population sqrt 4 * 8 + min random-angle polar-to-rect desired-position v+ restrict-location^ wander-loc! time wander-time! then wander-loc else desired-position then then position v- rect-to-polar swap 0.05 * MAX_SPEED min swap polar-to-rect desired-velocity! radius 0.05 * speed-slop! return ;end of eat-and-move #start random-position wander-loc! #const MAX_FIGHT_POSITION_SLOP 3 #const MIN_FIGHT_POSITION_SLOP 0 #const FIGHT_DISTANCE 7.3 #const CRUSADE_DIST 25 #const MIN_CRUSADE_DIST 12 #var have-crusade 0 #var crusade-time #vector crusade-position Begin-normaling: do energy max-energy / 0.2 > No-target& nifg robot-sensor-time grenades-reload-time + time < if fire-robot-sensor sync robot-found if armor max-armor < if robot-position robot-sensor-time 3 TARGET_CHANNEL send then grenades-cooldown nif robot-position position v- robot-velocity time robot-sensor-time - vs* v+ ;stack: current relative position of enemy robot-velocity velocity v- robot-distance grenades-speed / vs* v+ rect-to-polar fire-grenade then position robot-position v- unitize FIGHT_DISTANCE vs* robot-position v+ desired-position! MAX_FIGHT_POSITION_SLOP energy max-energy / MAX_FIGHT_POSITION_SLOP MIN_FIGHT_POSITION_SLOP - * - position-slop! Done-targeting& jump else ;no robot found No-target& jump then ;found else Done-targeting& jump then ;time to fire No-target: have-crusade if crusade-position position robot-sensor-range 0.8 * in-range time crusade-time - 200 > or and-if 0 have-crusade! then have-crusade nif shot-found and-if shot-velocity norm and-if shot-position shot-velocity -100 vs* v+ crusade-position! shot-sensor-time crusade-time! 1 have-crusade! then have-crusade nif TARGET_CHANNEL messages 2 - 0 max 0 random-int TARGET_CHANNEL skip-messages do TARGET_CHANNEL receive while ;stack: x y t crusade-time! crusade-position! time crusade-time - 100 < if ;newish crusade-position position dist CRUSADE_DIST < and-if crusade-position position dist MIN_CRUSADE_DIST > and-if 1 have-crusade! done-chatting& jump then ;acceptable crusade loop Done-chatting: then ;have-crusade not have-crusade if energy max-energy / 0.3 > and-if armor max-armor / 0.6 > and-if ;;;constructor-type not constructor-remaining 200 > or and-if crusade-position desired-position! 5 position-slop! else infinity position-slop! hungry-position desired-position! then ;have crusade Done-targeting: ;;jump here if we have a target Dodge-and-move^ energy 100 > max-repair-rate 0 ifev repair-rate! ;construct code was here eat-and-move^ Dodge-and-move^ shot-found if ;run away ; shot-velocity norm and-if energy max-energy / 0.05 > and-if energy max-energy / 0.2 < armor max-armor / 0.45 < or and-if ;hungry-position position 10 in-range if ; shot-velocity 60 vs* position v+ restrict-location^ desired-position! ;else hungry-position desired-position! ;then Begin-running& jump then have-crusade nif energy max-energy 0.97 * > if hungry-position position hungry-position v- unitize 5 vs* v+ desired-position! Begin-running& jump then then forever ;desired-position is set before entering running ;This is used for two purposes: running from danger and running home to food Begin-running: do energy 100 > max-repair-rate 0 ifev repair-rate! energy max-energy / 0.2 < nif robot-sensor-time grenades-reload-time + time < and-if grenades-cooldown not and-if fire-robot-sensor sync robot-found and-if robot-position position v- robot-velocity time robot-sensor-time - vs* v+ ;stack: current relative position of enemy robot-velocity velocity v- robot-distance grenades-speed / vs* v+ rect-to-polar fire-grenade then ;shooting 5 position-slop! eat-and-move^ Dodge-and-move^ desired-position position dist position-slop < if energy max-energy 0.5 * < and-if Begin-normaling& jump then forever #const Flee-angle 1.5 ;angle between shot velocity and fleeing. #const MIN_MISS_DIST 2.5 #const flee-speed 0.1 #const ASSUMED_ROBOT_SLOWDOWN_FACTOR 0.4 #const DODGE_OVERKILL_FACTOR 1.2 #var miss #vector dv #vector assumed-robot-velocity #vector go-dir #var last-danger-time -500 ;Dodge has inputs: ;-desired-velocity, the desired medium-term engine velocity ;-speed-slop, the amount the velocity can differ before engine is used ;Dodge then sets engine-velocity and power to avoid shots. Dodge-and-move: time last-danger-time 100 + > if shot-sensor-time 30 + time > and-if Obey-user& jump then do shot-sensor-time time 4 - < until sync loop ;do as much computation as possible before firing shot sensor to get up-to-date info energy max-energy / 2 * ; armor max-armor = 1 2 ifev * time shot-sensor-time - 20 / + energy max-energy / 6 * min armor max-armor / < Obey-user& ifg velocity ASSUMED_ROBOT_SLOWDOWN_FACTOR vs* 2dup desired-velocity dist 0.05 <= if 2drop desired-velocity else 2dup desired-velocity v- unitize -0.05 vs* v+ ;expected velocity then assumed-robot-velocity! assumed-robot-velocity rect-to-polar shot-sensor-focus-direction! 3 * shot-sensor-focus-distance! fire-shot-sensor sync shot-found Obey-User& nifg time last-danger-time! ;;;;;;;;; shot-process-loop: shot-velocity norm 2 < if ;don't dodge super-fast shots such as force fields shot-velocity assumed-robot-velocity v- dv! dv shot-position position v- dot 0 < and-if else next-shot shot-process-loop& obey-user& ifeg then dv unitize shot-position position v- cross miss! ;positive means the shot will miss to our right (when facing the incoming shot) dv angle miss 0 > Flee-angle Flee-angle negate ifev - dup 1 swap polar-to-rect go-dir! MIN_MISS_DIST miss abs - 0 max ;dist to move shot-distance 3 max / shot-velocity norm * DODGE_OVERKILL_FACTOR * ;this line: flee speed swap polar-to-rect assumed-robot-velocity v+ 2dup ;2 copies of engine-vel on stack desired-velocity v- go-dir dot ;negative if desired deviation from calculated is ok 0 < if 2drop Obey-User& jump then ;2dup angle fire-blaster engine-velocity! engine-max-power engine-power! return Obey-User: desired-velocity engine-velocity! velocity desired-velocity v- norm speed-slop < 0 engine-max-power ifev engine-power! return ;end of Dodge subroutine #comment ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Constructor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #type HouseHusband #decoration fcc cross #color 0f0 #hardware energy 600 0.5 armor 250 processor 4 radio send receive ;engine 0.15 constructor 2.5 solar-cells 0.22 repair-rate 0.1 #code #var last-birth-time -1 #var baby-cost #start constructor-type if ;;seeded with fetus time last-birth-time! constructor-remaining baby-cost! ;;;hack then #var last-cry-time -999 do time last-cry-time - energy 50 + > if position max-energy energy - time 4 HUNGRY_CHANNEL send time last-cry-time! then max-repair-rate repair-rate! constructor-type nif population 25 > 0.05 random-bool and if MISSILE_TYPE constructor-type! else last-birth-time 0 < if ;newly born, make a fighter FIGHTER_TYPE constructor-type! else ;base type on how long it's taken us to reproduce baby-cost time last-birth-time - / ;stack: average power consumption #var power-consumption dup power-consumption! constructor-max-rate 0.8 * < FIGHTER_TYPE PREGNANT_TYPE ifev constructor-type! then then constructor-remaining baby-cost! ;;;hack time last-birth-time! then max-energy 0.03 * energy < constructor-max-rate 0 ifev constructor-rate! forever ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MISSILE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #type Boom A missile that's better at purposefully massacring civilians. (Sides may eventually get fancy enough to support a notion of that being unethical, but that won't happen for a long time.) Its strategy: 1) Don't automatically chase any enemies seen. Instead, wait until a certain mass of enemy is seen, getting more tolerant of smaller numbers of enemies as our energy and armor decrease. #decoration fcc dot #color f00 #hardware energy 300 300 armor 300 processor 30 radio send receive engine 0.2 robot-sensor 12 12 ;shot-sensor 7 4 bomb 1100 #code #vector danger-position #var danger-time -1000 recent-danger: ;-- bool time danger-time 50 + < return #var exploring 1 #var expected-damage 0 #var max-expected-damage #vector wander-loc #var total-mass-seen targetable-robot-found: ;returns 1 if an ok target is found, 0 otherwise. Leaves robot cursor on target. robot-found if do robot-shield-fraction 0.3 > if 1 return then next-robot while-loop then 0 return #const edge-space 4 ;this subroutine copied from eventually 12 (via Untouchable 4 and Walled City) random-edge-position: 0 1 random-int if 0 1 random-int edge-space world-width edge-space - ifev edge-space world-height edge-space - random else edge-space world-width edge-space - random 0 1 random-int edge-space world-height edge-space - ifev then return new-wander-loc: random-edge-position^ wander-loc! return #vector robots-center #var importance #var max-expected-damage-time #const EXPL_RADIUS 6 #start new-wander-loc^ do time robot-sensor-time exploring 40 15 ifev + > if fire-robot-sensor sync robot-found if 0 0 robots-center! 0 expected-damage! 0 importance! 0 ;mass - leave on stack do robot-mass + 1 robot-distance EXPL_RADIUS / - 0 max robot-mass * expected-damage + expected-damage! robot-position robot-mass robot-distance EXPL_RADIUS < 1 0.1 ifev * ;stack: mass-accum, robot-position, robot-importance dup importance + importance! vs* robots-center v+ robots-center! next-robot while-loop total-mass-seen! robots-center importance vs/ robots-center! energy max-energy / armor max-armor / min exploring 120 80 ifev * total-mass-seen < if 0 exploring! else 1 exploring! then expected-damage 50 > if max-expected-damage 0.8 * expected-damage > time max-expected-damage-time 200 + > or and-if die sync then max-expected-damage expected-damage < if expected-damage max-expected-damage! time max-expected-damage-time! then then then exploring if wander-loc position 5 in-range if new-wander-loc^ then wander-loc position v- unitize 0.15 vs* engine-velocity! else robots-center seek-location ;0.3 robot-direction-overall polar-to-rect engine-velocity! ;;TODO: this is a terrible place to go towards. then engine-max-power engine-power! sync sync ;save CPU forever #end