Subversion Repositories jumper

Rev

Rev 23 | Rev 25 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 23 Rev 24
Line 11... Line 11...
11
    Y: integer;
11
    Y: integer;
12
  end;
12
  end;
13
 
13
 
14
  TFieldType = (ftUndefined, ftFullSpace, ftEmpty, ftRed, ftYellow, ftGreen);
14
  TFieldType = (ftUndefined, ftFullSpace, ftEmpty, ftRed, ftYellow, ftGreen);
15
 
15
 
16
  TFieldProperties = record
-
 
17
    Typ: TFieldType;
-
 
18
    Goal: Boolean;
-
 
19
  end;
-
 
20
 
-
 
21
  TGameMode = (gmUndefined, gmNormal, gmDiagonal);
16
  TGameMode = (gmUndefined, gmNormal, gmDiagonal);
22
 
17
 
23
  TRow = record
-
 
24
    Indent: integer;
-
 
25
    Fields: array of TFieldProperties;
-
 
26
  end;
-
 
27
  TLevelArray = array of TRow;
-
 
28
 
-
 
29
  TLevelError = (leUndefined, leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength,
18
  TLevelError = (leUndefined, leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength,
30
                 leUnsupportedVersion, leUnsupportedMode);
19
                 leUnsupportedVersion, leUnsupportedMode);
31
 
20
 
32
  TLevel = class(TObject)
-
 
33
  private
-
 
34
    FStringList: TStringList;
-
 
35
    procedure Load(ABoardFile: string);
-
 
36
    function GetGameMode: TGameMode;
-
 
37
  public
-
 
38
    constructor Create(ABoardFile: string);
-
 
39
    destructor Destroy; override;
-
 
40
    function LevelStringToLevelArray(ShowErrors: boolean): TLevelArray;
-
 
41
    function CheckLevelIntegrity: TLevelError; overload;
-
 
42
    function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload;
-
 
43
    property GameMode: TGameMode read GetGameMode;
-
 
44
  end;
-
 
45
 
-
 
46
  TField = record
21
  TField = record
-
 
22
    Indent: integer;
47
    FieldType: TFieldType;
23
    FieldType: TFieldType;
48
    Goal: Boolean;
24
    Goal: Boolean;
49
    Panel: TPanel;
25
    Panel: TPanel;
50
    Stone: TImage;
26
    Stone: TImage;
51
  end;
27
  end;
52
 
28
 
53
  TGoalStatus = (gsUndefined, gsNoGoal, gsMultipleStonesRemaining, gsLastStoneInGoalRed, gsLastStoneInGoalYellow, gsLastStoneInGoalGreen, gsLastStoneOutsideGoal);
29
  TGoalStatus = (gsUndefined, gsNoGoal, gsMultipleStonesRemaining, gsLastStoneInGoalRed, gsLastStoneInGoalYellow, gsLastStoneInGoalGreen, gsLastStoneOutsideGoal);
54
 
30
 
55
  TFieldState = (fsUndefined, fsError, fsLocked, fsAvailable, fsStone);
31
  TFieldState = (fsUndefined, fsLocked, fsAvailable, fsOccupied);
56
 
32
 
57
  TPlayGroundMatrix = record
33
  TPlayGroundMatrix = record
58
    Fields: array of array of TField;
34
    Fields: array of array of TField;
59
  public
35
  public
60
    procedure InitFieldArray(width, height: integer);
36
    procedure InitFieldArray(width, height: integer);
Line 65... Line 41...
65
    function CloneMatrix: TPlayGroundMatrix;
41
    function CloneMatrix: TPlayGroundMatrix;
66
    class function FieldState(t: TFieldType): TFieldState; overload; static;
42
    class function FieldState(t: TFieldType): TFieldState; overload; static;
67
    function FieldState(f: TField): TFieldState; overload;
43
    function FieldState(f: TField): TFieldState; overload;
68
    function FieldState(x, y: integer): TFieldState; overload;
44
    function FieldState(x, y: integer): TFieldState; overload;
69
    function CanJump(SourceX, SourceY, DestX, DestY: integer; DiagonalOK: boolean): boolean; overload;
45
    function CanJump(SourceX, SourceY, DestX, DestY: integer; DiagonalOK: boolean): boolean; overload;
-
 
46
    function CanJump(Source, Dest: TCoord; DiagonalOK: boolean): boolean; overload;
70
    function CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean; overload;
47
    function CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean; overload;
-
 
48
    function CanJump(Source: TCoord; DiagonalOK: boolean): boolean; overload;
71
    function CanJump(DiagonalOK: boolean): boolean; overload;
49
    function CanJump(DiagonalOK: boolean): boolean; overload;
72
    function IndexToCoord(index: integer): TCoord;
50
    function IndexToCoord(index: integer): TCoord;
73
    function CoordToIndex(coord: TCoord): integer; overload;
51
    function CoordToIndex(coord: TCoord): integer; overload;
74
    function CoordToIndex(x, y: integer): integer; overload;
52
    function CoordToIndex(x, y: integer): integer; overload;
75
    function Width: integer;
53
    function Width: integer;
76
    function Height: integer;
54
    function Height: integer;
77
  end;
55
  end;
78
 
56
 
-
 
57
  TLevel = class(TObject)
-
 
58
  private
-
 
59
    FStringList: TStringList;
-
 
60
    procedure Load(ABoardFile: string);
-
 
61
    function GetGameMode: TGameMode;
-
 
62
  public
-
 
63
    constructor Create(ABoardFile: string);
-
 
64
    destructor Destroy; override;
-
 
65
    procedure FillPlaygroundMatrix(var matrix: TPlayGroundMatrix; ShowErrors: boolean);
-
 
66
    function CheckLevelIntegrity: TLevelError; overload;
-
 
67
    function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload;
-
 
68
    property GameMode: TGameMode read GetGameMode;
-
 
69
  end;
-
 
70
 
79
function FieldTypeWorth(t: TFieldType): integer;
71
function FieldTypeWorth(t: TFieldType): integer;
80
 
72
 
81
implementation
73
implementation
82
 
74
 
83
function FieldTypeWorth(t: TFieldType): integer;
75
function FieldTypeWorth(t: TFieldType): integer;
Line 139... Line 131...
139
  SetLength(Fields, width, height);
131
  SetLength(Fields, width, height);
140
  for x := Low(Fields) to High(Fields) do
132
  for x := Low(Fields) to High(Fields) do
141
  begin
133
  begin
142
    for y := Low(Fields[x]) to High(Fields[x]) do
134
    for y := Low(Fields[x]) to High(Fields[x]) do
143
    begin
135
    begin
144
      Fields[x,y].FieldType := ftUndefined;
136
      Fields[x,y].FieldType := ftUndefined
145
    end;
137
    end;
146
  end;
138
  end;
147
end;
139
end;
148
 
140
 
149
function TPlayGroundMatrix.MatrixWorth: integer;
141
function TPlayGroundMatrix.MatrixWorth: integer;
Line 163... Line 155...
163
function TPlayGroundMatrix.Width: integer;
155
function TPlayGroundMatrix.Width: integer;
164
begin
156
begin
165
  result := Length(Fields);
157
  result := Length(Fields);
166
end;
158
end;
167
 
159
 
-
 
160
function TPlayGroundMatrix.CanJump(Source: TCoord;
-
 
161
  DiagonalOK: boolean): boolean;
-
 
162
begin
-
 
163
  result := CanJump(Source.X, Source.Y, DiagonalOK);
-
 
164
end;
-
 
165
 
-
 
166
function TPlayGroundMatrix.CanJump(Source, Dest: TCoord;
-
 
167
  DiagonalOK: boolean): boolean;
-
 
168
begin
-
 
169
  result := CanJump(Source.X, Source.Y, Dest.X, Dest.Y, DiagonalOK);
-
 
170
end;
-
 
171
 
168
procedure TPlayGroundMatrix.ClearMatrix(FreeVCL: boolean);
172
procedure TPlayGroundMatrix.ClearMatrix(FreeVCL: boolean);
169
var
173
var
170
  x, y: integer;
174
  x, y: integer;
171
begin
175
begin
-
 
176
  if FreeVCL then
-
 
177
  begin
172
  for x := Low(Fields) to High(Fields) do
178
    for x := Low(Fields) to High(Fields) do
173
  begin
179
    begin
174
    for y := Low(Fields[x]) to High(Fields[x]) do
180
      for y := Low(Fields[x]) to High(Fields[x]) do
175
    begin
181
      begin
176
      if FreeVCL then
-
 
177
      begin
-
 
178
        if Assigned(Fields[x,y].Stone) then Fields[x,y].Stone.Free;
182
        if Assigned(Fields[x,y].Stone) then Fields[x,y].Stone.Free;
179
        if Assigned(Fields[x,y].Panel) then Fields[x,y].Panel.Free;
183
        if Assigned(Fields[x,y].Panel) then Fields[x,y].Panel.Free;
180
      end;
184
      end;
181
    end;
185
    end;
182
  end;
186
  end;
Line 200... Line 204...
200
    end;
204
    end;
201
  end;
205
  end;
202
end;
206
end;
203
 
207
 
204
function TPlayGroundMatrix.CoordToIndex(x, y: integer): integer;
208
function TPlayGroundMatrix.CoordToIndex(x, y: integer): integer;
205
var
-
 
206
  c: TCoord;
-
 
207
begin
209
begin
208
  c.X := x;
-
 
209
  c.Y := y;
-
 
210
  result := CoordToIndex(c);
210
  result := x + y * Width;
211
end;
211
end;
212
 
212
 
213
function TPlayGroundMatrix.CoordToIndex(coord: TCoord): integer;
213
function TPlayGroundMatrix.CoordToIndex(coord: TCoord): integer;
214
begin
214
begin
215
  result := coord.X + coord.Y * Width;
215
  result := CoordToIndex(coord.X, coord.Y);
216
end;
216
end;
217
 
217
 
218
class function TPlayGroundMatrix.FieldState(t: TFieldType): TFieldState;
218
class function TPlayGroundMatrix.FieldState(t: TFieldType): TFieldState;
219
begin
219
begin
220
  result := fsError;
220
  result := fsUndefined;
221
  case t of
221
  case t of
222
    ftFullSpace: result := fsLocked;
222
    ftFullSpace: result := fsLocked;
223
    ftEmpty:     result := fsAvailable;
223
    ftEmpty:     result := fsAvailable;
224
    ftGreen:     result := fsStone;
224
    ftGreen:     result := fsOccupied;
225
    ftYellow:    result := fsStone;
225
    ftYellow:    result := fsOccupied;
226
    ftRed:       result := fsStone;
226
    ftRed:       result := fsOccupied;
227
  end;
227
  end;
228
end;
228
end;
229
 
229
 
230
function TPlayGroundMatrix.FieldState(f: TField): TFieldState;
230
function TPlayGroundMatrix.FieldState(f: TField): TFieldState;
231
begin
231
begin
232
  result := FieldState(f.FieldType);
232
  result := FieldState(f.FieldType);
233
end;
233
end;
234
 
234
 
235
function TPlayGroundMatrix.FieldState(x, y: integer): TFieldState;
235
function TPlayGroundMatrix.FieldState(x, y: integer): TFieldState;
236
begin
236
begin
237
  result := fsError;
237
  result := fsUndefined;
238
  if (x < Low(Fields)) or (x > High(Fields)) then exit;
238
  if (x < Low(Fields)) or (x > High(Fields)) then exit;
239
  if (y < Low(Fields[x])) or (y > High(Fields[x])) then exit;
239
  if (y < Low(Fields[x])) or (y > High(Fields[x])) then exit;
240
 
240
 
241
  result := FieldState(Fields[x,y]);
241
  result := FieldState(Fields[x,y]);
242
end;
242
end;
Line 249... Line 249...
249
  if FieldState(DestX, DestY) <> fsAvailable then exit;
249
  if FieldState(DestX, DestY) <> fsAvailable then exit;
250
 
250
 
251
  // Check 2: Befindet sich ein Stein zwischen Source und Destination und ist der Abstand 2?
251
  // Check 2: Befindet sich ein Stein zwischen Source und Destination und ist der Abstand 2?
252
  if DiagonalOK then
252
  if DiagonalOK then
253
  begin
253
  begin
254
    if (SourceX-2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX-1, SourceY-1) = fsStone) then result := true;
254
    if (SourceX-2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX-1, SourceY-1) = fsOccupied) then result := true;
255
    if (SourceX-2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX-1, SourceY+1) = fsStone) then result := true;
255
    if (SourceX-2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX-1, SourceY+1) = fsOccupied) then result := true;
256
    if (SourceX+2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX+1, SourceY-1) = fsStone) then result := true;
256
    if (SourceX+2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX+1, SourceY-1) = fsOccupied) then result := true;
257
    if (SourceX+2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX+1, SourceY+1) = fsStone) then result := true;
257
    if (SourceX+2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX+1, SourceY+1) = fsOccupied) then result := true;
258
  end;
258
  end;
259
 
259
 
260
  if (SourceX+2 = DestX) and (SourceY   = DestY) and (FieldState(SourceX+1, SourceY  ) = fsStone) then result := true;
260
  if (SourceX+2 = DestX) and (SourceY   = DestY) and (FieldState(SourceX+1, SourceY  ) = fsOccupied) then result := true;
261
  if (SourceX-2 = DestX) and (SourceY   = DestY) and (FieldState(SourceX-1, SourceY  ) = fsStone) then result := true;
261
  if (SourceX-2 = DestX) and (SourceY   = DestY) and (FieldState(SourceX-1, SourceY  ) = fsOccupied) then result := true;
262
  if (SourceX   = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX  , SourceY+1) = fsStone) then result := true;
262
  if (SourceX   = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX  , SourceY+1) = fsOccupied) then result := true;
263
  if (SourceX   = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX  , SourceY-1) = fsStone) then result := true;
263
  if (SourceX   = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX  , SourceY-1) = fsOccupied) then result := true;
264
end;
264
end;
265
 
265
 
266
function TPlayGroundMatrix.CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean;
266
function TPlayGroundMatrix.CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean;
267
begin
267
begin
268
  if FieldState(SourceX, SourceY) <> fsStone then
268
  if FieldState(SourceX, SourceY) <> fsOccupied then
269
  begin
269
  begin
270
    result := false;
270
    result := false;
271
    exit;
271
    exit;
272
  end;
272
  end;
273
 
273
 
Line 349... Line 349...
349
    FStringList.Strings[i] := StringReplace(FStringList.Strings[i], ' ', '', [rfReplaceAll]);
349
    FStringList.Strings[i] := StringReplace(FStringList.Strings[i], ' ', '', [rfReplaceAll]);
350
    if FStringList.Strings[i] = '' then FStringList.Delete(i);
350
    if FStringList.Strings[i] = '' then FStringList.Delete(i);
351
  end;
351
  end;
352
end;
352
end;
353
 
353
 
354
function TLevel.LevelStringToLevelArray(ShowErrors: boolean): TLevelArray;
354
procedure TLevel.FillPlaygroundMatrix(var matrix: TPlayGroundMatrix; ShowErrors: boolean);
355
var
355
var
356
  i: integer;
356
  i: integer;
357
  t: TFieldType;
357
  t: TFieldType;
358
  err: TLevelError;
358
  err: TLevelError;
359
  y: Integer;
359
  y: Integer;
360
  x: Integer;
360
  x: Integer;
361
  Line: string;
361
  Line: string;
362
  lch, uch: char;
362
  lch, uch: char;
363
  ch: char;
363
  ch: char;
-
 
364
  width: Integer;
-
 
365
  height: Integer;
-
 
366
  lineIndent: Integer;
364
begin
367
begin
365
  // Zuerst nach Fehlern suchen
368
  // Zuerst nach Fehlern suchen
366
  err := CheckLevelIntegrity(ShowErrors);
369
  err := CheckLevelIntegrity(ShowErrors);
367
  if err <> leNone then exit;
370
  if err <> leNone then exit;
368
 
371
 
-
 
372
  // Breite feststellen
-
 
373
  if FStringList.Count > NUM_HEADERS then
-
 
374
  begin
-
 
375
    Line := FStringList.Strings[NUM_HEADERS];
-
 
376
    Line := StringReplace(Line, '.', '', [rfReplaceAll]);
-
 
377
    width := Length(Line);
-
 
378
  end
-
 
379
  else width := 0;
-
 
380
 
-
 
381
  // Höhe feststellen
-
 
382
  height := FStringList.Count - NUM_HEADERS;
-
 
383
 
369
  // Nun Matrix aufbauen
384
  // Nun Matrix aufbauen
370
  SetLength(result, 0);
385
  matrix.ClearMatrix(true);
-
 
386
  matrix.InitFieldArray(width, height);
371
  for i := NUM_HEADERS to FStringList.Count-1 do
387
  for i := NUM_HEADERS to FStringList.Count-1 do
372
  begin
388
  begin
373
    y := i - NUM_HEADERS;
389
    y := i - NUM_HEADERS;
374
 
390
 
375
    SetLength(result, Length(result)+1); // add line to matrix
-
 
376
 
-
 
377
    Line := FStringList.Strings[i];
391
    Line := FStringList.Strings[i];
378
    result[y].Indent := DotsAtBeginning(Line) - DotsAtEnd(Line);
392
    lineIndent := DotsAtBeginning(Line) - DotsAtEnd(Line);
379
    Line := StringReplace(Line, '.', '', [rfReplaceAll]);
393
    Line := StringReplace(Line, '.', '', [rfReplaceAll]);
380
    SetLength(result[y].Fields, Length(Line));
-
 
381
 
394
 
382
    for x := 0 to Length(Line)-1 do
395
    for x := 0 to Length(Line)-1 do
383
    begin
396
    begin
384
      ch := Line[x+1];
397
      ch := Line[x+1];
385
      lch := LowerCase(ch)[1];
398
      lch := LowerCase(ch)[1];
Line 392... Line 405...
392
        'r': t := ftRed;
405
        'r': t := ftRed;
393
        'y': t := ftYellow;
406
        'y': t := ftYellow;
394
        'g': t := ftGreen;
407
        'g': t := ftGreen;
395
      end;
408
      end;
396
 
409
 
-
 
410
      matrix.Fields[x,y].Indent := lineIndent;
397
      result[y].Fields[x].Typ := t;
411
      matrix.Fields[x,y].FieldType := t;
398
      result[y].Fields[x].Goal := (ch = uch) and (ch <> lch);
412
      matrix.Fields[x,y].Goal := (ch = uch) and (ch <> lch);
399
    end;
413
    end;
400
  end;
414
  end;
401
end;
415
end;
402
 
416
 
403
function TLevel.CheckLevelIntegrity(ShowErrors: boolean): TLevelError;
417
function TLevel.CheckLevelIntegrity(ShowErrors: boolean): TLevelError;
Line 438... Line 452...
438
  begin
452
  begin
439
    result := leUnsupportedVersion;
453
    result := leUnsupportedVersion;
440
    exit;
454
    exit;
441
  end;
455
  end;
442
 
456
 
-
 
457
  if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and
443
  if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and (LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then
458
      (LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then
444
  begin
459
  begin
445
    result := leUnsupportedMode;
460
    result := leUnsupportedMode;
446
    exit;
461
    exit;
447
  end;
462
  end;
448
 
463
 
Line 462... Line 477...
462
  for i := NUM_HEADERS to FStringList.Count-1 do
477
  for i := NUM_HEADERS to FStringList.Count-1 do
463
  begin
478
  begin
464
    thisLine := StringReplace(FStringList.Strings[i], '.', '', [rfReplaceAll]);
479
    thisLine := StringReplace(FStringList.Strings[i], '.', '', [rfReplaceAll]);
465
    if Length(thisLine) <> Length(firstLine) then
480
    if Length(thisLine) <> Length(firstLine) then
466
    begin
481
    begin
467
      result := leRowInvalidLength; // at row y-NUM_HEADERS
482
      result := leRowInvalidLength; // at row y = i-NUM_HEADERS
468
      exit;
483
      exit;
469
    end;
484
    end;
470
  end;
485
  end;
471
 
486
 
472
  // Check 4: Gibt es ungültige Elemente in den Zeilen?
487
  // Check 4: Gibt es ungültige Elemente in den Zeilen?
Line 482... Line 497...
482
    Line := StringReplace(Line, 'g', '', [rfReplaceAll, rfIgnoreCase]);
497
    Line := StringReplace(Line, 'g', '', [rfReplaceAll, rfIgnoreCase]);
483
    Line := StringReplace(Line, 'e', '', [rfReplaceAll, rfIgnoreCase]);
498
    Line := StringReplace(Line, 'e', '', [rfReplaceAll, rfIgnoreCase]);
484
 
499
 
485
    if Length(Line) > 0 then
500
    if Length(Line) > 0 then
486
    begin
501
    begin
487
      result := leInvalidElement; // at row y-NUM_HEADERS
502
      result := leInvalidElement; // at row y = i-NUM_HEADERS
488
      Exit;
503
      Exit;
489
    end;
504
    end;
490
  end;
505
  end;
491
 
506
 
492
  // Check 5: Kann im Level gesprungen werden?
507
  // Check 5: Kann im Level gesprungen werden?