Autor Beitrag
Goaznic
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23

Win XP, Win 7
Delphi 5, Delphi 10
BeitragVerfasst: Mi 14.09.11 11:35 
Hey.

Ich bin derzeit damit beschäftigt, einen "Crossword-Generator" zu entwickeln.
Ich habe also ein Memo, in dem Begriffe stehen. Diese Begriffe werden per Klick auf einen Button in ein StringGrid gepackt (Je Zelle ein Buchstabe, also wie bei einem Crossword --> ist ja auch logisch. :D). Position und Richtung der Ausgabe in dem Grid werden zufällig bestimmt. Und dann werden natürlich die restlichen Felder noch zufällig befüllt.
Das funktioniert ja auch schonmal alles, war ja auch recht einfach.
Aber nun habe ich noch einen weiteren Button, ich nenne ihn einfach mal "Lösung". Denn wenn man auf diesen Button klickt, soll die Lösung des Crossword angezeigt werden, und zwar so, dass alle "richtigen" Zellen (die mit den "richtigen" Buchstaben) farblich markiert/befüllt werden.

Btw.: Diese Übung soll für mich der Einstieg in OOP sein.

Also: Mein Objekt ist ja 'ne Zelle - oder auch mehrere Zellen, wenn man's genau nimmt.
Nun dachte ich mir, ich kann ja erstmal beim FormCreate jeder Zelle sowas wie einen Index zuweisen, der zu diesem Zeitpunkt 0 ist.
Und dann, wenn man das Grid mit den Begriffen füllt, sollte den entsprechenden Zellen der Index 1 zugewiesen werden. Dann haben ja alle "richtigen" Zellen den Index 1 und alle "falschen" den Index 0.
Und dann beim Klick auf "Lösung" kann das Programm ja mittels einer Schleife das Grid durchgehen und immer dann, wenn der Index = 1 ist, diese Zelle färben.
Ja. Die Idee an sich soll ja schonmal soweit richtig sein. Aber bei mir hängts noch etwas an der Umsetzung.

Ich habe erstmal eine neue Klasse deklariert:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
  TCellData = class
    color: TColor;
    index: Integer;
  end;


Beim FormCreate muss diese dann ja erstmal aufgerufen werden, weil ja jeder Zelle der Index 0 zugewiesen werden soll:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure TfrmMain.FormCreate(Sender: TObject);
var
  I: Integer;
  e: Integer;
  grdRect: TGridRect;
begin
// jetzt folgt erstmal der Teil, wo diese blaue Zelle entfernt wird ...
  with grdRect do begin
    Top := -1;
    Left := -1;
    Right := -1;
    Bottom := -1;
  end;
  grdGrid.Selection := grdRect;

// und hier geht's los mit der Index-Zuweisung
  for I := 0 to grdGrid.RowCount do
    for e := 0 to grdGrid.ColCount do
    begin
      grdGrid.Objects[I, e] := TCellData.Create;
      TCellData(grdGrid.Objects[I, e]).index := 0;
    end;
end;


Dann muss ich beim Eintrag der Buchstaben auch immer gleich den Index auf 1 setzen (hier im Beispiel genügt wohl die Richtung Rechts):

ausblenden volle Höhe Delphi-Quelltext
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:
procedure TfrmMain.right(var sTerm: string);
var
  I, k: Integer;
begin
// erstmal wird die Startzelle festgelegt und so ...
  bStop_process := false;
  repeat
    Application.ProcessMessages;
    begin
      iCol_StartingValue := random(grdGrid.ColCount - length(sTerm));
      iRow_StartingValue := random(grdGrid.RowCount);
      iCol := iCol_StartingValue;
      bMatch := True;
      bOutput := false;
// dann kommt die Überpfüfung, ob der Begriff überhaupt da hin passt
      for k := 0 to length(sTerm) - 1 do
        if (grdGrid.Cells[iCol + k, iRow_StartingValue] <> ''and
          (grdGrid.Cells[iCol + k, iRow_StartingValue] <> sTerm[k + 1]) then
          bMatch := false;
// und wenn das der Fall ist, wird der Reihe nach jeder Buchstabe hinzugefügt
      for I := 1 to length(sTerm) do
      begin
        if bMatch = True then
        begin
          grdGrid.Cells[iCol, iRow_StartingValue] := sTerm[I];
          bOutput := True;
          iCol := iCol + 1// Inc(iCol)
// und hier hab ich versucht, den Index auf 1 zu erhöhen, keine Ahnung, warum ich die Form nochmal kreieren musste, aber ohne das kam immer eine Fehlermeldung, wenn ich die Begriffe ausgeben wollte
          grdGrid.Objects[iCol + (I - 1),
            iRow_StartingValue] := TCellData.Create;
          TCellData(grdGrid.Objects[iCol + (I - 1), iRow_StartingValue])
            .index := 1;
          end;
      end;
// jetzt folgt nur noch Kleinkram, der hierfür irrelevant ist
      Screen.Cursor := crHourglass;
    end;
  until (bOutput = True) or (bStop_process = True);
  Screen.Cursor := crDefault;
end;


So. Nachdem der Index 1 sein sollte (sofern das bei mir richtig ist ...) muss ja das Ereignis btnLösungMouseDown folgen:

Ja... Da brauch ich gar keinen Quelltext kopieren jetzt, da steht eh nur wirres Zeug. Jedenfalls muss ich a ja irgendwie eine Verbindung mit grdGridDrawCell aufbauen und das klappt nicht so ganz.
Ich kopier auch mal schnell mein DrawCell hier rein:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TfrmMain.grdGridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  if Assigned(grdGrid.Objects[ACol, ARow]) then
    exit;
  if gdFocused in State then
  begin
    grdGrid.Canvas.Brush.color := clRed;
    grdGrid.Canvas.FillRect(Rect);
  end;
end;


Ich glaub in dem Teil ist auch alles falsch ... irgendwie komm ich damit nicht weiter.
Kann mir da jemand weiterhelfen? Wenn's denn so jetzt überhaupt verständlich war. :'D
Falls jmd den ganzen Q-Text benötigt, kann ich den auch nochmal hier posten.
Horschdware
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 744
Erhaltene Danke: 54

Win XP Pro, Win 7 Pro x64
Delphi 7, Delphi XE, C++ Builder 5, SAP R/3
BeitragVerfasst: Mi 14.09.11 12:27 
Das mit deinem Index habe ich jetzt nicht ganz verstanden. Ich gehe mal davon aus, dass das, was da drin steht in Ordnung ist. Dann könnte deine Zeichenroutine so ausschauen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var s : string;
    sg : TStringGrid;
begin
  sg := TStringGrid(sender);
  s :=  sg.Cells[Acol,Arow];

  if not loesung_zeigen then exit;
//  if ((s = '') or (s=' ')) then exit; // optional?


  // Annahme: Index 1 = OK; Index 0 = nicht ok
  if TCellData(sg.Objects[acol,arow]).index = 1 then
   sg.Canvas.Brush.color := clLime
  else
    sg.Canvas.Brush.color := clRed;

  sg.Canvas.FillRect(rect);
  // Übermalten Text wieder zeichnen
  DrawText(sg.Canvas.Handle, PChar(s), Length(s), Rect, DT_LEFT)   ;
end;

Dabei wird der Schalter "loesung_zeigen" durch deinen Button gesetzt. Ist der nicht drin, wird auch keine Lösung gezeigt.

Ich persönlich hätte das aber ein wenig anders gemacht, indem ich TCellData einfach hätte den korrekten Wert beinhalten lassen.
ausblenden Delphi-Quelltext
1:
2:
3:
TCellData = class 
  correct_value : string;
end;

Dann könntest du beim Aufbau des Rätsels einfach prüfen, ob die Zelle schon belegt ist (Object[x,y] <> nil) und musst in der Zeichenroutine nur noch prüfen, ob das was gerade in der Zelle steht gleich dem ist, was in der Zelle stehen soll.

ausblenden Delphi-Quelltext
1:
if s = TCellData(sg.Objects[acol,arow]).correct_value then					



Btw: Mir fällt gerade auf, das mir nicht ganz klar wurde, wie du festhältst, welche Begriffe es zu erraten gibt in Abgrenzung zu dem, was der Benutzer eingegeben hat. (habe ich das nur übersehen?)

_________________
Delphi: XE - OS: Windows 7 Professional x64

Für diesen Beitrag haben gedankt: Goaznic
Goaznic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23

Win XP, Win 7
Delphi 5, Delphi 10
BeitragVerfasst: Mi 14.09.11 12:41 
Also die zu erratenden Begriffe werden ja (das hab ich etwas umständlich gemacht, aber geht ja auch. :D) vom Benutzer über ein Edit-Feld eingegeben. Dann werden die in ein Memo übertragen und wenn der Benutzer fertig ist, klickt er auf einen Button. Und damit werden dann der Reihe nach alle Begriffe aus dem Memo eingefügt in das Grid. Hmm, joa ... Anders halt ich das irgendwie nicht fest. Deshalb muss ich das ja so machen, dass den "richtigen" Zellen der "Index" 1 zugewiesen wird. :D
Aber anders lässt sich das doch auch nicht umsetzen, oder? Wobei das auch eher nebensächlich wäre. Hab das ja schon so weit alles jetzt, dann versuch ich das auch so fortzuführen.
Ich versuch gleich mal das, was du da geschrieben hast, anzuwenden. Aber erstmal mach ich jetzt Mittagspause! :D :D :D
Horschdware
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 744
Erhaltene Danke: 54

Win XP Pro, Win 7 Pro x64
Delphi 7, Delphi XE, C++ Builder 5, SAP R/3
BeitragVerfasst: Mi 14.09.11 13:02 
Tut mir echt leid, aber ich stehe da wohl auf dem Schlauch...

Der Spieler startet das Spiel und die zu findenden Begriffe werden in das Grid eingetragen. Aber dann sieht der Spieler doch schon, welche Begriffe es gibt... ??

Zudem funktioniert doch ein Kreuzworträtsel eher so, dass man in die einzelnen Zellen des Rätsels etwas hineinschreibt und nicht so, dass man ganze Wörter errät, die dann in ein Feld ausserhalb des Rätsels eingetragen werden.

Also entweder verstehe ich dich total falsch oder ich sollte mich mal richtig ausschlafen :lol:

_________________
Delphi: XE - OS: Windows 7 Professional x64
Goaznic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23

Win XP, Win 7
Delphi 5, Delphi 10
BeitragVerfasst: Mi 14.09.11 13:54 
Jaa, also das ist ja noch Version 1.0! :D
Ich werd das noch so ausarbeiten, dass man am Ende fertige Crosswords laden kann und so.
Aber zunächst soll es einfach erstmal nur so gehen. Weil man das in der Testphase dann besser nachvollziehen kann.
Und das ist schon so wie ein richtiges Crossword, also pro Zelle ein Buchstabe. Also zur Verdeutlichung:

Du hast eine Liste mit Begriffen.

Und daneben hast du ein Gitter mit ganz vielen Buchstaben.
Und in diesem Gitter sollst du die Begriffe aus der Liste dann finden.

So ist das ganze aufgebaut. Die Liste hab ich, weil das individuell sein soll. Der Benutzer soll halt die Wörter verwenden können, die er gern hätte.

Btw.: Ich merk grad, wenn ich das irgendwann so ausarbeite, dass man ein komplettes Rätsel laden kann, dann muss ich ja auch noch einen Such-Algorithmus schreiben.
Also wahrscheinlich werde ich das doch nicht ändern. :D
Naja, wie gesagt, es ist nur eine Übung. Ich sollte anfangs ein bisschen was über das StringGrid lernen und jetzt kam dann halt noch die Geschichte mit Zellfärbung und so dazu.
Sofern ich meinen Ausbilder richtig verstanden habe, ist das auch vorerst meine letzte Übung zu dem Grid.
Das Problem wird einfach sein, dass es zunächst ein Crossword-Generator war und jetzt auf einmal dann eher ein Crossword selbst ist. Lässt sich schwer kombinieren. :D

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Funktioniert aber leider doch nicht so, wie ich's mir erhofft hatte.

Ich hatte vorher mal 'ne Übung, wo das mit 'gdSelected in State' gemacht wurde und so.
Hach naja, ich frag einfach mal meinen Ausbilder.
Aber nochmal vielen Dank für die Hilfe. :)
Goaznic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23

Win XP, Win 7
Delphi 5, Delphi 10
BeitragVerfasst: Do 15.09.11 12:02 
Hey, ich hab's fast geschafft! Und ich konnte einiges von dem, was du gepostet hattest (bei dem DrawCell ...) doch noch verwenden! :)
Allerdings fehlt mir nun noch der Teil, wo ich den Text wieder sichbar mache. Also das was du da wie folgt geschrieben hast:

ausblenden Delphi-Quelltext
1:
DrawText(sg.Canvas.Handle, PChar(s), Length(s), Rect, DT_LEFT);					


Kannst du mir das ein wenig erläutern?

- - - - - - - - - - - - - - - - - - - - - - -

Derzeit sieht's bei mir so aus:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure TfrmMain.grdGridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  if not loesung_zeigen then
    Exit;
  if TCellData(grdGrid.Objects[ACol, ARow]).correct_value = True then
    grdGrid.Canvas.Brush.color := clLime
  else
    grdGrid.Canvas.Brush.color := clRed;
  grdGrid.Canvas.FillRect(Rect);
  DrawText(grdGrid.Canvas.Handle, pChar(), Length(), Rect, DT_LEFT)
end;


procedure TfrmMain.btnSolutionMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then
  begin
    loesung_zeigen := True;
    grdGrid.Invalidate;
  end;
end;


---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Hat sich schon erledigt. Danke. =D
Also, dann wär's das hierzu erstmal.
Nochmal vielen vielen Dank! :)