-
Notifications
You must be signed in to change notification settings - Fork 0
/
player-sniper.sml
executable file
·155 lines (132 loc) · 4.66 KB
/
player-sniper.sml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
structure Sniper :> LAYER =
struct
structure GS = GameState
datatype src = datatype Kompiler.src
(* This one doesn't pay any attention to the
game state. *)
fun init gs = ()
fun eprint s = TextIO.output (TextIO.stdErr, s)
(* Hard to kill. *)
val ATTACK_SLOT = 0
datatype mode =
FindTarget
(* Building the attack program for the given
cell. *)
| Emit of int * LTG.turn list
(* Keep attacking this slot until it's dead,
then find a new target. *)
| Attacking of int
(* Maybe should have a lower bound on what it will
consider valuable, and just heal/revive if there
are no current high-value targets. *)
fun scoreslot side (idx : int, s : LTG.stat) =
(idx,
(* XXX weighted! *)
if LTG.slotisdead side idx
then ~1000.0
else real (LTG.stat_left_applications s) +
real (LTG.stat_right_applications s) +
LTG.stat_damage_done s +
LTG.stat_healing_done s +
real (LTG.stat_iterations s) +
real (LTG.stat_gotten s))
val compare_scores = ListUtil.bysecond Real.compare
infix 9 --
val op -- = Apply
val $ = Var
fun \ x exp = Lambda (x, exp)
infixr 1 `
fun a ` b = a b
(* Takes an expression of object type unit.
Wraps in a function that ignores its single argument,
evaluates the expression, and then returns itself.
fun f _ = (exp; f)
*)
fun returnself src =
let val recursive =
\"self" `
\"unused" `
Card LTG.Put -- src -- $"self"
(* CBV fix-point operator. *)
val minifix =
\"x" ` $"f" -- (\"y" ` $"x" -- $"x" -- $"y")
val fix = \"f" ` minifix -- minifix
in
Apply (fix, recursive)
end
(* Makes a program that attacks the target slot index,
and then returns itself (so it sticks around). *)
fun attackprogram target =
let
(* XXX should dec as much as we can in this turn,
without exceeding 1000. *)
(* Numbers are reversed when attacking opponent. *)
val revtarget = 255 - target
val dec = Apply (Card LTG.Dec, Int revtarget)
val prog = returnself dec
(* val _ = eprint ` " PROGRAM SIZE = " ^
(Int.toString ` List.length (Kompiler.compile prog 0)) ^ "\n"
= 185 or so
*)
in
Kompiler.compile prog ATTACK_SLOT
end handle (e as Kompiler.Kompiler s) =>
let in
eprint ("Kompilation failed: " ^ s ^ "\n");
raise e
end
val n = ref 0
val mode = ref FindTarget
fun taketurn gs =
let in
n := !n + 1;
if !n mod 1000 = 0
then (eprint ("Turn #" ^ Int.toString (!n) ^ ". Stats:\n");
GS.printstats (GS.mystats gs);
eprint "Theirs:\n";
GS.printstats (GS.theirstats gs))
else ();
LTG.enable_trace false;
case !mode of
FindTarget =>
let
val theirside = GS.theirside gs
(* Find the highest-value slot in the
opponent's state, according to the
stats *)
val stats = GS.theirstats gs
val slots = List.tabulate (256, fn i =>
(i, LTG.statfor stats i))
val slots = map (scoreslot theirside) slots
val (best, _) = ListUtil.max compare_scores slots
val prog = attackprogram best
(* val () = eprint ("Program: " ^ LTG.turns2str prog ^ "\n") *)
in
eprint ("New target: " ^ Int.toString best ^ "\n");
mode := Emit (best, prog);
taketurn gs
end
| Emit (i, nil) => (mode := Attacking i; taketurn gs)
| Emit (i, (t :: rest)) => (mode := Emit (i, rest); t)
| Attacking i =>
let val theirside = GS.theirside gs
val health = Array.sub (#2 theirside, i)
in
if health <= 0
then (eprint ("Success! Killed slot " ^
Int.toString i ^ "\n");
mode := FindTarget;
taketurn gs)
(* Otherwise keep attacking. *)
else
let in
(*
eprint ("Target " ^ Int.toString i ^
"'s health: " ^ Int.toString health ^ "\n");
*)
LTG.RightApply (ATTACK_SLOT, LTG.I)
end
end
end
end
structure Player = LayerFn(Sniper)