Skip to content

Commit 2b96db4

Browse files
author
tom7
committed
This new sniper is a KILLING MACHINE
git-svn-id: svn://R_E_D_A_C_T_E_D/icfp/hw12@385 b3d0796d-73f4-44f3-a614-c7306c265f62
1 parent c2b6851 commit 2b96db4

File tree

5 files changed

+452
-63
lines changed

5 files changed

+452
-63
lines changed

dominator-sniper-dec.sml

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
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

Comments
 (0)