Rev 24 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit LevelFunctions; |
2 | |||
3 | interface |
||
4 | |||
5 | uses |
||
21 | daniel-mar | 6 | SysUtils, Dialogs, Functions, ExtCtrls, Classes, Math; |
1 | daniel-mar | 7 | |
8 | type |
||
25 | daniel-mar | 9 | TFieldType = (ftUndefined, ftFullSpace, ftEmpty, ftRed, ftYellow, ftGreen); |
10 | |||
11 | TFieldState = (fsUndefined, fsLocked, fsAvailable, fsOccupied); |
||
12 | |||
13 | TGameMode = (gmUndefined, gmNormal, gmDiagonal); |
||
14 | |||
15 | TLevelError = (leUndefined, leNone, leInvalidElement, leEmptyBoard, |
||
16 | leRowInvalidLength, leUnsupportedVersion, leUnsupportedMode); |
||
17 | |||
18 | TGoalStatus = (gsUndefined, gsNoGoal, gsMultipleStonesRemaining, |
||
19 | gsLastStoneInGoalRed, gsLastStoneInGoalYellow, |
||
20 | gsLastStoneInGoalGreen, gsLastStoneOutsideGoal); |
||
21 | |||
23 | daniel-mar | 22 | TCoord = record |
23 | X: integer; |
||
24 | Y: integer; |
||
25 | end; |
||
26 | |||
21 | daniel-mar | 27 | TField = record |
24 | daniel-mar | 28 | Indent: integer; |
21 | daniel-mar | 29 | FieldType: TFieldType; |
30 | Goal: Boolean; |
||
31 | Panel: TPanel; |
||
32 | Stone: TImage; |
||
33 | end; |
||
34 | |||
35 | TPlayGroundMatrix = record |
||
36 | Fields: array of array of TField; |
||
37 | public |
||
23 | daniel-mar | 38 | procedure InitFieldArray(width, height: integer); |
21 | daniel-mar | 39 | function MatrixHasGoal: boolean; |
25 | daniel-mar | 40 | function GoalStatus(StonesRemaining: integer): TGoalStatus; |
21 | daniel-mar | 41 | function GoalFieldType: TFieldType; |
42 | function MatrixWorth: integer; |
||
43 | procedure ClearMatrix(FreeVCL: boolean); |
||
44 | function CloneMatrix: TPlayGroundMatrix; |
||
23 | daniel-mar | 45 | class function FieldState(t: TFieldType): TFieldState; overload; static; |
21 | daniel-mar | 46 | function FieldState(f: TField): TFieldState; overload; |
47 | function FieldState(x, y: integer): TFieldState; overload; |
||
25 | daniel-mar | 48 | function FieldState(c: TCoord): TFieldState; overload; |
22 | daniel-mar | 49 | function CanJump(SourceX, SourceY, DestX, DestY: integer; DiagonalOK: boolean): boolean; overload; |
24 | daniel-mar | 50 | function CanJump(Source, Dest: TCoord; DiagonalOK: boolean): boolean; overload; |
22 | daniel-mar | 51 | function CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean; overload; |
24 | daniel-mar | 52 | function CanJump(Source: TCoord; DiagonalOK: boolean): boolean; overload; |
22 | daniel-mar | 53 | function CanJump(DiagonalOK: boolean): boolean; overload; |
23 | daniel-mar | 54 | function IndexToCoord(index: integer): TCoord; |
55 | function CoordToIndex(coord: TCoord): integer; overload; |
||
56 | function CoordToIndex(x, y: integer): integer; overload; |
||
57 | function Width: integer; |
||
58 | function Height: integer; |
||
21 | daniel-mar | 59 | end; |
60 | |||
24 | daniel-mar | 61 | TLevel = class(TObject) |
62 | private |
||
63 | FStringList: TStringList; |
||
64 | procedure Load(ABoardFile: string); |
||
65 | function GetGameMode: TGameMode; |
||
66 | public |
||
67 | constructor Create(ABoardFile: string); |
||
68 | destructor Destroy; override; |
||
69 | procedure FillPlaygroundMatrix(var matrix: TPlayGroundMatrix; ShowErrors: boolean); |
||
70 | function CheckLevelIntegrity: TLevelError; overload; |
||
71 | function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload; |
||
72 | property GameMode: TGameMode read GetGameMode; |
||
73 | end; |
||
74 | |||
8 | daniel-mar | 75 | function FieldTypeWorth(t: TFieldType): integer; |
1 | daniel-mar | 76 | |
77 | implementation |
||
78 | |||
25 | daniel-mar | 79 | uses |
80 | Constants; |
||
81 | |||
21 | daniel-mar | 82 | function FieldTypeWorth(t: TFieldType): integer; |
83 | begin |
||
25 | daniel-mar | 84 | if t = ftGreen then result := WORTH_GREEN |
85 | else if t = ftYellow then result := WORTH_YELLOW |
||
86 | else if t = ftRed then result := WORTH_RED |
||
21 | daniel-mar | 87 | else result := 0; |
88 | end; |
||
89 | |||
90 | { TPlayGroundMatrix } |
||
91 | |||
92 | function TPlayGroundMatrix.MatrixHasGoal: boolean; |
||
1 | daniel-mar | 93 | var |
22 | daniel-mar | 94 | x, y: integer; |
1 | daniel-mar | 95 | begin |
21 | daniel-mar | 96 | result := false; |
22 | daniel-mar | 97 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 98 | begin |
22 | daniel-mar | 99 | for y := Low(Fields[x]) to High(Fields[x]) do |
21 | daniel-mar | 100 | begin |
23 | daniel-mar | 101 | result := result or Fields[x,y].Goal; |
21 | daniel-mar | 102 | end; |
103 | end; |
||
104 | end; |
||
1 | daniel-mar | 105 | |
25 | daniel-mar | 106 | function TPlayGroundMatrix.GoalStatus(StonesRemaining: integer): TGoalStatus; |
107 | var |
||
108 | ft: TFieldType; |
||
109 | begin |
||
110 | if not MatrixHasGoal then |
||
111 | result := gsNoGoal |
||
112 | else if StonesRemaining > 1 then |
||
113 | Result := gsMultipleStonesRemaining |
||
114 | else |
||
115 | begin |
||
116 | ft := GoalFieldType; |
||
117 | if ft = ftRed then |
||
118 | result := gsLastStoneInGoalRed |
||
119 | else if ft = ftYellow then |
||
120 | result := gsLastStoneInGoalYellow |
||
121 | else if ft = ftGreen then |
||
122 | result := gsLastStoneInGoalGreen |
||
123 | else |
||
124 | result := gsUndefined; |
||
125 | end; |
||
126 | end; |
||
127 | |||
21 | daniel-mar | 128 | function TPlayGroundMatrix.GoalFieldType: TFieldType; |
129 | var |
||
22 | daniel-mar | 130 | x, y: integer; |
21 | daniel-mar | 131 | begin |
132 | result := ftEmpty; // Damit der Compiler nicht meckert |
||
22 | daniel-mar | 133 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 134 | begin |
22 | daniel-mar | 135 | for y := Low(Fields[x]) to High(Fields[x]) do |
21 | daniel-mar | 136 | begin |
23 | daniel-mar | 137 | if Fields[x,y].Goal then result := Fields[x,y].FieldType |
21 | daniel-mar | 138 | end; |
139 | end; |
||
140 | end; |
||
1 | daniel-mar | 141 | |
23 | daniel-mar | 142 | function TPlayGroundMatrix.Height: integer; |
143 | begin |
||
144 | if Length(Fields) = 0 then |
||
145 | result := 0 |
||
146 | else |
||
147 | result := Length(Fields[0]); |
||
148 | end; |
||
149 | |||
150 | function TPlayGroundMatrix.IndexToCoord(index: integer): TCoord; |
||
151 | begin |
||
152 | result.X := index mod Width; |
||
153 | result.Y := index div Width; |
||
154 | end; |
||
155 | |||
156 | procedure TPlayGroundMatrix.InitFieldArray(width, height: integer); |
||
157 | var |
||
158 | x, y: integer; |
||
159 | begin |
||
160 | SetLength(Fields, width, height); |
||
161 | for x := Low(Fields) to High(Fields) do |
||
162 | begin |
||
163 | for y := Low(Fields[x]) to High(Fields[x]) do |
||
164 | begin |
||
24 | daniel-mar | 165 | Fields[x,y].FieldType := ftUndefined |
23 | daniel-mar | 166 | end; |
167 | end; |
||
168 | end; |
||
169 | |||
21 | daniel-mar | 170 | function TPlayGroundMatrix.MatrixWorth: integer; |
171 | var |
||
22 | daniel-mar | 172 | x, y: integer; |
21 | daniel-mar | 173 | begin |
174 | result := 0; |
||
22 | daniel-mar | 175 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 176 | begin |
22 | daniel-mar | 177 | for y := Low(Fields[x]) to High(Fields[x]) do |
21 | daniel-mar | 178 | begin |
23 | daniel-mar | 179 | Inc(result, FieldTypeWorth(Fields[x,y].FieldType)); |
21 | daniel-mar | 180 | end; |
181 | end; |
||
182 | end; |
||
1 | daniel-mar | 183 | |
23 | daniel-mar | 184 | function TPlayGroundMatrix.Width: integer; |
185 | begin |
||
186 | result := Length(Fields); |
||
187 | end; |
||
188 | |||
24 | daniel-mar | 189 | function TPlayGroundMatrix.CanJump(Source: TCoord; |
190 | DiagonalOK: boolean): boolean; |
||
191 | begin |
||
192 | result := CanJump(Source.X, Source.Y, DiagonalOK); |
||
193 | end; |
||
194 | |||
195 | function TPlayGroundMatrix.CanJump(Source, Dest: TCoord; |
||
196 | DiagonalOK: boolean): boolean; |
||
197 | begin |
||
198 | result := CanJump(Source.X, Source.Y, Dest.X, Dest.Y, DiagonalOK); |
||
199 | end; |
||
200 | |||
21 | daniel-mar | 201 | procedure TPlayGroundMatrix.ClearMatrix(FreeVCL: boolean); |
202 | var |
||
22 | daniel-mar | 203 | x, y: integer; |
21 | daniel-mar | 204 | begin |
24 | daniel-mar | 205 | if FreeVCL then |
1 | daniel-mar | 206 | begin |
24 | daniel-mar | 207 | for x := Low(Fields) to High(Fields) do |
1 | daniel-mar | 208 | begin |
24 | daniel-mar | 209 | for y := Low(Fields[x]) to High(Fields[x]) do |
21 | daniel-mar | 210 | begin |
23 | daniel-mar | 211 | if Assigned(Fields[x,y].Stone) then Fields[x,y].Stone.Free; |
212 | if Assigned(Fields[x,y].Panel) then Fields[x,y].Panel.Free; |
||
1 | daniel-mar | 213 | end; |
21 | daniel-mar | 214 | end; |
215 | end; |
||
23 | daniel-mar | 216 | SetLength(Fields, 0, 0); |
21 | daniel-mar | 217 | end; |
1 | daniel-mar | 218 | |
21 | daniel-mar | 219 | function TPlayGroundMatrix.CloneMatrix: TPlayGroundMatrix; |
220 | var |
||
22 | daniel-mar | 221 | x, y: integer; |
21 | daniel-mar | 222 | begin |
223 | SetLength(result.Fields, Length(Fields)); |
||
22 | daniel-mar | 224 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 225 | begin |
22 | daniel-mar | 226 | SetLength(result.Fields[x], Length(Fields[x])); |
227 | for y := Low(Fields[x]) to High(Fields[x]) do |
||
21 | daniel-mar | 228 | begin |
23 | daniel-mar | 229 | result.Fields[x,y].FieldType := Fields[x,y].FieldType; |
230 | result.Fields[x,y].Goal := Fields[x,y].Goal; |
||
231 | result.Fields[x,y].Panel := Fields[x,y].Panel; |
||
232 | result.Fields[x,y].Stone := Fields[x,y].Stone; |
||
1 | daniel-mar | 233 | end; |
234 | end; |
||
235 | end; |
||
236 | |||
23 | daniel-mar | 237 | function TPlayGroundMatrix.CoordToIndex(x, y: integer): integer; |
1 | daniel-mar | 238 | begin |
24 | daniel-mar | 239 | result := x + y * Width; |
23 | daniel-mar | 240 | end; |
241 | |||
25 | daniel-mar | 242 | function TPlayGroundMatrix.FieldState(c: TCoord): TFieldState; |
243 | begin |
||
244 | result := FieldState(c.X, c.Y); |
||
245 | end; |
||
246 | |||
23 | daniel-mar | 247 | function TPlayGroundMatrix.CoordToIndex(coord: TCoord): integer; |
248 | begin |
||
24 | daniel-mar | 249 | result := CoordToIndex(coord.X, coord.Y); |
23 | daniel-mar | 250 | end; |
251 | |||
252 | class function TPlayGroundMatrix.FieldState(t: TFieldType): TFieldState; |
||
253 | begin |
||
24 | daniel-mar | 254 | result := fsUndefined; |
21 | daniel-mar | 255 | case t of |
256 | ftFullSpace: result := fsLocked; |
||
257 | ftEmpty: result := fsAvailable; |
||
24 | daniel-mar | 258 | ftGreen: result := fsOccupied; |
259 | ftYellow: result := fsOccupied; |
||
260 | ftRed: result := fsOccupied; |
||
21 | daniel-mar | 261 | end; |
1 | daniel-mar | 262 | end; |
263 | |||
21 | daniel-mar | 264 | function TPlayGroundMatrix.FieldState(f: TField): TFieldState; |
265 | begin |
||
266 | result := FieldState(f.FieldType); |
||
267 | end; |
||
268 | |||
269 | function TPlayGroundMatrix.FieldState(x, y: integer): TFieldState; |
||
270 | begin |
||
24 | daniel-mar | 271 | result := fsUndefined; |
21 | daniel-mar | 272 | if (x < Low(Fields)) or (x > High(Fields)) then exit; |
273 | if (y < Low(Fields[x])) or (y > High(Fields[x])) then exit; |
||
274 | |||
23 | daniel-mar | 275 | result := FieldState(Fields[x,y]); |
21 | daniel-mar | 276 | end; |
277 | |||
22 | daniel-mar | 278 | function TPlayGroundMatrix.CanJump(SourceX, SourceY, DestX, DestY: integer; DiagonalOK: boolean): boolean; |
279 | begin |
||
280 | result := false; |
||
281 | |||
282 | // Check 1: Ist das Zielfeld überhaupt leer? |
||
283 | if FieldState(DestX, DestY) <> fsAvailable then exit; |
||
284 | |||
285 | // Check 2: Befindet sich ein Stein zwischen Source und Destination und ist der Abstand 2? |
||
286 | if DiagonalOK then |
||
287 | begin |
||
24 | daniel-mar | 288 | if (SourceX-2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX-1, SourceY-1) = fsOccupied) then result := true; |
289 | if (SourceX-2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX-1, SourceY+1) = fsOccupied) then result := true; |
||
290 | if (SourceX+2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX+1, SourceY-1) = fsOccupied) then result := true; |
||
291 | if (SourceX+2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX+1, SourceY+1) = fsOccupied) then result := true; |
||
22 | daniel-mar | 292 | end; |
293 | |||
24 | daniel-mar | 294 | if (SourceX+2 = DestX) and (SourceY = DestY) and (FieldState(SourceX+1, SourceY ) = fsOccupied) then result := true; |
295 | if (SourceX-2 = DestX) and (SourceY = DestY) and (FieldState(SourceX-1, SourceY ) = fsOccupied) then result := true; |
||
296 | if (SourceX = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX , SourceY+1) = fsOccupied) then result := true; |
||
297 | if (SourceX = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX , SourceY-1) = fsOccupied) then result := true; |
||
22 | daniel-mar | 298 | end; |
299 | |||
300 | function TPlayGroundMatrix.CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean; |
||
301 | begin |
||
24 | daniel-mar | 302 | if FieldState(SourceX, SourceY) <> fsOccupied then |
22 | daniel-mar | 303 | begin |
304 | result := false; |
||
305 | exit; |
||
306 | end; |
||
307 | |||
308 | result := true; |
||
309 | |||
310 | if CanJump(SourceX, SourceY, SourceX+2, SourceY, DiagonalOK) then exit; |
||
311 | if CanJump(SourceX, SourceY, SourceX-2, SourceY, DiagonalOK) then exit; |
||
312 | if CanJump(SourceX, SourceY, SourceX, SourceY+2, DiagonalOK) then exit; |
||
313 | if CanJump(SourceX, SourceY, SourceX, SourceY-2, DiagonalOK) then exit; |
||
314 | |||
315 | if DiagonalOK then |
||
316 | begin |
||
317 | if CanJump(SourceX, SourceY, SourceX-2, SourceY-2, DiagonalOK) then exit; |
||
318 | if CanJump(SourceX, SourceY, SourceX+2, SourceY-2, DiagonalOK) then exit; |
||
319 | if CanJump(SourceX, SourceY, SourceX-2, SourceY+2, DiagonalOK) then exit; |
||
320 | if CanJump(SourceX, SourceY, SourceX+2, SourceY+2, DiagonalOK) then exit; |
||
321 | end; |
||
322 | |||
323 | result := false; |
||
324 | end; |
||
325 | |||
326 | function TPlayGroundMatrix.CanJump(DiagonalOK: boolean): boolean; |
||
327 | var |
||
328 | x, y: integer; |
||
329 | begin |
||
330 | result := false; |
||
331 | for x := Low(Fields) to High(Fields) do |
||
332 | begin |
||
333 | for y := Low(Fields[x]) to High(Fields[x]) do |
||
334 | begin |
||
335 | if CanJump(x, y, DiagonalOK) then |
||
336 | begin |
||
337 | result := true; |
||
338 | break; |
||
339 | end; |
||
340 | if result then break; |
||
341 | end; |
||
342 | end; |
||
343 | end; |
||
344 | |||
11 | daniel-mar | 345 | { TLevel } |
346 | |||
347 | const NUM_HEADERS = 2; |
||
348 | |||
349 | constructor TLevel.Create(ABoardFile: string); |
||
1 | daniel-mar | 350 | begin |
11 | daniel-mar | 351 | inherited Create; |
352 | FStringList := TStringList.Create; |
||
353 | Load(ABoardFile); |
||
1 | daniel-mar | 354 | end; |
355 | |||
11 | daniel-mar | 356 | destructor TLevel.Destroy; |
1 | daniel-mar | 357 | begin |
11 | daniel-mar | 358 | FreeAndNil(FStringList); |
359 | |||
360 | inherited; |
||
1 | daniel-mar | 361 | end; |
362 | |||
11 | daniel-mar | 363 | function TLevel.GetGameMode: TGameMode; |
364 | begin |
||
365 | if LowerCase(FStringList.Strings[1]) = 'mode: normal' then |
||
366 | result := gmNormal |
||
367 | else if LowerCase(FStringList.Strings[1]) = 'mode: diagonal' then |
||
368 | result := gmDiagonal |
||
369 | else |
||
370 | result := gmUndefined; |
||
371 | end; |
||
372 | |||
373 | procedure TLevel.Load(ABoardFile: string); |
||
1 | daniel-mar | 374 | var |
11 | daniel-mar | 375 | i: Integer; |
1 | daniel-mar | 376 | begin |
11 | daniel-mar | 377 | FStringList.Clear; |
378 | FStringList.LoadFromFile(ABoardFile); |
||
1 | daniel-mar | 379 | |
11 | daniel-mar | 380 | // Remove whitespaces and empty lines |
381 | for i := FStringList.Count-1 downto NUM_HEADERS do |
||
1 | daniel-mar | 382 | begin |
11 | daniel-mar | 383 | FStringList.Strings[i] := StringReplace(FStringList.Strings[i], ' ', '', [rfReplaceAll]); |
384 | if FStringList.Strings[i] = '' then FStringList.Delete(i); |
||
1 | daniel-mar | 385 | end; |
11 | daniel-mar | 386 | end; |
1 | daniel-mar | 387 | |
24 | daniel-mar | 388 | procedure TLevel.FillPlaygroundMatrix(var matrix: TPlayGroundMatrix; ShowErrors: boolean); |
11 | daniel-mar | 389 | var |
390 | i: integer; |
||
391 | t: TFieldType; |
||
392 | err: TLevelError; |
||
393 | y: Integer; |
||
394 | x: Integer; |
||
395 | Line: string; |
||
396 | lch, uch: char; |
||
397 | ch: char; |
||
24 | daniel-mar | 398 | width: Integer; |
399 | height: Integer; |
||
400 | lineIndent: Integer; |
||
11 | daniel-mar | 401 | begin |
402 | // Zuerst nach Fehlern suchen |
||
403 | err := CheckLevelIntegrity(ShowErrors); |
||
404 | if err <> leNone then exit; |
||
405 | |||
24 | daniel-mar | 406 | // Breite feststellen |
407 | if FStringList.Count > NUM_HEADERS then |
||
408 | begin |
||
409 | Line := FStringList.Strings[NUM_HEADERS]; |
||
410 | Line := StringReplace(Line, '.', '', [rfReplaceAll]); |
||
411 | width := Length(Line); |
||
412 | end |
||
413 | else width := 0; |
||
414 | |||
415 | // Höhe feststellen |
||
416 | height := FStringList.Count - NUM_HEADERS; |
||
417 | |||
11 | daniel-mar | 418 | // Nun Matrix aufbauen |
24 | daniel-mar | 419 | matrix.ClearMatrix(true); |
420 | matrix.InitFieldArray(width, height); |
||
11 | daniel-mar | 421 | for i := NUM_HEADERS to FStringList.Count-1 do |
1 | daniel-mar | 422 | begin |
11 | daniel-mar | 423 | y := i - NUM_HEADERS; |
1 | daniel-mar | 424 | |
11 | daniel-mar | 425 | Line := FStringList.Strings[i]; |
24 | daniel-mar | 426 | lineIndent := DotsAtBeginning(Line) - DotsAtEnd(Line); |
19 | daniel-mar | 427 | Line := StringReplace(Line, '.', '', [rfReplaceAll]); |
1 | daniel-mar | 428 | |
19 | daniel-mar | 429 | for x := 0 to Length(Line)-1 do |
11 | daniel-mar | 430 | begin |
19 | daniel-mar | 431 | ch := Line[x+1]; |
11 | daniel-mar | 432 | lch := LowerCase(ch)[1]; |
433 | uch := UpperCase(ch)[1]; |
||
19 | daniel-mar | 434 | |
435 | t := ftUndefined; |
||
11 | daniel-mar | 436 | case lch of |
437 | '*': t := ftFullSpace; |
||
438 | 'e': t := ftEmpty; |
||
439 | 'r': t := ftRed; |
||
440 | 'y': t := ftYellow; |
||
441 | 'g': t := ftGreen; |
||
442 | end; |
||
1 | daniel-mar | 443 | |
24 | daniel-mar | 444 | matrix.Fields[x,y].Indent := lineIndent; |
445 | matrix.Fields[x,y].FieldType := t; |
||
446 | matrix.Fields[x,y].Goal := (ch = uch) and (ch <> lch); |
||
11 | daniel-mar | 447 | end; |
448 | end; |
||
449 | end; |
||
450 | |||
451 | function TLevel.CheckLevelIntegrity(ShowErrors: boolean): TLevelError; |
||
452 | resourcestring |
||
453 | LNG_LVL_INVALID_ELEMENT = 'Level invalid: There are invalid elements in the file.'+#13#10#13#10+'Valid elements are r/R, y/Y, g/G, e/E, . and *.'; |
||
454 | LNG_LVL_UNSUPPORTED_VERSION = 'Level format invalid: Version not supported.'; |
||
455 | LNG_LVL_UNSUPPORTED_MODE = 'Level format invalid: Mode not supported.'; |
||
456 | LNG_LVL_EMPTY_BOARD = 'Level invalid: Board is empty.'; |
||
457 | LNG_LVL_INVALID_LENGTH = 'Level invalid: Lines don''t have an equal amount of elements.'; |
||
458 | begin |
||
459 | result := CheckLevelIntegrity; |
||
460 | if ShowErrors then |
||
1 | daniel-mar | 461 | begin |
11 | daniel-mar | 462 | case result of |
463 | leNone: ; |
||
464 | leInvalidElement: MessageDlg(LNG_LVL_INVALID_ELEMENT, mtError, [mbOk], 0); |
||
465 | leUnsupportedVersion: MessageDlg(LNG_LVL_UNSUPPORTED_VERSION, mtError, [mbOk], 0); |
||
466 | leUnsupportedMode: MessageDlg(LNG_LVL_UNSUPPORTED_MODE, mtError, [mbOk], 0); |
||
467 | leEmptyBoard: MessageDlg(LNG_LVL_EMPTY_BOARD, mtError, [mbOk], 0); |
||
468 | leRowInvalidLength: MessageDlg(LNG_LVL_INVALID_LENGTH, mtError, [mbOk], 0); |
||
1 | daniel-mar | 469 | end; |
470 | end; |
||
11 | daniel-mar | 471 | end; |
1 | daniel-mar | 472 | |
11 | daniel-mar | 473 | function TLevel.CheckLevelIntegrity: TLevelError; |
474 | var |
||
19 | daniel-mar | 475 | tmp: string; |
11 | daniel-mar | 476 | i: Integer; |
477 | Line: string; |
||
19 | daniel-mar | 478 | firstLine: string; |
479 | thisLine: string; |
||
11 | daniel-mar | 480 | begin |
481 | result := leNone; |
||
1 | daniel-mar | 482 | |
11 | daniel-mar | 483 | // Check 1: Ist der Header OK? |
1 | daniel-mar | 484 | |
11 | daniel-mar | 485 | if LowerCase(FStringList.Strings[0]) <> 'version 2' then |
1 | daniel-mar | 486 | begin |
11 | daniel-mar | 487 | result := leUnsupportedVersion; |
488 | exit; |
||
1 | daniel-mar | 489 | end; |
490 | |||
24 | daniel-mar | 491 | if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and |
492 | (LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then |
||
1 | daniel-mar | 493 | begin |
11 | daniel-mar | 494 | result := leUnsupportedMode; |
495 | exit; |
||
1 | daniel-mar | 496 | end; |
497 | |||
11 | daniel-mar | 498 | // Check 2: Ist das Brett leer? |
1 | daniel-mar | 499 | |
19 | daniel-mar | 500 | tmp := ''; |
501 | for i := NUM_HEADERS to FStringList.Count-1 do tmp := tmp + FStringList.Strings[i]; |
||
502 | if Trim(StringReplace(tmp, '.', '', [rfReplaceAll])) = '' then |
||
1 | daniel-mar | 503 | begin |
11 | daniel-mar | 504 | result := leEmptyBoard; |
505 | exit; |
||
1 | daniel-mar | 506 | end; |
507 | |||
11 | daniel-mar | 508 | // Check 3: Geht das Level nicht in einem Quadrat oder Rechteck auf? |
1 | daniel-mar | 509 | |
19 | daniel-mar | 510 | firstLine := StringReplace(FStringList.Strings[NUM_HEADERS], '.', '', [rfReplaceAll]); |
11 | daniel-mar | 511 | for i := NUM_HEADERS to FStringList.Count-1 do |
1 | daniel-mar | 512 | begin |
19 | daniel-mar | 513 | thisLine := StringReplace(FStringList.Strings[i], '.', '', [rfReplaceAll]); |
514 | if Length(thisLine) <> Length(firstLine) then |
||
11 | daniel-mar | 515 | begin |
24 | daniel-mar | 516 | result := leRowInvalidLength; // at row y = i-NUM_HEADERS |
11 | daniel-mar | 517 | exit; |
518 | end; |
||
1 | daniel-mar | 519 | end; |
520 | |||
11 | daniel-mar | 521 | // Check 4: Gibt es ungültige Elemente in den Zeilen? |
1 | daniel-mar | 522 | |
11 | daniel-mar | 523 | for i := NUM_HEADERS to FStringList.Count-1 do |
524 | begin |
||
525 | Line := FStringList.Strings[i]; |
||
1 | daniel-mar | 526 | |
11 | daniel-mar | 527 | Line := StringReplace(Line, '.', '', [rfReplaceAll]); |
528 | Line := StringReplace(Line, '*', '', [rfReplaceAll]); |
||
529 | Line := StringReplace(Line, 'r', '', [rfReplaceAll, rfIgnoreCase]); |
||
530 | Line := StringReplace(Line, 'y', '', [rfReplaceAll, rfIgnoreCase]); |
||
531 | Line := StringReplace(Line, 'g', '', [rfReplaceAll, rfIgnoreCase]); |
||
532 | Line := StringReplace(Line, 'e', '', [rfReplaceAll, rfIgnoreCase]); |
||
1 | daniel-mar | 533 | |
11 | daniel-mar | 534 | if Length(Line) > 0 then |
1 | daniel-mar | 535 | begin |
24 | daniel-mar | 536 | result := leInvalidElement; // at row y = i-NUM_HEADERS |
11 | daniel-mar | 537 | Exit; |
1 | daniel-mar | 538 | end; |
539 | end; |
||
540 | |||
22 | daniel-mar | 541 | // Check 5: Kann im Level gesprungen werden? |
11 | daniel-mar | 542 | |
543 | { Wird hier nicht abgeprüft, da dafür zuerst der PlayGround gebaut sein muss. |
||
544 | Es ist außerdem eher ein logischer Fehler, kein Fehler in der Levelstruktur! } |
||
8 | daniel-mar | 545 | end; |
546 | |||
1 | daniel-mar | 547 | end. |