1 import dfl.all;
2 import util;
3 import game;
4 import driver;
5
6 class GUI(Solver) : Form, GameObserver
7 {
8 this(in Game g)
9 {
10 this.solver = new Solver(g);
11 setup_size(g.map.W, g.map.H);
12 setup_resources(g);
13 draw(g);
14 }
15
16 private void delegate(char c) fn;
17 void set_fn(F)(F f) { this.fn = f; }
18
19 void run(bool automate = false)
20 {
21 if(automate) {
22 Timer t = new Timer;
23 t.interval = 50;
24 t.tick ~= (Timer sender, EventArgs ea){
25 fn(solver.single_step());
26 };
27 t.start();
28 this.closing ~= (Form f,CancelEventArgs c){t.stop();};
29 } else {
30 setup_keyhandling();
31 }
32 Application.run(this);
33 }
34
35 override void on_game_changed(char c, in Game g, bool finished)
36 {
37 draw(g);
38 }
39
40 private:
41 int cell;
42
43 void setup_size(int W, int H)
44 {
45 this.formBorderStyle = FormBorderStyle.FIXED_DIALOG;
46 this.maximizeBox = false;
47 this.minimizeBox = false;
48 this.cell = min(1024/W, 640/H);
49 this.clientSize = Size(W*cell, H*cell);
50 }
51
52 Font font;
53 Color[char] colors;
54 string[char] render;
55 Graphics graphicContext;
56
57 void setup_resources(in Game g)
58 {
59 this.graphicContext = new MemoryGraphics(this.clientSize.width, this.clientSize.height);
60 this.setStyle(ControlStyles.OPAQUE, true);
61 this.font = new Font("MS Gothic", cell-2, GraphicsUnit.PIXEL);
62 this.backColor = Color(255,255,255);
63 this.colors['#'] =
64 this.colors['.'] = Color(255,191,127);
65 this.colors['*'] = Color(255,127,127);
66 this.colors['R'] = Color(128,128,0);
67 this.colors['d'] = Color(255,0,0);
68 this.colors['\\'] =
69 this.colors['L'] =
70 this.colors['O'] = Color(127,255,127);
71 this.colors['w'] = Color(204,229,255);
72 this.colors['W'] =
73 this.colors['!'] = Color(159,159,159);
74 foreach(char c; 'A'..'J') this.colors[c] = Color(142,142,255);
75 foreach(char c; '1'..':') this.colors[c] = Color(255,142,255);
76 this.render['#'] = "■";
77 this.render['*'] = "✹";
78 this.render['.'] = "♒";
79 this.render['\\'] = "λ";
80 this.render['R'] = "☃";
81 this.render['d'] = "☠";
82 this.render['L'] = "☒";
83 this.render['O'] = "☐";
84 this.render['W'] = "ꔣ";
85 this.render['!'] = "✄";
86 foreach(c,tp; g.map.tr_target) {
87 char d = g.map[tp];
88 this.render[c] = [cast(dchar)('☢'+d-'1')].to!string();
89 }
90 foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1')].to!string();
91 this.paint ~= (Control c, PaintEventArgs ev) {
92 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientSize.width,this.clientSize.height));
93 };
94 }
95
96 void draw(in Game g)
97 {
98 int scrW = this.clientSize.width;
99 int scrH = this.clientSize.height;
100
101 // Fill bg.
102 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH));
103
104 // Fill water.
105 int w = g.water_level();
106 graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell*w-1, scrW, cell*w+1));
107
108 // Paint map.
109 for(int y=1; y<=g.map.H; ++y)
110 for(int x=1; x<=g.map.W; ++x) {
111 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell);
112 char c = g.map[y,x];
113 if( c != ' ' ) {
114 if( c == 'R' && g.dead )
115 c = 'd';
116 graphicContext.drawText(this.render[c], font, this.colors[c], r);
117 }
118 }
119
120 // Update textual info.
121 this.text = .text(
122 "Score: ", g.score,
123 " Air: ", g.hp,
124 " Tide: ", g.water_until_rise,
125 " Wadler: ", g.hige_until_rise,
126 " Razor: ", g.map.razor);
127 invalidate();
128 }
129
130 private:
131 void setup_keyhandling()
132 {
133 noMessageFilter();
134 this.keyDown ~= &my_keydown;
135 }
136
137 void do_manual_command(char c)
138 {
139 solver.force(c);
140 fn(c);
141 }
142
143 void my_keydown(Control c, KeyEventArgs ev)
144 {
145 switch(ev.keyCode)
146 {
147 case Keys.DOWN: do_manual_command('D'); break;
148 case Keys.UP: do_manual_command('U'); break;
149 case Keys.LEFT: do_manual_command('L'); break;
150 case Keys.RIGHT: do_manual_command('R'); break;
151 case Keys.W: do_manual_command('W'); break;
152 case Keys.S: do_manual_command('S'); break;
153 case Keys.A: do_manual_command('A'); break;
154 case Keys.G: fn(solver.single_step()); break;
155 default: break;
156 }
157 }
158
159 Solver solver;
160 }