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