Recent

Author Topic: [SOLVED] Peg Solitaire example problem  (Read 2458 times)

YiannisKam

  • Full Member
  • ***
  • Posts: 119
[SOLVED] Peg Solitaire example problem
« on: December 26, 2023, 12:36:23 am »
Maybe the peg solitaire doesn't work anymore in the newer version of Lazarus. I'm sure it was ok the last time I experimented with this example on a previous version. Or maybe it's my fault, although I followed the code step by step, I don't know, I can't find the reason why it's not working. Maybe someone else can help.
This is the example from the wiki: https://wiki.freepascal.org/Peg_Solitaire_tutorial
And here is my code in case I'm completely wrong
Code: Pascal  [Select][+][-]
  1. unit ufrmMain;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   PegDatastructures, PegSolPainter,
  9.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, Menus;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     MainMenu1: TMainMenu;
  17.     MenuItem1: TMenuItem;
  18.     MenuItem2: TMenuItem;
  19.     MenuItem3: TMenuItem;
  20.     MenuItem4: TMenuItem;
  21.     OpenDialog1: TOpenDialog;
  22.     pbPeg: TPaintBox;
  23.     procedure FormCreate(Sender: TObject);
  24.     procedure MenuItem2Click(Sender: TObject);
  25.     procedure MenuItem4Click(Sender: TObject);
  26.     procedure pbPegMouseDown(Sender: TObject; Button: TMouseButton;
  27.       Shift: TShiftState; X, Y: Integer);
  28.     procedure pbPegMouseUp(Sender: TObject; Button: TMouseButton;
  29.       Shift: TShiftState; X, Y: Integer);
  30.     procedure pbPegPaint(Sender: TObject);
  31.   private
  32.     pegsol  : TPegSolitaire;
  33.     pegpaint: TPegSolPainter;
  34.     FromCell: TCellPosition;
  35.  
  36.     procedure StartNewGame;
  37.   public
  38.  
  39.   end;
  40.  
  41. var
  42.   Form1 : TForm1;
  43.  
  44. implementation
  45.  
  46. {$R *.lfm}
  47.  
  48. { TForm1 }
  49.  
  50. procedure TForm1.pbPegPaint(Sender: TObject);
  51. begin
  52.   // And paint the board
  53.   pegpaint.Repaint(pbPeg.Width, pbPeg.Height);
  54. end;
  55.  
  56. procedure TForm1.FormCreate(Sender: TObject);
  57. begin
  58.   StartNewGame;
  59. end;
  60.  
  61. procedure TForm1.MenuItem2Click(Sender: TObject);
  62. begin
  63.   Close;
  64. end;
  65.  
  66. procedure TForm1.MenuItem4Click(Sender: TObject);
  67. begin
  68.   // Open the pop up dialog
  69.   if OpenDialog1.Execute then
  70.   begin
  71.     // Start with a new empty board
  72.     StartNewGame;
  73.  
  74.     // Dynamically create a stringlist to load the board layout
  75.     with TStringList.Create do
  76.     begin
  77.       // Load the board layout from the textfile
  78.       LoadFromFile(OpenDialog1.FileName);
  79.  
  80.       // Initialize the board with the file's contents
  81.       pegsol.InitializeBoard(Text);
  82.  
  83.       // Clean up the stringlist
  84.       Free
  85.     end;
  86.  
  87.     // After loading the new board update the paintbox
  88.     pbPeg.Repaint;
  89.   end;
  90. end;
  91.  
  92. procedure TForm1.pbPegMouseDown(Sender: TObject; Button: TMouseButton;
  93.   Shift: TShiftState; X, Y: Integer);
  94. begin
  95.   FromCell := pegpaint.CanvasXYtoCell(X,Y);
  96. end;
  97.  
  98. procedure TForm1.pbPegMouseUp(Sender: TObject; Button: TMouseButton;
  99.   Shift: TShiftState; X, Y: Integer);
  100. begin
  101.   pegsol.Leap(FromCell, pegpaint.CanvasXYtoCell(X,Y));
  102.   pbPeg.Repaint;
  103. end;
  104.  
  105. procedure TForm1.StartNewGame;
  106. begin
  107.   // Clean up the previous game
  108.   pegpaint.Free;
  109.   pegsol.Free;
  110.  
  111.   // Start with a new game
  112.   pegsol := TPegSolitaire.Create(7);
  113.   pegpaint := TPegSolPainter.Create(pegsol, pbPeg.Canvas);
  114.  
  115.   // Initialize the cells to the classic game
  116.    pegsol.InitializeBoard( '  ooo  ' + LineEnding +
  117.                            '  ooo  ' + LineEnding +
  118.                            'ooooooo' + LineEnding +
  119.                            'ooo.ooo' + LineEnding +
  120.                            'ooooooo' + LineEnding +
  121.                            '  ooo  ' + LineEnding +
  122.                            '  ooo  ' );
  123. end;
  124.  
  125. end.
  126.  
  127.  
Code: Pascal  [Select][+][-]
  1. unit PegDatastructures;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils;
  9.  
  10. const
  11.   C_MAX = 7;        // max board size 7x7
  12.  
  13. type
  14.   TCellNums = 1..C_MAX;
  15.   TCellType = (ctNoAccess, ctEmpty, ctPeg);
  16.   TPegCells = array[TCellNums, TCellNums] of TCellType;
  17.  
  18.   TCellPosition = record
  19.     Row: TCellNums;
  20.     Col: TCellNums;
  21.   end;
  22.  
  23.   { TPegSolitaire }
  24.  
  25.   TPegSolitaire = class
  26.   private
  27.     FSize    : TCellNums;
  28.     PegCells: TPegCells;
  29.     function  GetCell(const ARow, ACol: TCellNums): TCellType;
  30.     procedure SetCell(const ARow, ACol: TCellNums; AValue: TCellType);
  31.     function  GetCell(const APosition: TCellPosition): TCellType;
  32.   public
  33.     constructor Create(const ASize: TCellNums);
  34.     procedure   InitializeBoard(const ABoard: Ansistring);
  35.     procedure   Leap(const AFromCell, AToCell: TCellPosition);
  36.  
  37.     property Cell[const ARow, ACol: TCellNums]: TCellType read GetCell write SetCell;
  38.     property Size: TCellNums read FSize;
  39.   end;
  40.  
  41. implementation
  42.  
  43. { TPegSolitaire }
  44.  
  45. function TPegSolitaire.GetCell(const ARow, ACol: TCellNums): TCellType;
  46. begin
  47.   Result := PegCells[ARow, ACol];
  48. end;
  49.  
  50. procedure TPegSolitaire.SetCell(const ARow, ACol: TCellNums; AValue: TCellType);
  51. begin
  52.   PegCells[ARow, ACol] := AValue;
  53. end;
  54.  
  55. function TPegSolitaire.GetCell(const APosition: TCellPosition): TCellType;
  56. begin
  57.   Result := Cell[APosition.Col, APosition.Row];
  58. end;
  59.  
  60. constructor TPegSolitaire.Create(const ASize: TCellNums);
  61. var
  62.   iRow, iCol: Integer;
  63. begin
  64.   // Store the size of the board locally
  65.   FSize := ASize;
  66.  
  67.   // Initialize all cells to 'not accessible'
  68.   for iRow := 1 to Size do
  69.     for iCol := 1 to Size do
  70.       Cell[iRow, iCol] := ctNoAccess;
  71. end;
  72.  
  73. procedure TPegSolitaire.InitializeBoard(const ABoard: Ansistring);
  74. var
  75.   Lst       : TStringList;
  76.   iRow, iCol: Integer;
  77.   s         : String;
  78. begin
  79.   // Create a list with the board text in it. This will split all lines
  80.   // into individual lines, because of the LineEnding 'splitter'.
  81.   Lst      := TStringList.Create;
  82.   Lst.Text := ABoard;
  83.  
  84.   // Process all lines one at a time
  85.   for iRow := 0 to Lst.Count - 1 do begin
  86.     if iRow < Size then begin // make sure there is no overflow in the rows
  87.       // Process a single line of text
  88.       s := Lst[iRow];
  89.       for iCol := 1 to Length(s) do begin
  90.         if iCol <= Size then begin  // check overflow in the cols
  91.           case s[iCol] of
  92.             ' ': Cell[iRow + 1, iCol] := ctNoAccess;
  93.             '.': Cell[iRow + 1, iCol] := ctEmpty;
  94.             'o': Cell[iRow + 1, iCol] := ctPeg;
  95.           end;
  96.         end;
  97.       end;
  98.     end;
  99.   end;
  100.   // Clean up the list
  101.   FreeAndNil(Lst);
  102. end;
  103.  
  104. procedure TPegSolitaire.Leap(const AFromCell, AToCell: TCellPosition);
  105. var dx, dy: integer;
  106.     JumpedCell: TCellPosition;
  107. begin
  108.   // Verify that the start cell is occupied and the target cell is empty
  109.   // If not, leave the procedure via the EXIT.
  110.   if (GetCell(AFromCell) <> ctPeg) or (GetCell(AToCell) <> ctEmpty) then EXIT;
  111.  
  112.   // Calculate the horizontal and vertical distance between the cells
  113.   dx := abs(AFromCell.Col - AToCell.Col);
  114.   dy := abs(AFromCell.Row - AToCell.Row);
  115.  
  116.   // A valid move has one direction equal to zero and the other equal to 2
  117.   if ((dx = 2) and (dy = 0)) or ((dx = 0) and (dy = 2)) then
  118.   begin
  119.     // Determine the position of the jumped cell; it's in the middle
  120.     JumpedCell.Col := (AFromCell.Col + AToCell.Col) div 2;
  121.     JumpedCell.Row := (AFromCell.Row + AToCell.Row) div 2;
  122.  
  123.     // Final check: is there a peg in the jumped cell?
  124.     if GetCell(JumpedCell) = ctPeg then
  125.     begin
  126.       // Jump: clear the FromCell, empty the jumped cell and populate the ToCell
  127.       Cell[AFromCell.Row, AFromCell.Col]   := ctEmpty;
  128.       Cell[JumpedCell.Row, JumpedCell.Col] := ctEmpty;
  129.       Cell[AToCell.Row, AToCell.Col]       := ctPeg;
  130.     end;
  131.   end;
  132. end;
  133.  
  134. end.
Code: Pascal  [Select][+][-]
  1. unit PegSolPainter;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   PegDatastructures, Graphics,
  9.   Classes, SysUtils;
  10.  
  11. type
  12.  
  13.   { TPegSolPainter }
  14.  
  15.   TPegSolPainter = class
  16.   private
  17.     PegSol    : TPegSolitaire;
  18.     Canvas    : TCanvas;
  19.     CellWidth : Integer;
  20.     CellHeight: Integer;
  21.   public
  22.     constructor Create(APegSol: TPegSolitaire; ACanvas: TCanvas);
  23.     procedure   Repaint(const ACanvasWidth, ACanvasHeight: Integer);
  24.     function    CanvasXYtoCell(const AX, AY: Integer): TCellPosition;
  25.   end;
  26.  
  27. implementation
  28.  
  29. { TPegSolPainter }
  30.  
  31. constructor TPegSolPainter.Create(APegSol: TPegSolitaire; ACanvas: TCanvas);
  32. begin
  33.   PegSol := APegSol;
  34.   Canvas := ACanvas;
  35. end;
  36.  
  37. procedure TPegSolPainter.Repaint(const ACanvasWidth, ACanvasHeight: Integer);
  38. var
  39.   iRow, iCol: TCellNums;
  40.   CellArea: TRect;
  41. begin
  42.   // calculate the width/height of each cell in the paintbox
  43.   CellWidth  := ACanvasWidth div PegSol.Size;
  44.   CellHeight := ACanvasHeight div PegSol.Size;
  45.  
  46.   // draw boxes for all cells
  47.   for iRow := 1 to PegSol.Size do
  48.     for iCol := 1 to PegSol.Size do begin
  49.       // calculate the position of the cell in the paintbox
  50.       CellArea.Top    := (iRow - 1) * CellHeight;
  51.       CellArea.Left   := (iCol - 1) * CellWidth;
  52.       CellArea.Right  := CellArea.Left + CellWidth;
  53.       CellArea.Bottom := CellArea.Top + CellHeight;
  54.       // and now draw the cell based on the cell's content
  55.       case PegSol.Cell[iRow, iCol] of
  56.         ctNoAccess: // Draw cells that are not accessible
  57.           begin
  58.             Canvas.Brush.Color := clGray;
  59.             Canvas.Rectangle(CellArea);
  60.           end;
  61.  
  62.         ctEmpty: // Draw cells that are currently empty
  63.           begin
  64.             Canvas.Brush.Color := clBlue;
  65.             Canvas.Rectangle(CellArea);
  66.           end;
  67.  
  68.         ctPeg:  // Draw cells that are occupied
  69.           begin
  70.             Canvas.Brush.Color := clBlue;
  71.             Canvas.Rectangle(CellArea); // Erase the background first
  72.             Canvas.Brush.Color := clGreen;
  73.             Canvas.Ellipse(CellArea);
  74.           end;
  75.       end;
  76.     end;
  77. end;
  78.  
  79. function TPegSolPainter.CanvasXYtoCell(const AX, AY: Integer): TCellPosition;
  80. begin
  81.   Result.Col := (AX div CellWidth) + 1;
  82.   Result.Row := (AY div CellHeight) + 1;
  83. end;
  84.  
  85. end.
  86.  
« Last Edit: December 29, 2023, 10:37:13 pm by YiannisKam »
Windows 10 - 64bit
Lazarus version: 3.99
FPC       version: 3.3.1

eny

  • Hero Member
  • *****
  • Posts: 1643
Re: Peg Solitaire example problem
« Reply #1 on: December 29, 2023, 12:49:40 am »
Maybe the peg solitaire doesn't work anymore in the newer version of Lazarus.
Do you mean the latest 3.0 version?
What problem(s) do you encounter?

I did a rough comparison of your sourcecode with the original and at a glance did not see major discrepancies.

I also tried to recompile with the 3.0 version.
It seems to compile and run fine.

But there is a backwards compatibility problem with the latest version: when running the program from the IDE, the IDE no longer switches to the executable folder.
It runs the program from the project root, which obviously is not correct.
It should however run fine, just not with the fancy images.
« Last Edit: December 29, 2023, 12:51:51 am by eny »
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

YiannisKam

  • Full Member
  • ***
  • Posts: 119
Re: Peg Solitaire example problem
« Reply #2 on: December 29, 2023, 01:33:00 am »
The problem is that I can only leap once and that's it, no progress after that.
Windows 10 - 64bit
Lazarus version: 3.99
FPC       version: 3.3.1

eny

  • Hero Member
  • *****
  • Posts: 1643
Re: Peg Solitaire example problem
« Reply #3 on: December 29, 2023, 01:49:18 am »
Can you post a (compilable) version of your project? (no binaries...)
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

YiannisKam

  • Full Member
  • ***
  • Posts: 119
Re: Peg Solitaire example problem
« Reply #4 on: December 29, 2023, 03:01:40 am »
I don't have the previous version now, if that is what you are asking. But it was running with no problems.
Windows 10 - 64bit
Lazarus version: 3.99
FPC       version: 3.3.1

Josh

  • Hero Member
  • *****
  • Posts: 1321
Re: Peg Solitaire example problem
« Reply #5 on: December 29, 2023, 03:25:26 am »
just created project from wiki

done with fixes, so needed to add math unit to PegDatastructures to get the min function, a part from that all ok

The best way to get accurate information on the forum is to post something wrong and wait for corrections.

YiannisKam

  • Full Member
  • ***
  • Posts: 119
Re: Peg Solitaire example problem
« Reply #6 on: December 29, 2023, 01:21:54 pm »
Thank you Josh, it works.
Windows 10 - 64bit
Lazarus version: 3.99
FPC       version: 3.3.1

Josh

  • Hero Member
  • *****
  • Posts: 1321
Re: [SOLVED] Peg Solitaire example problem
« Reply #7 on: December 31, 2023, 01:50:24 am »
Your Welcome.

Recovering from flu, so had some time for fun.
Quite a bit of mods from original,
images for board styles held  in imagelist, marble is kind of drag n drop.
tells you if you have won, and the time taken to win.

« Last Edit: December 31, 2023, 02:06:18 am by Josh »
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

YiannisKam

  • Full Member
  • ***
  • Posts: 119
Re: [SOLVED] Peg Solitaire example problem
« Reply #8 on: January 01, 2024, 12:28:12 am »
Wonderful. Thank you very much, take care and Happy New Year!
Windows 10 - 64bit
Lazarus version: 3.99
FPC       version: 3.3.1

 

TinyPortal © 2005-2018