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