-
Hallo,
ich bin gerade dabei ein Kakuro Spiel zu schreiben und irgendwie funktioniert meine Funktion nicht so richtig.
In einer Sume dürfen keine doppelte Zufallszahlen sein.
Hier mal mein Code:
PHP-Code:var
x,y: integer;
ZaehlerX,ZaehlerY,Zaehler: integer;
Zahl: integer;
Doppelt: integer;
begin
ZaehlerX:=0;
ZaehlerY:=0;
Doppelt:=0;
Zahl:=0;
Zaehler:=0;
for y:=0 to 11 do begin
for x:=0 to 11 do begin
Doppelt := 0;
Zaehler := 0;
Zahl := 0;
if (Spielfeld[x][y].Feld = 'N') then
begin
repeat
Form1.Canvas.Draw(x*36-x,y*36-y,Image1.Picture.Bitmap);
if (Doppelt = 1) then
begin
Spielfeld[x][y].Wert := Zahl;
Doppelt := 0;
end
else begin
Zahl := random(9)+1;
Spielfeld[x][y].Wert := Zahl;
Doppelt := 0;
end;
ZaehlerX := x;
ZaehlerY := y;
while (ZaehlerX > 0) do begin
ZaehlerX := ZaehlerX - 1;
if ((Spielfeld[ZaehlerX][y].Feld = 'M') or (Spielfeld[ZaehlerX][y].Feld = 'S')) then
begin
break;
end;
if (Spielfeld[ZaehlerX][y].Wert = Zahl) then
begin
Doppelt := 1;
break;
end;
end;
while (ZaehlerY > 0) do begin
ZaehlerY := ZaehlerY - 1;
if ((Spielfeld[x][ZaehlerY].Feld = 'M') or (Spielfeld[x][ZaehlerY].Feld = 'S')) then
begin
break;
end;
if (Spielfeld[x][ZaehlerY].Wert = Zahl) then
begin
Doppelt := 1;
break;
end;
end;
if (Doppelt = 1) then
begin
Spielfeld[x][y].Wert := 0;
Zahl := Zahl + 1;
Zaehler := Zaehler + 1;
if (Zaehler > 9) then
begin
break;
end;
if (Zahl > 9) then Zahl := 1;
end;
until Doppelt = 0;
end;
end;
end;
Mein Code funktioniert manchmal, die Schleife hängt sich aber manchmal auf, deshalb habe ich einen weiteren Zähler eingebaut, der die Schleife abbricht, wenn Zaehler > 9 ist.PHP-Code:Spielfeld[x][y].Feld = 'N' //=Felder, in denen die Zufallszahlen rein sollen
Spielfeld[x][y].Feld = 'M' //=Normaler Block
Spielfeld[x][y].Feld = 'S' // =Sume Block
Kann mir da vll jemand weiterhelfen?
MfG
-
26.01.09 14:16 #2
- Registriert seit
- Mar 2004
- Beiträge
- 441
Möglicherweise. Aber ich habe keine Ahnung, was "Kakuro" ist.
Bevor ist mich an eine Lösung wagen kann, hätte ich ein paar Fragen:
- Wie sieht das "Spielfeld" größentechnisch aus?
- Was sollen die ganzen "M", "N" und "S"?
- Was für Werte willst du wo reinschreiben?
- Was meinst du mit "doppelten Zufallszahlen"?
-
Erstmal Danke für die antwort.
Also, S sind die Sume Felder, M sind die einfache Blöcke und N für die Zahlen.
Hier mal ein Bild von mir:
http://www.qpic.ws/viewimage.php?fil...s/G5N77793.png
Da wo S steht, dürfen keine Doppelte Zahlen vorhanden sein, bis ein weiterer Block kommt oder ein S Feld, also in einer Sume dürfen keine Doppelte Zahlen vorkommen.
Mein Code funktioniert nicht immer, manchmal hängt sich mein Programm dabei auf.
Hier mal eine anleitung zu Kakuro:
http://www.knobelfieber.de/html/kakuro_anleitung.html
Ich bedanke mich schonmal im Voraus.
MfG
-
26.01.09 16:02 #4
- Registriert seit
- Mar 2004
- Beiträge
- 441
Nenn mich meinetwegen begriffsstutzig, aber ich kapiere immer noch nicht, was mit "doppelten Zahlen in Summen" gemeint ist und was dein Programm überhaupt machen soll.
Ich habe mal den von dir geposteten Source nachgebaut und das Bild als Spielfeld noch eingetragen, aber logischerweise kann da nichts passieren, da kein einziges Feld ein 'N' beinhaltet.
Und zum kompletten Durcharbeiten dieser Kakuro-Regeln habe ich momentan weder Zeit noch Lust.
-
Die Felder erstelle ich mit einem Klick auf den Button:
Also, Feld S sind die Sume Felder und die Felder N sind die Felder in denen Zahlen von 1-9 rein kommen sollen, man addiert die Zahlen die in einem Sumen Block sind, aber es dürfen in einem Sime Block keine Doppelte Zahlen existieren.PHP-Code:procedure TForm1.FormCreate(Sender: TObject);
begin
randomize();
Spielfeld[0,0].Feld := 'M';
Spielfeld[1,0].Feld := 'M';
Spielfeld[2,0].Feld := 'M';
Spielfeld[3,0].Feld := 'S';
Spielfeld[4,0].Feld := 'S';
Spielfeld[5,0].Feld := 'S';
Spielfeld[6,0].Feld := 'S';
Spielfeld[7,0].Feld := 'M';
Spielfeld[8,0].Feld := 'M';
Spielfeld[9,0].Feld := 'S';
Spielfeld[10,0].Feld := 'S';
Spielfeld[11,0].Feld := 'S';
Spielfeld[0,1].Feld := 'M';
Spielfeld[1,1].Feld := 'M';
Spielfeld[2,1].Feld := 'S';
Spielfeld[3,1].Feld := 'N';
Spielfeld[4,1].Feld := 'N';
Spielfeld[5,1].Feld := 'N';
Spielfeld[6,1].Feld := 'N';
Spielfeld[7,1].Feld := 'S';
Spielfeld[8,1].Feld := 'S';
Spielfeld[9,1].Feld := 'N';
Spielfeld[10,1].Feld := 'N';
Spielfeld[11,1].Feld := 'N';
Spielfeld[0,2].Feld := 'M';
Spielfeld[1,2].Feld := 'S';
Spielfeld[2,2].Feld := 'N';
Spielfeld[3,2].Feld := 'N';
Spielfeld[4,2].Feld := 'N';
Spielfeld[5,2].Feld := 'N';
Spielfeld[6,2].Feld := 'N';
Spielfeld[7,2].Feld := 'N';
Spielfeld[8,2].Feld := 'S';
Spielfeld[9,2].Feld := 'N';
Spielfeld[10,2].Feld := 'N';
Spielfeld[11,2].Feld := 'N';
Spielfeld[0,3].Feld := 'S';
Spielfeld[1,3].Feld := 'N';
Spielfeld[2,3].Feld := 'N';
Spielfeld[3,3].Feld := 'S';
Spielfeld[4,3].Feld := 'N';
Spielfeld[5,3].Feld := 'N';
Spielfeld[6,3].Feld := 'S';
Spielfeld[7,3].Feld := 'N';
Spielfeld[8,3].Feld := 'N';
Spielfeld[9,3].Feld := 'N';
Spielfeld[10,3].Feld := 'M';
Spielfeld[11,3].Feld := 'M';
Spielfeld[0,4].Feld := 'S';
Spielfeld[1,4].Feld := 'N';
Spielfeld[2,4].Feld := 'N';
Spielfeld[3,4].Feld := 'S';
Spielfeld[4,4].Feld := 'S';
Spielfeld[5,4].Feld := 'N';
Spielfeld[6,4].Feld := 'N';
Spielfeld[7,4].Feld := 'S';
Spielfeld[8,4].Feld := 'N';
Spielfeld[9,4].Feld := 'N';
Spielfeld[10,4].Feld := 'S';
Spielfeld[11,4].Feld := 'S';
Spielfeld[0,5].Feld := 'M';
Spielfeld[1,5].Feld := 'S';
Spielfeld[2,5].Feld := 'N';
Spielfeld[3,5].Feld := 'N';
Spielfeld[4,5].Feld := 'S';
Spielfeld[5,5].Feld := 'N';
Spielfeld[6,5].Feld := 'N';
Spielfeld[7,5].Feld := 'S';
Spielfeld[8,5].Feld := 'N';
Spielfeld[9,5].Feld := 'N';
Spielfeld[10,5].Feld := 'N';
Spielfeld[11,5].Feld := 'N';
Spielfeld[0,6].Feld := 'S';
Spielfeld[1,6].Feld := 'N';
Spielfeld[2,6].Feld := 'N';
Spielfeld[3,6].Feld := 'N';
Spielfeld[4,6].Feld := 'N';
Spielfeld[5,6].Feld := 'N';
Spielfeld[6,6].Feld := 'S';
Spielfeld[7,6].Feld := 'N';
Spielfeld[8,6].Feld := 'N';
Spielfeld[9,6].Feld := 'N';
Spielfeld[10,6].Feld := 'N';
Spielfeld[11,6].Feld := 'N';
Spielfeld[0,7].Feld := 'S';
Spielfeld[1,7].Feld := 'N';
Spielfeld[2,7].Feld := 'N';
Spielfeld[3,7].Feld := 'N';
Spielfeld[4,7].Feld := 'N';
Spielfeld[5,7].Feld := 'S';
Spielfeld[6,7].Feld := 'N';
Spielfeld[7,7].Feld := 'N';
Spielfeld[8,7].Feld := 'S';
Spielfeld[9,7].Feld := 'N';
Spielfeld[10,7].Feld := 'N';
Spielfeld[11,7].Feld := 'S';
Spielfeld[0,8].Feld := 'M';
Spielfeld[1,8].Feld := 'M';
Spielfeld[2,8].Feld := 'S';
Spielfeld[3,8].Feld := 'N';
Spielfeld[4,8].Feld := 'N';
Spielfeld[5,8].Feld := 'S';
Spielfeld[6,8].Feld := 'N';
Spielfeld[7,8].Feld := 'N';
Spielfeld[8,8].Feld := 'S';
Spielfeld[9,8].Feld := 'S';
Spielfeld[10,8].Feld := 'N';
Spielfeld[11,8].Feld := 'N';
Spielfeld[0,9].Feld := 'M';
Spielfeld[1,9].Feld := 'S';
Spielfeld[2,9].Feld := 'S';
Spielfeld[3,9].Feld := 'N';
Spielfeld[4,9].Feld := 'N';
Spielfeld[5,9].Feld := 'N';
Spielfeld[6,9].Feld := 'S';
Spielfeld[7,9].Feld := 'N';
Spielfeld[8,9].Feld := 'N';
Spielfeld[9,9].Feld := 'S';
Spielfeld[10,9].Feld := 'N';
Spielfeld[11,9].Feld := 'N';
Spielfeld[0,10].Feld := 'S';
Spielfeld[1,10].Feld := 'N';
Spielfeld[2,10].Feld := 'N';
Spielfeld[3,10].Feld := 'N';
Spielfeld[4,10].Feld := 'S';
Spielfeld[5,10].Feld := 'N';
Spielfeld[6,10].Feld := 'N';
Spielfeld[7,10].Feld := 'N';
Spielfeld[8,10].Feld := 'N';
Spielfeld[9,10].Feld := 'N';
Spielfeld[10,10].Feld := 'N';
Spielfeld[11,10].Feld := 'M';
Spielfeld[0,11].Feld := 'S';
Spielfeld[1,11].Feld := 'N';
Spielfeld[2,11].Feld := 'N';
Spielfeld[3,11].Feld := 'N';
Spielfeld[4,11].Feld := 'M';
Spielfeld[5,11].Feld := 'S';
Spielfeld[6,11].Feld := 'N';
Spielfeld[7,11].Feld := 'N';
Spielfeld[8,11].Feld := 'N';
Spielfeld[9,11].Feld := 'N';
Spielfeld[10,11].Feld := 'M';
Spielfeld[11,11].Feld := 'M';
end;
Hier mal ein beispiel:
http://www.qpic.ws/viewimage.php?fil...s/Bue85659.png
Das was ich rot markiert habe, ist ein Sumen Block, in diesem Sumen Block dürfen keine doppelte Zahlen existieren.Das was ich grün markiert habe, ist wieder ein anderer Sumen Block, auch wieder keine Doppelte Zahlen.
Ich möchte einfach alle Felder mit Zahlen versehen, ohne das sich doppelte Zahlen in einem Sumen Block befinden.
Ich hoffe, man kann es jetzt besser verstehen.
Danke schonmal.
MfG
-
26.01.09 17:55 #6
- Registriert seit
- Mar 2004
- Beiträge
- 441
Jau, jetzt (glaube ich) kapiere ich langsam, worum es geht. Ich schau mir mal deinen Source an und melde mich morgen wieder.
-
Vielen Dank.
Wenn es nicht reichen sollte, dann kann ich ja mal mein Komplette Source Posten, um es zu verdeutlichen.
MfG
-
27.01.09 05:44 #8
- Registriert seit
- Mar 2004
- Beiträge
- 441
Ok, ich habe mich jetzt mal ein bißchen mit dem Teil gespielt und nochmal deinen Anfangspost gelesen. Ich poste mal, wie weit ich die Aufgabe verstehe. Falls was falsch ist, korrigiere mich:
- Dieses Kakuro ist eine Art Kreuzworträtsel für Zahlen
- Die Summen beziehen sich auf Zeilen und Spalten
- In einer Summenzeile oder Summenspalte dürfen nur Ziffern (ist was anderes als Zahlen
) von 1 - 9 vorkommen.
- Jede Ziffer darf pro Summenzeile und -spalte nur einmal vorkommen
- Du willst ein Spielfeld erstellen und keine Lösung
Es wäre noch praktisch, wenn du mir sagen könntest, was in Image1->Picture drin ist.
Nachtrag:
Ok, ich habe mal was zusammengebastelt. Du kannst es dir ja mal bei Gelegenheit anschauen und mir sagen, ob es ungefähr in die Richtung geht, die du meinst. Falls ja, dann kann ich mal weitersuchen.
kakuro.rarGeändert von CSANecromancer (27.01.09 um 10:16 Uhr)
-
27.01.09 12:04 #9
- Registriert seit
- Mar 2004
- Beiträge
- 441
So. Ich habe mal (nach meinem Verständnis) den Kakuro-Generator gebaut und bin dabei auf ein Problem gestossen, das dem sehr ähnlich schien, wie du es beschrieben hast. Die Lösung war wirklich etwas knifflig zu finden, aber ich bin schließlich dahinter gekommen:
Mein Programm generiert das Spielfeld Feld für Feld, Zeile für Zeile, so wie in deinem Algorithmus. Jetzt kann es aber mit dem von dir geposteten Template für das Spielfeld passieren (ca. zu 10-15%), daß mein Generator die Felder dergestalt mit Ziffern belegt hat, daß er keine passende Ziffer für das Feld findet, das er aktuell bearbeitet. Sprich: Es wäre ein ungültiges Kakuro, das entsteht.
Und mit einer einfachen while-Schleife rechnet sich dann der Computer natürlich tot. Er generiert Zufallszahlen von 1 bis 9 wie ein Wilder, aber keine davon passt in das Feld, ergo: Das Programm hängt sich auf.
Bei mir habe ich es so gelöst, daß ich pro Feld 100 Versuche auf alle Ziffern durchlaufen lasse. Wenn das Feld dann immer noch nicht belegt werden konnte, wird eine entsprechende Hinweismeldung ausgegeben und die Generierung wird abgebrochen.
Wenn du willst, dann kann ich nachher noch den Source meines Kakurogenerators posten. Das Formular dazu ist pieseleinfach.
-
Vielen Dank.
Genau das meine ich, ich brauche nur den richtigen Code um die Spielfelder alle mit Zahlen zu versehen, den rest schaffe ich alleine.
Also, da wo die weise Felder sind, wo die Zahlen addiert wurden und eingetragen wurden, schaffe ich alleine.
Und wie sieht jetzt der Code aus?
Ich bin Dir sehr dankbar für die Hilfe.
MfGGeändert von jackie05 (27.01.09 um 12:08 Uhr)
-
27.01.09 13:30 #11
- Registriert seit
- Mar 2004
- Beiträge
- 441
Tja, sorry, aber nur explizit den Part mit der Berechnung der Zahlenwerte extrahieren funktioniert leider nicht, da ich den Generator komplett selber gebastelt habe und von daher auch ganz andere Algorithmen benutzt habe. Aber ich kann dir den Source von mir posten.
Das Formular dazu sieht ganz einfach aus:
Fomular selbst:
Name: Main
Darauf ein TImage:
Name: Image
Und ein TButton:
Name: btGenerate
Caption: "Generate..."
Und hier der Source dazu:
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
{*----------------------------------------------------------------------------- Kakuro Generator Auch bekannt als "Kreuzworträtsel für Legastheniker" @author The Necromancer @version 0.2 -----------------------------------------------------------------------------*} unit Dialogs.Main; interface uses Classes, Controls, Dialogs, ExtCtrls, Forms, Graphics, Messages, StdCtrls, StrUtils, SysUtils, Variants, Windows; type {*----------------------------------------------------------------------------- Record für ein einzelnes Feld des Kakurospielfelds -----------------------------------------------------------------------------*} TKakuroField = record public Name: String; Value: Integer; end; type {*----------------------------------------------------------------------------- Klassendefinition für das Hauptformular -----------------------------------------------------------------------------*} TMain = class(TForm) Image: TImage; btGenerate: TButton; procedure FormCreate(Sender: TObject); procedure btGenerateClick(Sender: TObject); private PlayingField: array[0..12, 0..12] of TKakuroField; procedure ReadingPlayingFieldTemplate(const p_Field: TStringList); procedure PlayingFieldGenerate; procedure PlayingFieldDraw; procedure DrawGrid; procedure DrawBlock( const p_X: Integer; const p_Y: Integer; const p_Color: TColor); function IsInRow(const p_Value: Integer; const p_x: Integer; const p_y: Integer): boolean; function IsInColumn(const p_Value: Integer; const p_x: Integer; const p_y: Integer): boolean; function HorizontalSum(const p_x: Integer; const p_y: Integer): Integer; function VerticalSum(const p_x: Integer; const p_y: Integer): Integer; end; var {*----------------------------------------------------------------------------- Objektdefinition für die Klasse des Hauptformulars -----------------------------------------------------------------------------*} Main: TMain; implementation {$R *.dfm} {*----------------------------------------------------------------------------- Wird vom Konstruktor aufgerufen @param Sender Handle auf das aufrufende Objekt -----------------------------------------------------------------------------*} procedure TMain.FormCreate(Sender: TObject); var strlTemplate: TStringList; x, y: Integer; begin // Um unschönes Flackern beim Neuzeichnen des Programms zu vermeiden self.DoubleBuffered := true; // Wird nur hier und einmalig aufgerufen, so wie es auch in der // Delphi-Hilfe steht Randomize; // In der Stringlist mit dem Template steht die Struktur des // Kakuro-Feldes drin. Anhand dieses Templates wird das // Spielfeld erstmal grundlegend eingerichtet. strlTemplate := TStringList.Create; strlTemplate.Clear; strlTemplate.Add('MMMSSSSMMSSS'); strlTemplate.Add('MMSNNNNSSNNN'); strlTemplate.Add('MSNNNNNNSNNN'); strlTemplate.Add('SNNSNNNSNNMM'); strlTemplate.Add('SNNSSNNSNNSS'); strlTemplate.Add('MSNNSNNSNNNN'); strlTemplate.Add('SNNNNNSNNNNN'); strlTemplate.Add('SNNNNSNNSNNS'); strlTemplate.Add('MMSNNSNNSSNN'); strlTemplate.Add('MSSNNNSNNSNN'); strlTemplate.Add('SNNNSNNNNNNM'); strlTemplate.Add('SNNNMSNNNNMM'); ReadingPlayingFieldTemplate(strlTemplate); FreeAndNil(strlTemplate); // Ich mag es nicht, eine graphische Ausgabe direkt auf den Canvas // des Formulars zu zeichnen. Lieber kapsel ich das Ganze in die Bitmap // eines unskalierten TImage. // Damit ich aber (ohne ein Bild explizit zu laden), mit der Bitmap // des TImage arbeiten kann, muß ich es erstmal einrichten, wobei das // wichtigste die Zuweisung von Breite und Höhe ist. // Die Zahlenwerte kommen daher: // Breite des Spielfeldes: 12 Felder // Höhe des SpielfeldeS: 12 Felder // Pixelgrösse eines einzelnen Feldes des Spielfelds: 32x32 Image.Picture.Bitmap.Width := 12 * 32; Image.Picture.Bitmap.Height := 12 * 32; // Gitterraster in das Spielfeld einzeichnen // Dabei wird die Anzeige des Spielfelds automatisch gelöscht DrawGrid; // Das geladene Template wird auf dem Spielfeld angezeigt, ohne daß dabei // die Ziffernwerte der Spielfelder berücksichtigt werden. for y := 0 to 11 do begin for x := 0 to 11 do begin if PlayingField[y][x].Name = 'M' then DrawBlock(x, y, clBlack) else if PlayingField[y][x].Name = 'S' then Image.Picture.Bitmap.Canvas.TextOut(x * 32 + 6, y * 32 + 6, 'S') else if PlayingField[y][x].Name = 'N' then DrawBlock(x, y, clSilver) else DrawBlock(x, y, clRed); end; end; end; {*----------------------------------------------------------------------------- Aktionsmethode des Buttons "Generate..." In dieser Methode wird das eigentliche Spielfeld generiert und ggf. angezeigt. Sehr einfach gehalten. @param Sender Handle auf das aufrufende Objekt -----------------------------------------------------------------------------*} procedure TMain.btGenerateClick(Sender: TObject); begin Screen.Cursor := crHourglass; btGenerate.Enabled := false; PlayingFieldGenerate; Screen.Cursor := crDefault; btGenerate.Enabled := true; end; {*----------------------------------------------------------------------------- Übertragen des Templates auf das Spielfeld Wie der Methodenname schon sagt. Allerdings wird das Spielfeld vorher noch sauber mit Leerwerten initialisiert. @param Sender Handle auf das aufrufende Objekt -----------------------------------------------------------------------------*} procedure TMain.ReadingPlayingFieldTemplate(const p_Field: TStringList); var x, y: Integer; begin // Leeren des Spielfelds for y := 0 to 11 do begin for x := 0 to 11 do begin PlayingField[y][x].Value := -1; PlayingField[y][x].Name := ''; end; end; // Übernehmen der Spielfeldnamen aus dem Template for y := 0 to p_Field.Count - 1 do begin for x := 0 to Length(p_Field.Strings[y]) - 1 do PlayingField[y][x].Name := MidStr(p_Field.Strings[y], x + 1, 1); end; end; {*----------------------------------------------------------------------------- Erzeugen des Spielfelds Für eine genauere Beschreibung kommentiere ich die Funktion direkt im Source. Hier nur eine Beschreibung des verwendeten Variablen: x, y: Die X- und Y-Koordinate des aktuell betrachteten Feldes nTempWert: Übernimmt zeitweilig die neue Zufallszahl, die in das Feld geschrieben werden soll. bEingetragen: Flag ob der neue Wert in das Feld eingetragen werden konnte. bUnsuccessful: Flag ob das Kakuro nicht mehr erstellt werden kann. nTryCounter: Zähler wie oft versucht wurde, einen neuen Wert in das aktuell betrachtete Feld zu schreiben. @param Sender Handle auf das aufrufende Objekt -----------------------------------------------------------------------------*} procedure TMain.PlayingFieldGenerate; var x, y: Integer; nTempWert: Integer; bEingetragen: boolean; bUnsuccessful: boolean; nTryCounter: Integer; begin // Generell wird davon ausgegangen, daß das Spielfeld erstellt // werden kann. bUnsuccessful := false; // Nochmal Leeren der Zahlenwerte der einzelnen Felder. // Ist dafür gut, daß durch erneutes Klicken auf "Generate..." // unterschiedliche Kakuros auf das gleiche Template gebastelt // werden können. for y := 0 to 11 do for x := 0 to 11 do PlayingField[y][x].Value := -1; // Zeile für Zeile... for y := 0 to 11 do // ...und pro Zeile Feld für Feld for x := 0 to 11 do if PlayingField[y][x].Name = 'N' then begin // Für jedes Feld wird neu versucht, einen Zufallswert // reinzuschreiben nTryCounter := 0; // Logisch, daß bislang noch kein neuer Zufallswert // reingeschrieben wurde. bEingetragen := false; // Solche Bedingungen mag ich. Die sind einfach zu lesen // und zu verstehen. // Solange noch kein neuer Wert eingetragen wurde und das // Kakuro noch nicht als unlösbar bewertet wurde, wird // versucht, einen neuen Wert reinzuschreiben. while (not bEingetragen) and (not bUnsuccessful) do begin nTempWert := Random(9) + 1; Inc(nTryCounter); // Wenn auch nach 100 Versuchen noch kein passender // neuer Wert gefunden wurde, dann wird das Kakuro // als nicht lösbar gewertet if nTryCounter > 100 then bUnsuccessful := true; // Auch die Bedingung sollte direkt verständlich sein: // Die beiden Funktionen prüfen, ob der gewählte neue // Zufallswert schon in der Zeile und/oder der Spalte // vorkommt. Wenn nein, dann wird er eingetragen. if ((not IsInRow(nTempWert, x, y)) and (not IsInColumn(nTempWert, x, y))) then begin PlayingField[y][x].Value := nTempwert; bEingetragen := true; end; end; end; // Falls das Kakuro gebaut werden konnte, wird es angezeigt... if not bUnsuccessful then PlayingFieldDraw // ...andernfalls wird das Spielfeld gelöscht und eine entsprechende // Hinweismeldung ausgegeben. else begin DrawGrid; ShowMessage('Generating unsuccessful.' + #13 + 'Ran into an unsolvable puzzle.'); end; end; {*----------------------------------------------------------------------------- Prüfen des neuen Zahlenwerts auf die Zeile Die Vorgehensweise ist sehr direkt: Es werden für die Zeile der Start- und der Endpunkt in Relation zum angewählten Feld bestimmt. Der Startpunkt ist das links vom angewählten Feld liegende Summenfeld + 1 und der Endpunkt entsprechend das rechts vom angewählten Feld liegende Feld, das keine Zahlen beinhaltet - 1. Es muß nur aufgepasst werden, daß die Spielfeldbegrenzungen korrekt erkannt werden. Sobald Anfang und Ende bekannt sind, wird einfach geschaut, ob der übergebene (neue) Zahlenwert schon vorkommt oder nicht. @param p_Value Der neue Zahlenwert, der überprüft werden soll @param p_X X-Koordinate des angewählten Feldes @param p_Y Y-Koordinate des angewählten Feldes @return Flag ob der Wert schon vorhanden ist -----------------------------------------------------------------------------*} function TMain.IsInRow(const p_Value: Integer; const p_x: Integer; const p_y: Integer): boolean; var RowStart: Integer; RowEnd: Integer; i: Integer; begin // Sicher ist sicher, daher die Initialisierung RowStart := 0; RowEnd := 0; // Ermitteln des Startpunkts if p_x > 0 then for i := p_x downto 0 do if PlayingField[p_y][i].Name <> 'N' then begin RowStart := i + 1; break; end; // Ermitteln des Endpunkts if p_x <= 11 then for i := p_x to 11 do if i = 11 then RowEnd := 11 else if PlayingField[p_y][i].Name <> 'N' then begin RowEnd := i - 1; break; end; // Sicherstellen, daß die Spielfeldgrenzen gewahrt bleiben if RowStart < 0 then RowStart := 0; if RowStart > 11 then RowStart := 11; if RowEnd < 0 then RowEnd := 0; if RowEnd > 11 then RowEnd := 11; // Rückgabewertermittlung, ob es den Wert des ausgewählten // Feldes in der Reihe schon gibt oder nicht. Result := false; for i := RowStart to RowEnd do if PlayingField[p_y][i].Value = p_Value then Result := true; end; {*----------------------------------------------------------------------------- Prüfen des neuen Zahlenwerts auf die Spalte Funktioniert genauso wie die Reihenprüfung, weswegen ich mir eine exzessive Dokumentation spare. @param p_Value Der neue Zahlenwert, der überprüft werden soll @param p_X X-Koordinate des angewählten Feldes @param p_Y Y-Koordinate des angewählten Feldes @return Flag ob der Wert schon vorhanden ist -----------------------------------------------------------------------------*} function TMain.IsInColumn(const p_Value: Integer; const p_x: Integer; const p_y: Integer): boolean; var ColStart: Integer; ColEnd: Integer; i: Integer; begin ColStart := 0; ColEnd := 0; if p_y > 0 then for i := p_y downto 0 do if PlayingField[i][p_x].Name <> 'N' then begin ColStart := i + 1; break; end; if p_y <= 11 then for i := p_y to 11 do if i = 11 then ColEnd := 11 else if PlayingField[i][p_x].Name <> 'N' then begin ColEnd := i - 1; break; end; if ColStart < 0 then ColStart := 0; if ColStart > 11 then ColStart := 11; if ColEnd < 0 then ColEnd := 0; if ColEnd > 11 then ColEnd := 11; Result := false; for i := ColStart to ColEnd do if PlayingField[i][p_x].Value = p_Value then Result := true; end; {*----------------------------------------------------------------------------- Zeichnen des Spielfeldes Macht fast das gleiche wie das Zeichnen des Templates, nur daß diesmal die Zahlenwerte der Felder mit angegeben werden und die Summenfelder auch passend beschriftet werden. -----------------------------------------------------------------------------*} procedure TMain.PlayingFieldDraw; var x, y: Integer; Text: String; pCanvas: TCanvas; begin pCanvas := Image.Picture.Bitmap.Canvas; // Gitterraster einzeichnen (und damit das Spielfeld löschen) DrawGrid; // Und wieder: Zeile für Zeile... for y := 0 to 11 do // ...und pro Zeile Feld für Feld for x := 0 to 11 do // Blockfelder werden einfach als schwarze Kästchen dargestellt if PlayingField[y][x].Name = 'M' then DrawBlock(x, y, clBlack) // Zahlenfelder bekommen einen grauen Hintergrund und danach // wird der Zahlenwert reingeschrieben else if PlayingField[y][x].Name = 'N' then begin DrawBlock(x, y, clSilver); Text := IntToStr(PlayingField[y][x].Value); pCanvas.Brush.Style := bsClear; pCanvas.TextOut(x * 32 + 8, y * 32 + 6, Text); pCanvas.Brush.Style := bsSolid; end // Es stimmt irgendwas nicht mit dem Feld, also wird es // rot gefärbt. else if PlayingField[y][x].Name <> 'S' then DrawBlock(x, y, clRed); // Jetzt kommen noch die Summenfelder dran pCanvas.Font.Size := 8; // Der Durchlauf ist ja bekannt for y := 0 to 11 do begin for x := 0 to 11 do begin if PlayingField[y][x].Name = 'S' then begin // Falls eine Horizontalsumme vorhanden ist: Anzeigen if HorizontalSum(x, y) > 0 then pCanvas.TextOut(x * 32 + 18, y * 32 + 2, IntToStr(HorizontalSum(x, y))); // Falls eine Vertikalsumme vorhanden ist: Anzeigen if VerticalSum(x, y) > 0 then pCanvas.TextOut(x * 32 + 2, y * 32 + 18, IntToStr(VerticalSum(x, y))); // Zeichnen der schwarzen Schräglinie bei Summenfeldern pCanvas.Pen.Color := clBlack; pCanvas.MoveTo(x * 32, y * 32); pCanvas.LineTo(x * 32 + 32, y * 32 + 32); pCanvas.Pen.Color := clWhite; end; end; end; // Die gesamte Spielfläche neu zeichnen Image.Invalidate; end; {*----------------------------------------------------------------------------- Bestimmen der horizontalen Summe eines Summenfeldes @param p_X X-Spielfeldkoordinate des Summenfeldes @param p_Y Y-Spielfeldkoordinate des Summenfeldes @return Horizontalsumme -----------------------------------------------------------------------------*} function TMain.HorizontalSum(const p_x: Integer; const p_y: Integer): Integer; var i: Integer; begin Result := 0; for i := p_x + 1 to 11 do begin if PlayingField[p_y][i].Name = 'N' then Result := Result + PlayingField[p_y][i].Value else break; end; end; {*----------------------------------------------------------------------------- Bestimmen der vertikalen Summe eines Summenfeldes @param p_X X-Spielfeldkoordinate des Summenfeldes @param p_Y Y-Spielfeldkoordinate des Summenfeldes @return Vertikalsumme -----------------------------------------------------------------------------*} function TMain.VerticalSum(const p_x: Integer; const p_y: Integer): Integer; var i: Integer; begin Result := 0; for i := p_y + 1 to 11 do begin if PlayingField[i][p_x].Name = 'N' then Result := Result + PlayingField[i][p_x].Value else break; end; end; {*----------------------------------------------------------------------------- Zeichnen eines Blocks in einem Feld des Spielfelds Der wesentliche Punkt ist nur, daß dabei die alten Zeichenfarben beibehalten werden. @param p_X X-Spielfeldkoordinate des angewählten Feldes @param p_Y Y-Spielfeldkoordinate des angewählten Feldes @param p_Color Farbe des zu zeichnenden Blocks -----------------------------------------------------------------------------*} procedure TMain.DrawBlock( const p_X: Integer; const p_Y: Integer; const p_Color: TColor); var OldPenColor: TColor; OldBrushColor: TColor; pCanvas: TCanvas; begin pCanvas := Image.Picture.Bitmap.Canvas; OldPenColor := pCanvas.Pen.Color; OldBrushColor := pCanvas.Brush.Color; pCanvas.Pen.Color := p_Color; pCanvas.Brush.Color := p_Color; pCanvas.Rectangle(p_x * 32 + 1, p_y * 32 + 1, p_x * 32 + 32, p_y * 32 + 32); pCanvas.Pen.Color := OldPenColor; pCanvas.Brush.Color := OldBrushColor; end; {*----------------------------------------------------------------------------- Zeichnen des Spielgitters Löscht gleichzeitig die Anzeige des Spielfelds -----------------------------------------------------------------------------*} procedure TMain.DrawGrid; var pCanvas: TCanvas; x, y: Integer; begin // Leeren des Spielfelds pCanvas := Image.Picture.Bitmap.Canvas; pCanvas.Pen.Color := clWhite; pCanvas.Pen.Style := psSolid; pCanvas.Brush.Color := clWhite; pCanvas.Brush.Style := bsSolid; pCanvas.Font.Name := 'Arial'; pCanvas.Font.Size := 16; pCanvas.Rectangle(0, 0, Image.Picture.Bitmap.Width, Image.Picture.Bitmap.Height); // Vorbereiten auf das Zeichnen der Gitterlinien pCanvas.Pen.Color := clBlack; pCanvas.Brush.Color := clBlack; // Zeichnen der horizontalen Linien for y := 0 to 11 do begin pCanvas.MoveTo(0, y * 32); pCanvas.LineTo(Image.Picture.Bitmap.Width, y * 32); end; // Zeichnen der vertikalen Linien for x := 0 to 11 do begin pCanvas.MoveTo(x * 32, 0); pCanvas.LineTo(x * 32, Image.Picture.Bitmap.Height); end; // Rücksetzen der Farben, sonst kommen andere Outputmethoden in // Schwierigkeiten pCanvas.Pen.Color := clWhite; pCanvas.Brush.Color := clWhite; end; end.
Damit kannst du mal vergleichen und schauen, wo dann bei dir den Haken war.
-
Vielen Dank für die Mühe.
Eigentlich habe ich mir das so vorgestellt:
Man Setzt im ersten Sumen Block eine Zufallszahl und dann geht man ein Feld weiter, danach wird wieder eine Zufallszahl eingesetzt und prüft die Zahl nach links in der gleichen Reihe, wenn es die gleiche Zahl entspricht, wird sie um 1 erhöt und das gleiche Spiel wieder von vorne, bis die Zahl in der reihe nicht existiert.
So müsste man keine 100 versuche durch eine Zufallszahl testen.
So habe ich das ja gemacht, was auch nicht 100% funktionierte.
Ich arbeite ja mit mehreren Programmiersprache und habe diese Funktion in BlitzMax testweise mal umgeschrieben und getestet, läuft fehlerfrei, wirklich seltsam.
Edit: Hier ist mal ein Screen von mir:
http://www.qpic.ws/viewimage.php?fil...s/LeZ77736.png
Wie man auf dem Screen erkennen kann, fehlt unten rechts eine Zahl.
Es passiert nur manchmal, das wenn ich die Zahlen neu generiere, das eine Zahl dann fehlt.
Das ist nur bei den großen Spielfeldern so, die kleinere Spielfeldern funktionieren Top.
Naja, ich werde mir mal in Ruhe deinen Code ankucken und vielen Dank für die Hilfe.
MfGGeändert von jackie05 (27.01.09 um 18:39 Uhr)
-
27.01.09 20:26 #13
- Registriert seit
- Mar 2004
- Beiträge
- 441
Genau der von dir gepostete Screenshot zeigt das Problem:
Welche Ziffer würdest du denn in das Feld eintragen, um zu einer eindeutigen Lösung zu kommen? Denn die Ziffern von 1-9 sind schon waagrecht und senkrecht vergeben.
Bei meinem Programm werden sämtliche Ziffern genauso komplett zufällig verteilt wie in deinem. Der Unterschied bei mir ist, daß ich mir gedacht habe, daß dieses Programm keine zeitkritische Anwendung ist und ich ohne weiteres ein paar hundert bis tausend Zyklen verbraten kann.
Natürlich lässt sich das Ganze noch optimieren mit Abgleichsarrays senkrecht und waagrecht von 1-9. Aber das zu implementieren war mir zu viel Aufwand für ein schnell runtergetipptes Programm. Da lasse ich den Zufallszahlengenerator eher einfach 100 Ehrenrunden drehen, bevor ich sage: "Jetzt langt's".
Das Kernproblem ist doch das Generieren von "unmöglichen" Puzzeln. Ob die Zufallszahlen jetzt mit einem Inkrementierungsalgorithmus (wie bei dir) oder mit schon fast "brute force" (wie bei mir) im Feld landen, spielt da ja keine Musik. Aber die Generierungsmethode muß mitbekommen, wenn sie entweder gegen die Wand läuft (bei mir die 100er-Schwelle) oder wenn ein fehlerhaftes Rätsel gebildet wird (z.B. bei deinem Leerfeld).Geändert von CSANecromancer (27.01.09 um 20:29 Uhr)
-
Achso, das ist mir noch garnicht aufgefallen, da kann ja keine Zahl mehr hinein passen.
Also, dann ist ja mein Code in Ordnung, weil es ansonsten funktioniert und die Schleifen arbeiten auch sehr schnell.
Jetzt muss ich nur noch überprüfen, wenn keine Zahl (1-9) passt, das er versucht in dieser Reihe eine andere passende Zahl zu setzen.
Ich bin dir sehr dankbar, ich hätte den fehler irgendwie nie bemerkt, da ich nicht so besonders drauf geachtet habe.
Nochmals, vielen Dank.
MfG
-
28.01.09 07:59 #15
- Registriert seit
- Mar 2004
- Beiträge
- 441
Da habe ich auch etwas suchen müssen.
Jup, entweder das oder du verwirfst das alte Ergebnis und startest die Generierung neu. So oft hatte ich es nicht, daß ein unlösbares Rätsel rauskam. Ca. 12mal bei 100 Versuchen.
Keine Ursache, über Bewertungen freue ich mich immer.
Ähnliche Themen
-
Probleme mit Zufallszahlen...
Von proXXic im Forum JavaAntworten: 18Letzter Beitrag: 15.10.08, 14:27 -
Array aus Zufallszahlen erstellen ohne doppelte Werte
Von DAM im Forum Visual Basic 6.0Antworten: 3Letzter Beitrag: 02.09.08, 09:39 -
Array mit Zufallszahlen
Von avenger2099 im Forum C/C++Antworten: 3Letzter Beitrag: 17.08.07, 17:38 -
Probleme mit Array
Von einfachf im Forum Visual Basic 6.0Antworten: 2Letzter Beitrag: 16.08.07, 06:32 -
Problem beim speichern von Zufallszahlen in einem Array.
Von GreenThunder im Forum JavaAntworten: 10Letzter Beitrag: 06.12.05, 21:12



1Danke

Zitieren
Login





