Autor Beitrag
n1con
Hält's aus hier
Beiträge: 12
Erhaltene Danke: 1

Win7 Ultimate x64
Delphi 6, Delphi 2007
BeitragVerfasst: Do 08.09.11 03:55 
Hallo,

ich habe vor einiger Zeit ein neues Projekt begonnen. Und zwar Vier Gewinnt.

Ich benutze dafür eine StringGrid als Spielfeld. Soweit kann das Programm sagen, welcher Spieler am Zug ist. Außerdem fällt jeder Stein an die richtige Position. Nun habe ich ein Problem damit festzustellen ob ein Spieler gewonnen hat.
Hier ist mein Quellcode den ich bisher habe:

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:
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:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    StatusBar1: TStatusBar;
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    MainMenu1: TMainMenu;
    Neu1: TMenuItem;
    NeuesSpiel1: TMenuItem;
    Ende1: TMenuItem;
    Hilfe1: TMenuItem;
    About1: TMenuItem;
    MeinBlog1: TMenuItem;
    Label1: TLabel;
    procedure StringGrid1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;
  procedure naechsterspieler;
var
  Form1: TForm1;
  amzug : integer;
  Name1, Name2 : string;
  gestartet : boolean;

implementation




{$R *.dfm}

function CheckWinner(x,y : integer) : Integer;
var i, links, rechts, k, l : Integer;
begin
  k:= 1;
  l:= 1;
  links:= 0;
  rechts:= 0;
  for i:= 1 to 3 do
    begin

      //Waagerecht
      if (x-3) < 0 then
      begin
        if Form1.StringGrid1.Cells[x,y] <> Form1.StringGrid1.Cells[x+i,y] then
        begin
          result:= 0;
          exit;
        end
      end

      else if (x+3) > 7 then
      begin
        if Form1.StringGrid1.Cells[x,y] <> Form1.StringGrid1.Cells[x-i,y] then
        begin
          result:= 0;
          exit;
        end;
      end;


      //Waagerecht

      {//Senkrecht
      if (y-3) <= 0 then
      begin
        result:= 0;
        exit
      end;
      if Form1.StringGrid1.Cells[x,y] <> Form1.StringGrid1.Cells[x,y-i] then
      begin
        result:= 0;
        exit;
      end;
      //Senkrecht }




    end//for
  result:= 1;

end;

procedure TForm1.StringGrid1Click(Sender: TObject);
var x,y : integer;
begin
  if gestartet then
  begin
    x:= Stringgrid1.Col;
    y:= Stringgrid1.Row;
    if amzug = 1 then
    begin
    y:= StringGrid1.RowCount-1;
      if StringGrid1.Cells[x,StringGrid1.RowCount-1] = '' then
        begin
          y:= StringGrid1.RowCount-1;
          StringGrid1.Cells[x,y]:= 'X'
        end
      else while StringGrid1.Cells[x,y] <> '' do
        begin
          if y<=0 then
          begin
            ShowMessage('Ungültiger Zug!');
            exit;
          end
          else y:= y-1;
        end//while

      StringGrid1.Cells[x,y]:= 'X';
      if CheckWinner(x,y) = 1 then ShowMessage('gewonnen');
    end//Spieler 1

    if amzug = 2 then
    begin
    y:= StringGrid1.RowCount-1;
      if StringGrid1.Cells[x,StringGrid1.RowCount-1] = '' then
        begin
          y:= StringGrid1.RowCount-1;
          StringGrid1.Cells[x,y]:= 'O'
        end

      else while StringGrid1.Cells[x,y] <> '' do
        begin
          if y<=0 then
          begin
            ShowMessage('Ungültiger Zug!');
            exit;
          end
          else y:= y-1;
        end//while

      StringGrid1.Cells[x,y]:= 'O';
      if CheckWinner(x,y) = 1 then ShowMessage('gewonnen');
    end//Spieler 2

    naechsterspieler;
  end//gestartet
end;

procedure naechsterspieler;
begin
  if amzug= 1 then
  begin
    amzug:= 2;
    Form1.StatusBar1.SimpleText:= Name2+' ist am Zug.';
  end
  else begin
    amzug:= 1;
    Form1.StatusBar1.SimpleText:= Name1+' ist am Zug.';
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  amzug:= 1;
end;

procedure TForm1.Button1Click(Sender: TObject);
var i : Integer;
begin
  if gestartet = false then
  begin
    gestartet:= true;
    Name1:= Edit1.Text;
    Name2:= Edit2.Text;
    StatusBar1.SimpleText:= Name1+' ist am Zug.';
    Button1.Caption:= 'Spiel Stoppen';
    Label1.Caption:= '';
  end

  else begin
    gestartet:= false;
    Button1.Caption:= 'Spiel Starten';
    for i:= 0 to (StringGrid1.RowCount - 1do StringGrid1.Rows[i].Clear;
    amzug:= 1;
    StatusBar1.SimpleText:= '';
    Label1.Caption:= 'Drücken sie zuerst auf "Spiel Starten".';
  end;
end;

end.


Ich hoffe er ist soweit verständlich und ihr könnt mir weiterhelfen.

Vielen Dank

n1con
Jann1k
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 866
Erhaltene Danke: 43

Win 7
TurboDelphi, Visual Studio 2010
BeitragVerfasst: Do 08.09.11 10:19 
Wenn ich deinen Code richtig verstehe, versuchst du jeweils zu prüfen, ob die nächsten drei Spielsteine von der gleichen Farbe sind. Problematisch dabei ist, dass der neu eingesetzte Spielstein nicht nur am Anfang bzw. Ende einer Viererkette stehen kann, sondern auch an einer der beiden mittleren Positionen.

Ich würde das ganze lieber so anstellen(angenommen man hat einen roten Spielstein eingeworfen):
Zähle die roten Spielsteine links vom neuen Stein bis man auf einen gelben trifft, zähle die roten Spielsteine rechts vom neuen Stein bis man auf einen gelben trifft, wenn linke Steine + rechte Steine + 1 (für den neuen Stein) >= 4 hat man gewonnen. Analog dazu kannst du die Diagonalen überprüfen. In der Senkrechten ist es einfacher, da du nur nach unten zu zählen brauchst. Das Zählen in einer Richtung kannst du leicht mit einer while Schleife realisieren, dabei aber wieder auf die Grenzen des Spielfeldes achten.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Do 08.09.11 10:23 
Hallo,

In da.zfx.info/forum/vi...der=asc&start=34 war mal eine lustige Diskussion dazu.

Aber was Dir wirklich weiter hilft ist wohl user profile iconFiete Version von vier Gewinnt.
www.delphi-forum.de/...t=vier+gewinnt+fiete

Gruß Horst
n1con Threadstarter
Hält's aus hier
Beiträge: 12
Erhaltene Danke: 1

Win7 Ultimate x64
Delphi 6, Delphi 2007
BeitragVerfasst: Do 08.09.11 16:28 
@Jann1k: die Idee hatte ich auch mal, hab sie dann aber auch aus Frust beim ersten Widerstand wieder verworfen. (Du kennst das vllt nach 4h Programmieren) Allerdings probiere ich das nochmal so.

Euch beiden schonmal Vielen Dank für die Hilfe. Ich melde mich sobald es erste Erfolge gibt.

LG n1con
n1con Threadstarter
Hält's aus hier
Beiträge: 12
Erhaltene Danke: 1

Win7 Ultimate x64
Delphi 6, Delphi 2007
BeitragVerfasst: Do 08.09.11 17:11 
So ich bin jetzt mal soweit Jann1k's Idee nachgegangen. Das ist dabei rausgekommen:

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:
function CheckWinner(x,y : integer) : Integer;
var i, links, rechts : Integer;
begin
  links:= 0;
  rechts:= 0;

  for i:= 1 to 3 do
    begin

      //Waagerecht
      if (x+i) < 7 then begin
        if Form1.StringGrid1.Cells[x,y] = Form1.StringGrid1.Cells[x+i,y] then rechts:= rechts+1;
      end;

      if (x-i) > 0 then begin
        if Form1.StringGrid1.Cells[x,y] = Form1.StringGrid1.Cells[x-i,y] then links:= links + 1;
      end;

    end//for
  if links+rechts+1 >= 4 then result:= 1;

end;


Allerdings funktioniert die ganze Geschichte noch nicht ganz hundertprozentig. Einige Situationen erkennt er aber nicht alle. Die die am Rand beginnen erkennt er noch nicht. Ich hoffe ihr könnt mir nochmal helfen.

LG n1con
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Do 08.09.11 17:32 
Hallo,

geht stringgrid nicht bei 0 los?
Also eher:
ausblenden Delphi-Quelltext
1:
if (x-i) >= 0 then begin					


Grusz Horst

Für diesen Beitrag haben gedankt: n1con
n1con Threadstarter
Hält's aus hier
Beiträge: 12
Erhaltene Danke: 1

Win7 Ultimate x64
Delphi 6, Delphi 2007
BeitragVerfasst: Do 08.09.11 17:35 
Danke ja du hast recht ;) jetzt funktioniert es.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Do 08.09.11 17:54 
Hallo,

user profile iconJann1k meinte es wohl mehr in dieser Richtung.
Man bricht die Schleife fruehzeitig ab.

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:
function CheckWinner(x,y : integer) : Integer;
var 
  i, sum : Integer;
  Spieler : string;
begin
  Spieler := Form1.StringGrid1.Cells[x,y]:
  sum := 1;
  
  //testet rechts
  i := x+1;
  while (i < 7do
    begin
    if Form1.StringGrid1.Cells[i,y] = Spieler then 
      inc(sum)
    else
      break:
    inc(i);
    end;
    
  //testet links
  i := x-1;
  while (i >= 0do
    begin
    if Form1.StringGrid1.Cells[i,y] = Spieler then 
      inc(sum)
    else
      break:
    dec(i);
    end;
    
  if sum >= 4 then 
    result:= 1
  else
    result := 0;  
end;


Grusz Horst
Jann1k
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 866
Erhaltene Danke: 43

Win 7
TurboDelphi, Visual Studio 2010
BeitragVerfasst: Do 08.09.11 22:28 
Kleine Anpassung von Horst_H Code, damit man auch ohne break auskommt.

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:
24:
25:
26:
27:
function CheckWinner(x,y : integer) : Integer;
var 
  i, sum : Integer;
  Spieler : string;
begin
  Spieler := Form1.StringGrid1.Cells[x,y]:
  sum := 1;
  
  //testet rechts
  i := x+1;
  while (i < 7and (Form1.StringGrid1.Cells[i,y] = Spieler) do
    inc(sum)
    inc(i);
  end;
    
  //testet links
  i := x-1;
  while (i >= 0and (Form1.StringGrid1.Cells[i,y] = Spieler) do
    inc(sum)
    dec(i);
  end;
    
  if sum >= 4 then 
    result:= 1
  else
    result := 0;  
end;



@N1con: Wenn du deinen bisherigen Code ausführlich testest, siehst du dass einige Situationen fälschlicherweise als Gewonnen markiert werden. Z.B. Rot - Rot - Gelb - Rot - Rot wird als gewonnen erkannt, wenn zuletzt das zweite Rot eingeworfen wurde.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 09.09.11 00:17 
Und wenn man jetzt noch etwas fleißig ist, erweitert man die Klasse so, dass sie auch für Tic Tac Toe und auf beliebig lange Reihen (vier, fünf, sechs) anwendbar ist. Eigentlich eine schöne Übung.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Fr 09.09.11 13:24 
Hallo,

ich haenge mal meine leicht geaenderte Version von developia an.
Das Prinzip ist dabei ein etwas anderes.
Ich habe fuer jede Spielfarbe fuenf Felder in Groesze des Spielfeldes.
Jeweils eins zur Bestimmung der waagerechten,senkrechten Nachbarn und der auf der Haupt und Nebendiagonalen.
Im fuenften Feld steht die an der Position die maximal erreichte Zahl an Nachbarn.Was aber wenig Sinn macht, aber egal. ( Es fehlt das Wissen an welcher Position man weitermachen sollte etc )

Betrachtet man eine waagerechte Linie, auf der zwei gleicharbige Steine mit einem Abstand liegen:
__X_X__
dann steht im Feld_waagerecht
0010100, die Steine haben nur sich selbst als Nachbarn.
Wirft man nun einen gleichfarbigen Stein in deren Mitte,
__XXX__ dann betrachtet man das Feld links und rechts davon und summiert die Anzahl aendert sich Feld_waagerecht zu.
0030300 . Also nur an den Enden wird die neue Anzahl der Nachbarn eingetragen, denn es kann auch nur an den Enden spaeter ein Spielstein hinzukommen.

Das hat den Vorteil, dass man im Prinzip auch 17 Gewinnt auf einem 200x 413 Feld spielen kann, ohne dass die Zeit zur Feststellung, ob gewonnen wurde, zunimmt gegenueber 4 gewinnt auf einem 6x7 Feld.

Der Aufwand macht aber nur Sinn, wenn der Computer auch mitspielt.

Grusz Horst
Einloggen, um Attachments anzusehen!
n1con Threadstarter
Hält's aus hier
Beiträge: 12
Erhaltene Danke: 1

Win7 Ultimate x64
Delphi 6, Delphi 2007
BeitragVerfasst: Fr 09.09.11 14:22 
Also mittlerweile sieht es bei mir so aus. Ich habe noch keine while Schleife drin, aber so funktioniert es waagerecht schon perfekt. Allerdings funktioniert senkrecht noch nicht ganz. Was habe ich da falsch gemacht?
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:
41:
42:
43:
function CheckWinner(x, y, dir : integer) : Integer;
var i, links, rechts, senkrecht : Integer;
begin
  links:= 0;
  rechts:= 0;
  senkrecht:= 0;

  for i:= 1 to 3 do
    begin
      case dir of
      //Waagerecht
      0begin
           if (x+i) <= 7 then begin
             if Form1.StringGrid1.Cells[x,y] = Form1.StringGrid1.Cells[x+i,y] then inc(rechts);
           end;

           if (x-i) >= 0 then begin
             if Form1.StringGrid1.Cells[x,y] = Form1.StringGrid1.Cells[x-i,y] then inc(links);
           end;
         end;
      //Waagerecht

      //Senkrecht
      1begin
           if (y+i) >= 0 then begin
             if Form1.StringGrid1.Cells[x,y] = Form1.StringGrid1.Cells[x,y+i] then inc(senkrecht);
           end;
         end;
      //Senkrecht
     end//case
    end//for

  case dir of
    0begin
         if (links+rechts+1) >= 4 then result:= 1;
       end;

    1begin
         if (senkrecht+1) >= 4 then result:= 1;
       end;

    end;
end;


EDIT: Habs selber rausgefunden. Sorry. aber was haltet ihr so mittlerweile davon?