|
| 1 | +(* This is the legacy version of sniper |
| 2 | + that uses repeated decrement, which is pretty dumb. *) |
| 3 | +structure Sniper :> DOMINATOR = |
| 4 | +struct |
| 5 | + structure GS = GameState |
| 6 | + datatype src = datatype Kompiler.src |
| 7 | + datatype dosturn = datatype DOS.dosturn |
| 8 | + |
| 9 | + structure EP = EmitProgram |
| 10 | + |
| 11 | + infix 9 -- |
| 12 | + val op -- = Apply |
| 13 | + val $ = Var |
| 14 | + fun \ x exp = Lambda (x, exp) |
| 15 | + infixr 1 ` |
| 16 | + fun a ` b = a b |
| 17 | + |
| 18 | + datatype mode = |
| 19 | + (* First need to create the gun program, which never changes. *) |
| 20 | + CreateGun |
| 21 | + (* Once the program is in place, find a target and put it in target_slot. *) |
| 22 | + | BuildingGun of { status : EP.status ref, gun_slot : int, target_slot : int } |
| 23 | + (* We loop between the following two for the rest of time. We could consider |
| 24 | + making a new gun, but the current strategy is to hope for the medic to |
| 25 | + save us. *) |
| 26 | + | FindTarget of { gun_slot : int, target_slot : int } |
| 27 | + (* Now keep attacking until it's dead, or something happens to our |
| 28 | + equipment. *) |
| 29 | + | Attacking of { status : EP.status ref, |
| 30 | + shots : int ref, |
| 31 | + (* Slot containing the gun. *) |
| 32 | + gun_slot : int, |
| 33 | + (* Slot containing the index of |
| 34 | + the target, which is referred |
| 35 | + to by gun_slot. *) |
| 36 | + target_slot : int, |
| 37 | + target : int } |
| 38 | + |
| 39 | + val compare_scores = ListUtil.bysecond Real.compare |
| 40 | + |
| 41 | + val lastmsg = ref "" |
| 42 | + val eprint = |
| 43 | + fn s => if s = !lastmsg |
| 44 | + then () |
| 45 | + else (eprint ("[SNIPER] " ^ s ^ "\n"); lastmsg := s) |
| 46 | + |
| 47 | + fun create () = |
| 48 | + let |
| 49 | + |
| 50 | + (* Maybe should have a lower bound on what it will |
| 51 | + consider valuable, and reduce priority if there |
| 52 | + are no current high-value targets. *) |
| 53 | + |
| 54 | + (* Makes a program that attacks the target slot index, |
| 55 | + and then returns itself (so it sticks around). *) |
| 56 | + fun attackprogram target_slot prog_slot = |
| 57 | + let |
| 58 | + fun repeat 1 e = e |
| 59 | + | repeat n e = repeat (n - 1) e -- e |
| 60 | + |
| 61 | + val dec = |
| 62 | + (\"target" ` |
| 63 | + (* empirical. Attack is MUCH more efficient. |
| 64 | + Should use attack. *) |
| 65 | + repeat 100 (Card LTG.Dec -- $"target")) -- |
| 66 | + (Card LTG.Get -- Int target_slot) |
| 67 | + |
| 68 | + val prog = Kompiler.run_and_return_self dec |
| 69 | + in |
| 70 | + eprint (Kompiler.src2str prog); |
| 71 | + Kompiler.compile prog prog_slot |
| 72 | + end handle (e as Kompiler.Kompiler s) => |
| 73 | + let in |
| 74 | + eprint ("Kompilation failed: " ^ s ^ "\n"); |
| 75 | + raise e |
| 76 | + end |
| 77 | + |
| 78 | + fun preview dos = () |
| 79 | + |
| 80 | + (* This is just for diagnostics. *) |
| 81 | + val was_stuck = ref false |
| 82 | + |
| 83 | + val mode = ref CreateGun |
| 84 | + fun taketurn dos = |
| 85 | + let val gs = DOS.gamestate dos |
| 86 | + in |
| 87 | + case !mode of |
| 88 | + CreateGun => |
| 89 | + (case (DOS.reserve_slot dos, DOS.reserve_addressable_slot dos) of |
| 90 | + (NONE, NONE) => DOS.Can'tRun |
| 91 | + | (NONE, SOME s) => (DOS.release_slot dos s; DOS.Can'tRun) |
| 92 | + | (SOME s, NONE) => (DOS.release_slot dos s; DOS.Can'tRun) |
| 93 | + | (SOME gun_slot, SOME target_slot) => |
| 94 | + let |
| 95 | + val prog = attackprogram target_slot gun_slot |
| 96 | + val (stat, child_pid) = EP.emitspawn dos prog |
| 97 | + in |
| 98 | + eprint ("Assembling gun in: " ^ Int.toString gun_slot ^ |
| 99 | + " reading from: " ^ Int.toString target_slot ^ |
| 100 | + " Program length: " ^ Int.toString (length prog)); |
| 101 | + mode := BuildingGun { status = stat, gun_slot = gun_slot, |
| 102 | + target_slot = target_slot }; |
| 103 | + was_stuck := false; |
| 104 | + taketurn dos |
| 105 | + end) |
| 106 | + |
| 107 | + | BuildingGun { status = ref (EP.Progress _), ... } => DOS.Can'tRun |
| 108 | + (* Hope that medic helps us. *) |
| 109 | + | BuildingGun { status = ref (EP.Paused _), ... } => DOS.Can'tRun |
| 110 | + | BuildingGun { status = ref EP.Done, gun_slot, target_slot } => |
| 111 | + let in |
| 112 | + eprint ("Gun is assembled :D"); |
| 113 | + mode := FindTarget { gun_slot = gun_slot, target_slot = target_slot }; |
| 114 | + was_stuck := false; |
| 115 | + taketurn dos |
| 116 | + end |
| 117 | + | FindTarget { gun_slot, target_slot } => |
| 118 | + (* XXX check if gun is dead? *) |
| 119 | + if LTG.slotisdead (GS.myside gs) gun_slot orelse |
| 120 | + LTG.slotisdead (GS.myside gs) target_slot |
| 121 | + then |
| 122 | + let in |
| 123 | + if !was_stuck |
| 124 | + then eprint ("Gun/target slots are dead!") |
| 125 | + else (); |
| 126 | + was_stuck := true; |
| 127 | + Can'tRun |
| 128 | + end |
| 129 | + else |
| 130 | + let |
| 131 | + val slots = List.tabulate (256, fn i => |
| 132 | + (i, GS.scoreopponentslot gs i)) |
| 133 | + |
| 134 | + (* Maybe should have a lower bound on what it will |
| 135 | + consider valuable, and just heal/revive if there |
| 136 | + are no current high-value targets. *) |
| 137 | + val (best, _) = ListUtil.max compare_scores slots |
| 138 | + |
| 139 | + (* Put the number in our targeting slot. *) |
| 140 | + val prog = Kompiler.compile (Int (255 - best)) target_slot |
| 141 | + |
| 142 | + (* Ignore child pid since we never kill it. *) |
| 143 | + val (stat, child_pid) = EP.emitspawn dos prog |
| 144 | + in |
| 145 | + mode := Attacking { shots = ref 0, |
| 146 | + gun_slot = gun_slot, |
| 147 | + target_slot = target_slot, |
| 148 | + target = best, |
| 149 | + status = stat }; |
| 150 | + was_stuck := false; |
| 151 | + Can'tRun |
| 152 | + end |
| 153 | + | Attacking { status = ref (EP.Progress _), ... } => |
| 154 | + let in |
| 155 | + if !was_stuck |
| 156 | + then eprint ("Unstuck! Thanks!") |
| 157 | + else (); |
| 158 | + was_stuck := false; |
| 159 | + Can'tRun |
| 160 | + end |
| 161 | + | Attacking { status = ref EP.Done, shots, gun_slot, target, target_slot } => |
| 162 | + if LTG.slotisdead (GS.myside gs) gun_slot orelse |
| 163 | + LTG.slotisdead (GS.myside gs) target_slot |
| 164 | + then |
| 165 | + let in |
| 166 | + if !was_stuck |
| 167 | + then eprint ("Sniper's gun/target slot " ^ |
| 168 | + Int.toString gun_slot ^ "/" ^ |
| 169 | + Int.toString target_slot ^ |
| 170 | + " was killed! Hoping for medic.\n") |
| 171 | + else (); |
| 172 | + was_stuck := true; |
| 173 | + Can'tRun |
| 174 | + end |
| 175 | + else |
| 176 | + let val theirside = GS.theirside gs |
| 177 | + val health = Array.sub (#2 theirside, target) |
| 178 | + val num = Array.sub (#1 (GS.myside gs), target_slot) |
| 179 | + |
| 180 | +(* |
| 181 | + val () = eprint ("target_slot contains: " ^ |
| 182 | + LTG.valtos num ^ " and target health is " ^ |
| 183 | + Int.toString health) |
| 184 | +
|
| 185 | + val () = Array.appi (fn (i, n) => |
| 186 | + if n < 10000 |
| 187 | + then eprint ("But " ^ Int.toString i ^ " has vitality " ^ |
| 188 | + Int.toString n) |
| 189 | + else ()) (#2 theirside) |
| 190 | +*) |
| 191 | + in |
| 192 | + was_stuck := false; |
| 193 | + if health <= 0 |
| 194 | + then |
| 195 | + let in |
| 196 | + eprint ("Success! Killed slot " ^ |
| 197 | + Int.toString target ^ |
| 198 | + " in " ^ Int.toString (!shots) ^ " shots."); |
| 199 | + mode := FindTarget { gun_slot = gun_slot, |
| 200 | + target_slot = target_slot }; |
| 201 | + taketurn dos |
| 202 | + end |
| 203 | + else |
| 204 | + let in |
| 205 | + (* Otherwise keep attacking. *) |
| 206 | + (* eprint ("Attack!"); *) |
| 207 | + shots := !shots + 1; |
| 208 | + DOS.Turn (LTG.RightApply (gun_slot, LTG.I)) |
| 209 | + end |
| 210 | + end |
| 211 | + |
| 212 | + (* Optimistically hope that medic will heal it? *) |
| 213 | + | Attacking { status = ref (EP.Paused i), ... } => |
| 214 | + let in |
| 215 | + if !was_stuck |
| 216 | + then () |
| 217 | + else eprint ("Stuck because slot " ^ Int.toString i ^ " is dead."); |
| 218 | + was_stuck := true; |
| 219 | + Can'tRun |
| 220 | + end |
| 221 | + end |
| 222 | + in |
| 223 | + { preview = preview, |
| 224 | + taketurn = taketurn } |
| 225 | + end |
| 226 | +end |
| 227 | + |
0 commit comments