Subversion Repositories lightgame

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
unit LightGameMain;
2
 
3
(*
4
  TODO for the future:
5
  Predefined Levels...
6
  Undo...
7
*)
8
 
9
interface
10
 
11
uses
12
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
3 daniel-mar 13
  Dialogs, ExtCtrls, StdCtrls, Menus, System.UITypes;
2 daniel-mar 14
 
15
type
16
  TMainForm = class(TForm)
17
    Panel1: TPanel;
18
    Panel2: TPanel;
19
    Panel3: TPanel;
20
    Panel4: TPanel;
21
    Panel5: TPanel;
22
    Panel6: TPanel;
23
    Panel7: TPanel;
24
    Panel8: TPanel;
25
    Panel9: TPanel;
26
    Panel10: TPanel;
27
    Panel11: TPanel;
28
    Panel12: TPanel;
29
    Panel13: TPanel;
30
    Panel14: TPanel;
31
    Panel15: TPanel;
32
    Panel16: TPanel;
33
    Panel17: TPanel;
34
    Panel18: TPanel;
35
    Panel19: TPanel;
36
    Panel20: TPanel;
37
    Panel21: TPanel;
38
    Panel22: TPanel;
39
    Panel23: TPanel;
40
    Panel24: TPanel;
41
    Panel25: TPanel;
42
    Image1: TImage;
43
    MainMenu1: TMainMenu;
44
    Game1: TMenuItem;
45
    Exit1: TMenuItem;
46
    N1: TMenuItem;
47
    Newgame1: TMenuItem;
48
    Help1: TMenuItem;
49
    About1: TMenuItem;
50
    Cleargrid1: TMenuItem;
51
    Designmode1: TMenuItem;
52
    N2: TMenuItem;
53
    Save1: TMenuItem;
54
    Loadgrid1: TMenuItem;
55
    N3: TMenuItem;
56
    SaveDialog1: TSaveDialog;
57
    OpenDialog1: TOpenDialog;
58
    Label1: TLabel;
59
    Label2: TLabel;
60
    Timer1: TTimer;
61
    procedure Panel1Click(Sender: TObject);
62
    procedure FormCreate(Sender: TObject);
63
    procedure Exit1Click(Sender: TObject);
64
    procedure About1Click(Sender: TObject);
65
    procedure Newgame1Click(Sender: TObject);
66
    procedure Cleargrid1Click(Sender: TObject);
67
    procedure Loadgrid1Click(Sender: TObject);
68
    procedure Save1Click(Sender: TObject);
69
    procedure Designmode1Click(Sender: TObject);
70
    procedure Timer1Timer(Sender: TObject);
71
  protected const
72
    SIZE_X = 5;
73
    SIZE_Y = 5;
74
    RANDOM_STEPS = 1000;
75
    ONCOLOR = clYellow;
76
    OFFCOLOR = clSilver;
77
  private
78
    FStartTime: TDateTime;
79
    FMoves: integer;
80
    function GetDesignMode: boolean;
81
    procedure SetDesignMode(const Value: boolean);
82
  protected
83
    GameGrid: array[0..SIZE_X-1, 0..SIZE_Y-1] of boolean;
84
    property DesignMode: boolean read GetDesignMode write SetDesignMode;
85
    procedure ResetCounter;
86
    procedure IncCounter;
87
    procedure ToggleSingle(x, y: integer);
88
    procedure RedrawGrid;
89
    procedure RandomMove(PreferLights: boolean=true; redraw: boolean=true);
90
    procedure Draw(x, y: integer; redraw: boolean=true);
91
    procedure ClearGrid(redraw: boolean=true);
92
    function LightsOut: boolean;
93
    procedure LoadGame(FileName: string);
94
    procedure SaveGame(FileName: string);
95
  end;
96
 
97
var
98
  MainForm: TMainForm;
99
 
100
implementation
101
 
102
{$R *.dfm}
103
 
104
uses
105
  LightGameAbout, IniFiles, DateUtils;
106
 
107
{ TMainForm }
108
 
109
procedure TMainForm.About1Click(Sender: TObject);
110
begin
111
  AboutBox.ShowModal;
112
end;
113
 
114
procedure TMainForm.ClearGrid(redraw: boolean=true);
115
var
116
  x, y: integer;
117
begin
118
  for x := 0 to SIZE_X - 1 do
119
    for y := 0 to SIZE_Y - 1 do
120
      GameGrid[x][y] := false;
121
  if redraw then RedrawGrid;
122
end;
123
 
124
procedure TMainForm.Cleargrid1Click(Sender: TObject);
125
begin
126
  ClearGrid;
127
  ResetCounter;
128
end;
129
 
130
procedure TMainForm.Designmode1Click(Sender: TObject);
131
resourcestring
132
  LNG_CLEARGRID = 'Clear grid?';
133
begin
134
  if DesignMode then
135
  begin
136
    if MessageDlg(LNG_CLEARGRID, mtConfirmation, mbYesNoCancel, 0) = mrYes then
137
    begin
138
      ClearGrid;
139
    end;
140
  end;
141
  ResetCounter;
142
end;
143
 
144
procedure TMainForm.Draw(x, y: integer; redraw: boolean=true);
145
begin
146
  ToggleSingle(x, y);
147
 
148
  if not DesignMode then
149
  begin
150
    ToggleSingle(x-1, y);
151
    ToggleSingle(x+1, y);
152
    ToggleSingle(x, y-1);
153
    ToggleSingle(x, y+1);
154
  end;
155
 
156
  if redraw then RedrawGrid;
157
end;
158
 
159
procedure TMainForm.Exit1Click(Sender: TObject);
160
begin
161
  Close;
162
end;
163
 
164
procedure TMainForm.FormCreate(Sender: TObject);
165
begin
166
  Randomize;
167
 
168
  ClientWidth := Image1.Width;
169
  ClientHeight := Image1.Height;
170
 
171
  ClearGrid;
172
end;
173
 
174
function TMainForm.GetDesignMode: boolean;
175
begin
176
  result := Designmode1.Checked;
177
end;
178
 
179
procedure TMainForm.IncCounter;
180
begin
181
  Inc(FMoves);
182
  if FMoves = 1 then FStartTime := Now;
183
  Timer1Timer(Timer1);
184
end;
185
 
186
function TMainForm.LightsOut: boolean;
187
var
188
  x, y: integer;
189
begin
190
  result := true;
191
  for x := 0 to SIZE_X - 1 do
192
  begin
193
    for y := 0 to SIZE_Y - 1 do
194
    begin
195
      if GameGrid[x][y] then
196
      begin
197
        result := false;
198
        Exit;
199
      end;
200
    end;
201
  end;
202
end;
203
 
204
procedure TMainForm.Loadgrid1Click(Sender: TObject);
205
begin
206
  if OpenDialog1.Execute then
207
  begin
208
    LoadGame(OpenDialog1.FileName);
209
  end;
210
  ResetCounter;
211
end;
212
 
213
procedure TMainForm.Newgame1Click(Sender: TObject);
214
var
215
  i, RandomSteps: integer;
216
begin
217
  DesignMode := false;
218
  RandomSteps := Random(RANDOM_STEPS);
219
  for i := 0 to RandomSteps - 1 do
220
  begin
221
    RandomMove(true, false);
222
  end;
223
  RedrawGrid;
224
  ResetCounter;
225
end;
226
 
227
procedure TMainForm.Panel1Click(Sender: TObject);
228
resourcestring
229
  LNG_WIN = 'Congratulations! You solved the puzzle in %d moves in %.2d:%.2d min.';
230
var
231
  x, y, idx: integer;
232
  secs: integer;
233
begin
234
  idx := TPanel(Sender).Tag-1;
235
 
236
  x := idx div SIZE_X;
237
  y := idx mod SIZE_Y;
238
 
239
  Draw(x, y);
240
 
241
  if not DesignMode then IncCounter;
242
 
243
  RedrawGrid;
244
 
245
  if LightsOut and not DesignMode then
246
  begin
247
    secs := SecondsBetween(Now, FStartTime);
248
    ShowMessageFmt(LNG_WIN, [FMoves, secs div 60, secs mod 60]);
249
  end;
250
end;
251
 
252
procedure TMainForm.RandomMove(PreferLights: boolean=true; redraw: boolean=true);
253
var
254
  x, y: integer;
255
begin
256
  if not PreferLights then
257
  begin
258
    x := Random(SIZE_X);
259
    y := Random(SIZE_Y);
260
    Draw(x, y, redraw);
261
  end
262
  else
263
  begin
264
    if LightsOut then
265
    begin
266
      x := Random(SIZE_X);
267
      y := Random(SIZE_Y);
268
      Draw(x, y, redraw);
269
    end
270
    else
271
    begin
272
      repeat
273
        x := Random(SIZE_X);
274
        y := Random(SIZE_Y);
275
      until GameGrid[x][y];
276
      Draw(x, y, redraw);
277
    end;
278
  end;
279
end;
280
 
281
procedure TMainForm.RedrawGrid;
282
var
283
  x, y, idx, c: integer;
284
  p: TPanel;
285
  comp: TComponent;
286
begin
287
  idx := 0;
288
  for x := Low(GameGrid) to High(GameGrid) do
289
  begin
290
    for y := Low(GameGrid[x]) to High(GameGrid[x]) do
291
    begin
292
      Inc(idx);
293
 
294
      p := nil;
295
      for c := 0 to ComponentCount - 1 do
296
      begin
297
        comp := Components[c];
298
        if (comp is TPanel) and (comp.Tag = idx) then
299
        begin
300
          p := TPanel(comp);
301
        end;
302
      end;
303
 
304
      if Assigned(p) then
305
      begin
306
        if GameGrid[x][y] then
307
        begin
308
          p.Color := ONCOLOR;
309
        end
310
        else
311
        begin
312
          p.Color := OFFCOLOR;
313
        end;
314
      end;
315
    end;
316
  end;
317
end;
318
 
319
procedure TMainForm.ResetCounter;
320
begin
321
  FStartTime := 0;
322
  FMoves := 0;
323
  Timer1Timer(Timer1);
324
end;
325
 
326
procedure TMainForm.Save1Click(Sender: TObject);
327
begin
328
  if SaveDialog1.Execute then
329
  begin
330
    SaveGame(SaveDialog1.FileName);
331
  end;
332
end;
333
 
334
procedure TMainForm.LoadGame(FileName: string);
335
var
336
  ini: TMemIniFile;
337
  x, y: integer;
338
  s: string;
339
begin
340
  ini := TMemIniFile.Create(FileName);
341
  try
342
    for x := 0 to SIZE_X - 1 do
343
    begin
344
      for y := 0 to SIZE_Y - 1 do
345
      begin
346
        begin
347
          s := IntToStr(x) + ',' + IntToStr(y);              { do not localize }
348
          GameGrid[x][y] := ini.ReadBool('Grid', s, false);  { do not localize }
349
        end;
350
      end;
351
    end;
352
  finally
353
    ini.Free;
354
  end;
355
  RedrawGrid;
356
end;
357
 
358
procedure TMainForm.SaveGame(FileName: string);
359
var
360
  ini: TMemIniFile;
361
  x, y: integer;
362
  s: string;
363
begin
364
  ini := TMemIniFile.Create(FileName);
365
  try
366
    for x := 0 to SIZE_X - 1 do
367
    begin
368
      for y := 0 to SIZE_Y - 1 do
369
      begin
370
        begin
371
          s := IntToStr(x) + ',' + IntToStr(y);      { do not localize }
372
          ini.WriteBool('Grid', s, GameGrid[x][y]);  { do not localize }
373
        end;
374
      end;
375
    end;
376
    ini.UpdateFile;
377
  finally
378
    ini.Free;
379
  end;
380
end;
381
 
382
procedure TMainForm.SetDesignMode(const Value: boolean);
383
begin
384
  Designmode1.Checked := Value;
385
  Designmode1Click(Designmode1);
386
end;
387
 
388
procedure TMainForm.Timer1Timer(Sender: TObject);
389
resourcestring
390
  LNG_MOVES = '%d moves';
391
var
392
  secs: integer;
393
begin
394
  label1.Visible := FMoves > 0;
395
  Label2.Visible := FMoves > 0;
396
 
397
  Label1.Caption := Format(LNG_MOVES, [FMoves]);
398
 
399
  secs := SecondsBetween(Now, FStartTime);
400
  Label2.Caption := Format('%.2d:%.2d', [secs div 60, secs mod 60]);
401
end;
402
 
403
procedure TMainForm.ToggleSingle(x, y: integer);
404
begin
405
  if (x < 0) or (x >= SIZE_X) then exit;
406
  if (y < 0) or (y >= SIZE_Y) then exit;
407
 
408
  GameGrid[x][y] := not GameGrid[x][y];
409
end;
410
 
411
end.