Subversion Repositories lightgame

Rev

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

  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,
  13.   Dialogs, ExtCtrls, StdCtrls, Menus, System.UITypes;
  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.
  412.