Zahlenvergleich oder Sortieren?

dreamsahin

Grünschnabel
Hallo @Forum,
Habe vor 2 Monaten einen Mastermind Klon(Zahlen) mit Delphi angefangen..
fast und mit ein paar Bugs habe ich es geschafft..

Ablauf des Spiels ist..

Programm generiert 5 Zufallszahlen von 0-9 dieser vom Spieler erraten werden müssen...
Spieler gibt seine erratene Zahlen in 5 nebeneinander gesetzte EditFelder ein....
von Spieler eingegebene Zahlen werden in eine Liste (StringGrid1 mit 5 Cells) eingetragen und mit der von Programm generierte Zahlen verglichen..
und zur zweite Liste(StringGrid2 mit 2 Cells) übertragen und als ergebniss weiter gegeben als
R = (Richtige zahl im RICHTIGEN Position) und als F = (richtige Zahl aber in FALSCHEM position)..
bei der ergebniss ausgabe für F kriege ich meistens falsche ergebnisse sobald in Programm generierte 5 CodeFeldern gleiche Zahlen vorkommen.. werden die Zahlen auch mehrmals mitgezählt dadurch erhält man auch unterschiedliche ergebnisse..
Bsp...

Generierte Zahlen.
8 0 0 3 1
erraten vom Spieler
0 8 8 8 0

als ergebniss bekomme ich dann
R = 0 und F = 7

also die 8 wird 3 mal und die 0 wird 4 mal berechnet..
dies möchte ich verhindern..jedes Zahl dieser von Spieler eingegeben ist soll und darf nur eimal gezählt werden....

Das Quellcode des Spiels habe ich unten eingefügt....
würde mich auf eure Tips und hilfe sehr freuen....

bedanke mich schonmal im voraus...

1.Bug
Quellcodezeile 112 bis 119


Code:
unit Master;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    StringGrid1: TStringGrid;
    OK: TLabel;
    Neu: TButton;
    Abbrechen: TButton;
    Beenden: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    StringGrid2: TStringGrid;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    Counter: TEdit;
    Label10: TLabel;
    procedure OKClick(Sender: TObject);
    procedure OKMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure OKMouseLeave(Sender: TObject);
    procedure NeuClick(Sender: TObject);
    procedure BeendenClick(Sender: TObject);
    procedure AbbrechenClick(Sender: TObject);
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
    procedure Label10Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Masteranleitung;

{$R *.dfm}
var
count: Integer;

procedure TForm1.OKClick(Sender: TObject);
var
code: Array[1..5] of Integer;
geraten: Array[1..5] of Integer;
richtig,falsch: Integer;
i,j,k,c,f,g,h: Integer;
begin
  if Edit1.Text='' then ShowMessage('eingabe überprüfen')else
  if Edit2.Text='' then ShowMessage('eingabe überprüfen')else
  if Edit3.Text='' then ShowMessage('eingabe überprüfen')else
  if Edit4.Text='' then ShowMessage('eingabe überprüfen')else
  if Edit5.Text='' then ShowMessage('eingabe überprüfen')else
begin
  i:=StringGrid1.RowCount-1;
  with StringGrid1 do
  begin
  // Geratene Zahlen werden in die Liste eingefügt....
    StringGrid1.Cells[0,i]:=Edit1.Text;
    StringGrid1.Cells[1,i]:=Edit2.Text;
    StringGrid1.Cells[2,i]:=Edit3.Text;
    StringGrid1.Cells[3,i]:=Edit4.Text;
    StringGrid1.Cells[4,i]:=Edit5.Text;
    StringGrid1.RowCount:=StringGrid1.RowCount+1;

      end;
  begin
    code[1]:=StrToInt(Label1.Caption);
    code[2]:=StrToInt(Label2.Caption);
    code[3]:=StrToInt(Label3.Caption);
    code[4]:=StrToInt(Label4.Caption);
    code[5]:=StrToInt(Label5.Caption);
    geraten[1]:=StrToInt(Edit1.Text);
    geraten[2]:=StrToInt(Edit2.Text);
    geraten[3]:=StrToInt(Edit3.Text);
    geraten[4]:=StrToInt(Edit4.Text);
    geraten[5]:=StrToInt(Edit5.Text);
    Edit1.Clear;
    Edit2.Clear;
    Edit3.Clear;
    Edit4.Clear;
    Edit5.Clear;
    Count:=Count+1;
    Counter.Text:=IntToStr(count);

  begin
  // richtige zahlen werden sortiert....
    richtig:=0;
    for g:=1 to 5 do
    if geraten[g]=code[g] then inc(richtig);
    Label8.Caption:=IntToStr(richtig);
  end;

   begin
   // falsche zahlen werden sortiert....
     falsch:=0;
     for f:=1 to 5 do
     for c:=1 to f do
     if geraten[ c]<>code[ c] then
     if geraten[ c]=code[f] then inc(Falsch);
     Label9.Caption:=IntToStr(falsch);

 begin
   // Ergebniss Liste für richtige und falsche Zahlen...
    k:=StringGrid2.RowCount-1;
    j:=StringGrid2.RowCount-1;
    with StringGrid2 do
    begin
      StringGrid2.Cells[0,j]:=Label8.Caption;
      StringGrid2.Cells[1,k]:=Label9.Caption;
      StringGrid2.RowCount:=StringGrid2.RowCount+1;
      end;
      begin
        if richtig=5 then ShowMessage('Sie haben es Geschafft');
         if richtig=5 then Neu.Enabled:=True;
         if richtig=5 then Abbrechen.Enabled:=False;
         if Count=12 then
          begin
            Counter.Color:=clRed;
            if Application.MessageBox('Spiel Verloren','VERLOREN')=5
            then
            Label1.Visible:=True;
            Label1.Visible:=True;
            Label2.Visible:=True;
            Label3.Visible:=True;
            Label4.Visible:=True;
            Label5.Visible:=True;
            Abbrechen.Enabled:=False;
            Neu.Caption:='VERLOREN';
            Neu.Enabled:=True;
            OK.Enabled:=False;
           end;
         end;
        end;
     end;
    end;
   end;
   end;
procedure TForm1.OKMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  OK.Font.Color:=clGreen;
end;

procedure TForm1.OKMouseLeave(Sender: TObject);
begin
  OK.Font.Color:=clBlack;
end;

procedure TForm1.NeuClick(Sender: TObject);
var
Num1, Num2, Num3, Num4, Num5: Byte;
begin
// Zufallszahlen werden generiert....
   Randomize;
   Num1:=random(10); Num2:=random(10); Num3:=random(10);
   Num4:=random(10); Num5:=random(10);
   Count:=0;
   Label1.Caption:=IntToStr(Num1);
   Label2.Caption:=InttoStr(Num2);
   Label3.Caption:=IntToStr(Num3);
   Label4.Caption:=IntToStr(Num4);
   Label5.Caption:=IntToStr(Num5);
   Abbrechen.Enabled:=True;
   Neu.Caption:='Neu';
   Counter.Color:=clWhite;
   Counter.Clear;
   Ok.Enabled:=True;
   Neu.Enabled:=False;
   //Liste1 leeren
   StringGrid1.RowCount:=StringGrid1.RowCount-12;
   StringGrid1.Rows[0].Clear;
   //Liste2 leeren
   StringGrid2.RowCount:=StringGrid2.RowCount-12;
   StringGrid2.Rows[0].Clear;
   
end;

procedure TForm1.BeendenClick(Sender: TObject);
begin
// Frage ob Beenden? wenn Bestätigt dann Beenden
 if Application.MessageBox('Sind Sie sicher','BEENDEN',36)=6
 then
  close;
end;

procedure TForm1.AbbrechenClick(Sender: TObject);
begin
// Frage ob Abbrechen wenn Bestätigt dann Abbrechen und Zufallszahlen zeigen...
 if Application.MessageBox('wollen Sie Aufgeben','AUFGEBEN',36)=6 then
 Label1.Visible:=True;
 Label2.Visible:=True;
 Label3.Visible:=True;
 Label4.Visible:=True;
 Label5.Visible:=True;
 Abbrechen.Enabled:=False;
 Neu.Enabled:=True;
end;

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in ['0'..'9',#8]) then Key:=#0;
end;


procedure TForm1.Label10Click(Sender: TObject);
begin
 Masteranleitung.Form2.Show;
end;

end.
 

CSANecromancer

Erfahrenes Mitglied
Hallo @Forum,

bei der ergebniss ausgabe für F kriege ich meistens falsche ergebnisse sobald in Programm generierte 5 CodeFeldern gleiche Zahlen vorkommen.. werden die Zahlen auch mehrmals mitgezählt dadurch erhält man auch unterschiedliche ergebnisse..
Bsp...

Generierte Zahlen.
8 0 0 3 1
erraten vom Spieler
0 8 8 8 0

als ergebniss bekomme ich dann
R = 0 und F = 7

also die 8 wird 3 mal und die 0 wird 4 mal berechnet..
dies möchte ich verhindern..
Nenn mich von mir aus einen Kluger, aber genau dieser geschilderte Fall ist für mich das, was den Software-Entwickler vom Programmierer unterscheidet. Ich würde dir einfach empfehlen, dir einmal die Logik deines Spielchens nochmal in Ruhe zu überlegen. Was soll wann und wie geschehen? Was soll passieren, wenn der Spieler seine 5 Zahlen eingegeben hat? Ein einfaches "ja, dann soll halt der Computer vergleichen, ob irgendwelche Zahlen passen" reicht da absolut nicht aus. Formuliere das Ganze so präzise und exakt, daß es selbst ein Kleinkind verstehen könnte. Denn der Computer ist auf einem noch niedrigeren geistigen Niveau.
Wenn du die Logik des Programms sauber ausformuliert hat, dann denke ich, daß es an der Zeit ist, das Tei zu programmieren.

Ich kenne noch das Master Mind-Spiel, aber wenn ich mich recht entsinne, dann konnte eine Spielereingabe nicht nur 2 sondern 3 verschiedene Zustände annehmen:
1. Richtige Zahl, richtige Position
2. Richtige Zahl, falsche Position
3. nicht vorkommende Zahl
So gesehen wäre hier schon mal ein grundlegender Designfehler in deinem Programm.

Ist aber nur meine bescheidene Meinung dazu.
 

Online-Skater

Erfahrenes Mitglied
Du hast absolut Recht, ich habe dieses Spiel auch in Delphi gemacht mit Farben und das geht nicht mal so eben, der Algorythmus ist entscheidend und wie der Vorredner gesagt hat, den musst du dir nochmal neu überlegen, einfaches vergleichen reicht dort nicht mehr aus mit den 3 Fällen ;)

Tipp. Ich habe es mit einem boolschen array gelöst
 

dreamsahin

Grünschnabel
möchte erstmal für eure Antworten bedanken.

@Online-Skater

Da ist auch mein problem
wie könnte ich es mit der boolschen array lösen
könntest du mir da etwas weiter helfen?
 

CSANecromancer

Erfahrenes Mitglied
Tipp. Ich habe es mit einem boolschen array gelöst
Hmmm... du fragst drei Stati mit einem boolschen Array ab?
Stelle ich mir so auf Anhieb lustig vor. Ein einfaches
Code:
if array[i] = true
oder
Code:
if array[i] = false
wird da wohl nicht reichen.
Würde mich auch interessieren, wie du das gelöst hast. Auf Anhieb schwirrt etwas in der Richtung von
Code:
if array[i] = IsTrue then...
if array[i] = IsFalse then...
if array[i] = IsSomethingBetweenTrueAndFalseNotReallyBooleanButNeccessary then...
im Kopf herum. :)

Ich persönlich würde wohl zu einem Array mit ShortInts greifen. :)
 

Van-Fanel

Grünschnabel
Da fällt mir spontan eine Facharbeit zu ein:

Sie hatte den Titel: Erweiterung der Boolean-Variable um "Maybe" & "both".
Hier könnte man das vielleicht gebrauchen :p


Aber Scherz beiseite:
Versuch das ganze doch mal Objektorientiert zu lösen. Dazu gibt es bei Delphi eine ganze Reihe von Tutorials.
Ich würde dann für jeden Knopf bzw. jedes Feld ein einzelnes Objekt erstellen, die dann miteinander Interagieren sollen.


MFG
Van
 

Hellie

Erfahrenes Mitglied
Hui, jetzt wird's fuzzy :eek:

Ich wollte mal nachfragen, wie die Anzeigen beim normalen Spiel sind? Zählt jede Zahl am falschen Ort ein Mal oder wie? Und woraus ergibt sich dann die Anzahl der gar nicht vorkommenden Zahlen?

Ich kenn das Prinzip nicht, würde aber am ehesten versuchen, die Zahlenreihen während des Vergleichs zu manipulieren und mit einem Set arbeiten. Nicht sauber, aber eindeutig, finde ich. Oder spricht da was dagegen?

Würde mich interessieren?
Liebe Grüße
Hellie

PS: Bitte nicht schlagen, wenn das gar nicht geht, hab heut Mathe-Abi geschrieben :-(
 

dreamsahin

Grünschnabel
thx @all,
für eure Tipps

kann ich es mit einer function probieren? :confused:
vom Spieler erratene identische Zahlen sollen durch function
auf gleichheit geprüft werden.

wenn gleiche zahl dann result=false ? :confused:

wäre es möglich?
 

Online-Skater

Erfahrenes Mitglied
Aslo als ich das Spiel Mastermind programmiert habe ist schon ne Weile her, von daher gibt es bestimmt bessere Lösungen :)
Ich habe das mit einer richtigen Oberfläche mit Farbshapes gemacht also nicht wundern, ich versuche die Kommentare möglichst eindeutig zu machen. Anzumerken ist das es es nur ein Ausschnitt der Funktion ist da es ja nur um den Algorithmus geht.
Code:
procedure Check(var counter : integer);  // counter = Anzahl des Versuches
var h,i,j,RS,RF : integer;   //i,j = Zähler | RS(Stelle),RF(Farbe) = punkte
    geheim,rate : array[1..4] of Boolean;
    Shape,Richt : array[1..4] of TShape;
begin
RS := 0;  RF := 0;            // Anfangspunkte auf null setzen
 for i := 1 to 4 do
 begin
   geheim[i] := false;
   rate[i] := false;
   Shape[i].Enabled := false;   // aktuelle Reihe ausschalten
 end;

 for i := 1 to 4 do      // richtige Stellen
 begin
   if Form1.Sgeheim[i].Brush.Color = Shape[i].Brush.Color then
     begin
       geheim[i] := true;
       rate[i] := true;
       RS := RS + 1;
     end;
 end;

   for i := 1 to 4 do   // richtige Farbe, doppelte schleife
   begin
     for j := 1 to 4 do
     begin
     // Folgesndes dient damit der Wert nicht doppelt gezählt wird
       if (Form1.Sgeheim[i].Brush.Color = Shape[j].Brush.Color) and (i <> j) and (geheim[i] = false) and (rate[j] = false) then
       begin
         geheim[i] := true;
         rate[j] := true;
         RF := RF + 1;
       end;
     end;
   end;

 if (RS > 0) or (RF > 0) then            // Ausgabe der Punkte
      begin
        // Auswertung
      end;
end;
Ich hoffe ich kann damit ein wenig helfen. Das schwierige war die richtige farbe am falschen ort so zu finden das es nur einmal gezählt wird ;-)

mfg