Autor Beitrag
Jetstream
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 03:13 
Ich steh grade voll aufm Schlauch ...
hab den Algorithmus mehr oder weniger ausm Buch kopiert, er funzt aber nicht.

Zur Erklärung:
Ich schreibe grade an einer KI für ne Art Schach. Der Alpha-Beta-Algorithmus soll eine Spielstellung bewerten, indem er von einer gegebenen Brettstellung aus alle sinnvollen Möglichkeiten bildet, wie das Spielfeld in X Zügen aussehen könnte, und diese Möglichkeiten dann auswertet. Zurückgegeben wird ein Integer-Wert, der angibt, wie gut es grade für Weiss steht. Positive Werte bedeuten einen Vorteil für Weiss, negative für Schwarz. Genug Gelaber, hier der Code:
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:
28:
function TSpielfeld.alphaBeta(tiefe,alpha,beta:integer;Farbe:TSpielsteinfarbe):integer;
var
  a,i,wert:integer;
  Zugliste:TMovelist;
begin
  a := endposition; // endposition gibts an, ob das Spiel schon zu Ende ist.
  if a = 1 then Result :=  10000 else // Hier hätte Weiss gewonnen
  if a = 2 then Result := -10000 else // und hier Schwarz
  if (tiefe=0then Result := evaluate(Farbe) else // Rekursionsanker : Am Ende der 
  begin                                            // Baumstruktur wird ausgewertet. 
    Zugliste:=generateMoves(Farbe); // Züge erstellen
    for a:=1 to 32 do if Zugliste[a] <> nil then // Züge einzeln durchgehen
    begin
      doMove(Zugliste[a]);  // Zug ausführen
      wert := -alphaBeta(tiefe-1,-beta,-alpha,switchcolor(Farbe)); // resultierende Brettstellung auswerten
      undoMove(Zugliste[a]); // Zug zurücknehmen
      if wert >= beta  then  // Beta-Abbruch: Wenn der Zug "zu gut" ist, wird der Gegner 
      begin                  //               es gar nicht erst so weit kommen lassen
        Result:= beta;
        for i:=1 to 32 do FreeandNil(Zugliste[i]);
        exit;
      end;
      if wert > alpha then alpha :=wert; // Ist der Zug besser als der bisher beste, nehmen wir ihn.
    end;
    Result := alpha;  
    for i:=1 to 32 do FreeandNil(Zugliste[i]); 
  end;
end;

Der Algorithmus funktioniert solange, bis ich ihn mit einer Tiefe größer Null aufrufe :)
Dann wird nur noch Müll ausgegeben (Alle Züge haben die gleiche Bewertung etc. )

Sieht jemand den Fehler ?

// Edit: So, alles funzt. Zu bestaunen unter www.flechtmann.net/Sushi116.rar

// Version 1.0: Alpha-Beta funktioniert, Tiefe fest auf drei eingestellt.
// Version 1.1: Gewinnstellung wird erkannt, neu starten wird angeboten
// Version 1.11: Man kann nicht mehr mit jedem Stein alles vom Gegner schlagen (dummer Fehler)
// Version 1.12: Wenn man Schwarz wählt, zieht die KI zuerst (vorher vergessen zu implementieren)
// Version 1.13: Access Violation behoben
// Version 1.14: Bei gleich guten Zügen zieht er jetzt zufällig, das sorgt für Abwechslung.
// Version 1.15: Einen dummen Bug gefixt
// Version 1.16: Logo gebastelt, Neustart-Button, Rand verschöndert

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.


Zuletzt bearbeitet von Jetstream am Do 22.03.07 16:55, insgesamt 4-mal bearbeitet
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 21.12.06 09:02 
Vielleicht hilft dir eine NegaMax-(Besseres Alpha-Beta + Minimax) Implementierung weiter?

www.delphi-forum.de/...ieren_59658,100.html

Nach kurzem Studium deiner Implementierung vermisse ich die Angabe, welcher Zug denn nun der Beste ist...

Normalerweise würde ich die Funktion ja 'FindeDenBestenZug (.... Var BesterZug : TZug) : TBewertung' nennen (also sinngemäß).

_________________
Na denn, dann. Bis dann, denn.
Jetstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 11:06 
user profile iconalzaimar hat folgendes geschrieben:
Nach kurzem Studium deiner Implementierung vermisse ich die Angabe, welcher Zug denn nun der Beste ist...


Das wiederum erledigt eine andere Prozedur, die das ganze aufruft:
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:
28:
29:
30:
function TSpielfeld.getBestMove(Tiefe:integer;Farbe:TSpielsteinfarbe;movelistImage:TImage):TMove;
var
  a,alpha,beta,wert,auswahl:integer;
  Zugliste:TMoveList;
  Intliste:TIntlist;
begin
  alpha := -20000;
  beta  :=  20000;
  auswahl := 0;
  for a:=1 to 32 do Intliste[a]:=0;
  Zugliste := generateMoves(Farbe);
  for a:=1 to 32 do if Zugliste[a] <> nil then
  begin
    doMove(Zugliste[a]);
    if Farbe = Weiss   then wert :=   alphaBeta(Tiefe,alpha,beta,Schwarz)
                       else wert :=  -alphaBeta(Tiefe,alpha,beta,Weiss);
    undoMove(Zugliste[a]);
    Intliste[a] := wert;
    if wert >= beta  then
    begin
      Result := Zugliste[a];
      if movelistImage <> nil then movelistZeichnen(Zugliste,Intliste,movelistImage);
      exit;
    end;
    if wert > alpha then begin alpha :=wert; auswahl:=a; end;
  end;
  if auswahl = 0 then Result := TMove.create(1,1,1,1)
                 else Result := Zugliste[auswahl];
  if movelistImage <> nil then movelistZeichnen(Zugliste,Intliste,movelistImage);
end;
Funtioniert tadellos, man könnte aber bestimmt noch beide Funktionen zusammenschreiben ...

Zum NegaMax: Ich hatte eigentlich gelesen, dass Alpha-Beta eine Verbesserung des NegaMax darstellt.
NegaMax ist eine Verbesserung des MiniMax und macht aus zwei Prozeduren (Max und Min) eine einzige. (Unter der Annahme, dass man statt "Minimum" auch einfach "Maximum der Negativa" verstehen kann. Alpha-Beta beherrscht zusätzlich noch den Beta-Abbruch, um Rechenzeit zu sparen.

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 21.12.06 12:04 
user profile iconJetstream hat folgendes geschrieben:
Funtioniert tadellos, man könnte aber bestimmt noch beide Funktionen zusammenschreiben ...

Ich dachtem, es funktioniert doch nur bei Zugtiefe = 0 tadellos :wink:
Du solltest die AlphaBeta-Routine so erweitern, das sie auch den besten Zug zurückliefert.
user profile iconJetstream hat folgendes geschrieben:
...Ich hatte eigentlich gelesen, dass Alpha-Beta eine Verbesserung des NegaMax darstellt. NegaMax ist eine Verbesserung des MiniMax und macht aus zwei Prozeduren (Max und Min) eine Einzige...

Stimmt, hatte ich verwechselt: Vielleicht übernimmst Du einfach die Ermittlung des besten Zuges aus meinem Algorithmus (zumindest als Anhaltspunkt, weil Du bestimmt eine eigene Implementierung haben willst):

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:
Type
  TMove = record
    mPlayer,                    // Welcher Stein ist auf dem Feld
      mPrev: TPlayer;           // Welcher Stein war vorher drauf (beim Zurücknehmen des Zuges)
    mFrom, mTo: TPoint;         // Zug geht von mFrom nach mTo
    mScore: Integer;            // Bewertung des Zuges hoher Wert = gut
  end;

Function AlphaBeta(Level: Integer; aPlayer, aOpponent: TPlayer; Var aBoard: TBoard; Var aBestMove: TMove; Alpha, Beta: Integer; aPatt: Boolean): Integer;
Var
  aMoves: TMoveList;
  I, N, S: Integer;

Begin
  Result := sPassScore;
  aBestMove.mPlayer := plEmpty;
// CreateAllMoves erzeugt eine Liste aller möglichen Züge und bewertet sie.
  CreateAllMoves(aPlayer, aOpponent, aBoard, aMoves, N); 
// Sortieren, damit gute Zuge zuerst ausgeführt werden und somit A/B schneller greift
// Die Liste wird anhand der Zugbewertung sortiert. Die sollte rudimentär (also schnell) 
// sein und eben z.B. Gewinnzüge mit hohen Werten belegen
  if level>0 Then
    SortMoveList(aBoard, aMoves, Level,aPlayer, aOpponent); 
  If aMoves.Count = 0 Then                                    // Keine Züge vorhanden
    If aPatt Then                         // Wenn der Aufrufer auch nicht konnte, ... 
      Result := 0                                              // ... ist es ein Patt
    Else                    // ... ansonsten den Gegner ziehen lassen mit 'aPatt=True'
      Result := -AlphaBeta(Level, aOpponent, aPlayer, aBoard, M, -beta, -alpha, True)
  Else Begin
    inc(iTotal);
    For i := 0 To aMoves.Count - 1 Do Begin       // Nacheinander alle Züge ausführen
      MakeMove(aBoard, aMoves[i]);
      if (Level = 0or (amoves[i].mScore >= sWinScore) then // Bei Zugtiefe 0 nehmen
        S := aMoves[i].mScore         // wir die Zugbewertung, besser wäre jedoch die 
      Else                                         // ausführliche Stellungsbewertung
        S := -AlphaBeta(Level - 1, aOpponent, aPlayer, aBoard, M, -beta, -alpha, False);
      UndoMove(aBoard, aMoves[i]);                                // Zug zurücknehmen
      If (s >= beta) Then Begin                                   // Beta Optimierung 
        aBestMove := aMoves[i];                               // Besser geht es nicht
        Result := Beta;
        Exit;                        // Also abbruch, denn Weitersuchen bringt nichts
      End;
      If (S > alpha) Then Begin
        Alpha := S;
        aBestMove := aMoves[i];
      End
    End;
    Result := Alpha;
  End;
End;

// Mit dieser Funktion findet man den besten Zug 'aBestMove' des Spielers mit der Farbe 'aPlayer'
// Die Funktion soll bis zu einer Zugtiefe von aLevel rechnen. Es wird der 'Wert' des besten Zuges
// geliefert.
// Wenn aBestMove.mPlayer = plEmpty, dann konnte kein Zug gefunden werden
//
function FindBestMove(aLevel: Integer; aPlayer, aOpponent: TPlayer; var aBoard: TBoard; var aBestMove: TMove): Integer;
begin
  Result := AlphaBeta(aLevel, aPlayer, aOpponent, aBoard, aBestMove, -maxint, maxint);
end;

_________________
Na denn, dann. Bis dann, denn.
Jetstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 12:31 
user profile iconalzaimar hat folgendes geschrieben:
user profile iconJetstream hat folgendes geschrieben:
Funtioniert tadellos, man könnte aber bestimmt noch beide Funktionen zusammenschreiben ...

Ich dachtem, es funktioniert doch nur bei Zugtiefe = 0 tadellos :wink:
Das war auch nur auf die getBestMove-Funktion begrenzt. Was nicht funzt, ist alphaBeta.

Ich sehe jetzt nur keinen großen Unterschied zwischen unseren Funktionen.
Gut, du hast die Bewertung eines Zuges gleich in den Zug gesteckt, ich hab dafür ne eigene Prozedur ... deins is da eleganter. Trotzdem müsste meins doch auch funktionieren.

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 21.12.06 12:43 
Ich glaube, der Fehler ist Folgender:
Verlfleichen wir meine Routine:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
...
    S := -AlphaBeta(Level - 1, aOpponent, aPlayer, aBoard, M, -beta, -alpha, False);
    UndoMove(aBoard, aMoves[i]);
    ...
    If (S > alpha) Then Begin
      Alpha := S;
      aBestMove := aMoves[i];
   End;
...

Mit GetBestMove von Dir:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
...
    if Farbe = Weiss   then wert :=   alphaBeta(Tiefe,alpha,beta,Schwarz)
                       else wert :=  -alphaBeta(Tiefe,alpha,beta,Weiss);
...
    if wert > alpha then begin alpha :=wert; auswahl:=a; end;
...

Das ist ja (fast das gleiche), aber ... :mrgreen:
Du rufst alphaBeta mit 'alpha,beta' auf, es müsste aber doch '-beta, -alpha' heißen, schließlich suchst Du dann den besten Zug des GEGNERS...

[edit] Sortierst Du deine Zugliste? [/edit]

_________________
Na denn, dann. Bis dann, denn.
Jetstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 13:55 
Nein, ich sortiere nicht, habe aber auch gelesen, dass es die Performance erhöhen soll.

Du betrachtest grade die Funktion, die funktioniert. Was nicht funktioniert, ist die Funktion aus dem ersten Post.

Vergleichen wir die mal:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
meins:
    wert := -alphaBeta(tiefe-1,-beta,-alpha,switchcolor(Farbe)); // resultierende Brettstellung auswerten
    undoMove(Zugliste[a]); // Zug zurücknehmen

deins:
    S := -AlphaBeta(Level - 1, aOpponent, aPlayer, aBoard, M, -beta, -alpha, False);
    UndoMove(aBoard, aMoves[i]);

Kein Unterschied zu entdecken ...

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 21.12.06 14:02 
user profile iconJetstream hat folgendes geschrieben:
Nein, ich sortiere nicht, habe aber auch gelesen, dass es die Performance erhöhen soll.

Es erhöht die Performance, weil das Pruning (Abschnippeln des Suchbaumes) viel früher ansetzt.

user profile iconJetstream hat folgendes geschrieben:
Du betrachtest grade die Funktion, die funktioniert. Was nicht funktioniert, ist die Funktion aus dem ersten Post....
Kein Unterschied zu entdecken ...

Wenn da keiner wäre, müsste es ja laufen.

Deine GetBestMove-Routine ruft AlphaBeta falsch auf. Innerhalb des Alpha-Beta machst du Alles richtig. Versuch's doch einfach mal.

_________________
Na denn, dann. Bis dann, denn.
Jetstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 14:16 
user profile iconalzaimar hat folgendes geschrieben:
Deine GetBestMove-Routine ruft AlphaBeta falsch auf.

Wenn ich daraus aus alpha,beta einfach -beta,-alpha mache, ruft er die routine mit genau den gleichen werten auf ... -20000 und 20000

Wie gesagt, getBestMove(0,Weiss,nil) funzt bestens.
getBestMove(1,Weiss,nil) geht leider gar nicht. (Produziert nur Quark, die Steine rennen manisch hin und her).
Gleiches bei allen höheren Tiefen.

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.


Zuletzt bearbeitet von Jetstream am Do 21.12.06 14:22, insgesamt 1-mal bearbeitet
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 21.12.06 14:19 
Aber du veränderst doch Alpha .... und dann sieht die Welt doch anders aus

_________________
Na denn, dann. Bis dann, denn.
Jetstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 14:26 
Oh, du hast Recht ... ist mir gar nicht aufgefallen.
Da muss aber irgendwo noch ein Fehler sein, jetzt verändert sich nur das Verhalten von Schwarz auf Tiefe Eins: Schwarz spielt auf einmal gut !
Auf höheren Ebenen weiterhin Chaos.

//Edit: Nein, immernoch überall Chaos. Muss an alphaBeta liegen.

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 21.12.06 14:31 
Um 'mein' AlphaBeta zu testen, habe ich mal AB und NegaMax parallel aufgerufen (2x Delphi offen) und bin dann Schritt-für-Schritt durchgegangen. Dabei findet man i.a. die Stelle, an der es hakt. Sortiere am Besten die Züge, damit A/B vorhersagbar abbricht.

Ich vermute, das es irgend eine blöde Stelle ist: Ich sehe nämlich auch beim 2. Hinsehen keinen Fehler ...

Ich hack' nochmal auf GetBestMove (und dem Aufruf von AlphaBeta) herum: Deine Funktion, die die Spielstellung bewertet, tut das doch hoffentlich immer aus der Sicht eines Spielers, oder?

Meine Funktion hat folgenden Kopf:
ausblenden Delphi-Quelltext
1:
Function ScoreBoard (aBoard : TBoard; aPlayer : TPlayer) : Integer;					

Sie liefert immer einen hohen Wert, wenn die Stellung für den aPlayer gut ist, egal welche Farbe aPlayer hat!

_________________
Na denn, dann. Bis dann, denn.
Jetstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 17:55 
Öhm, evaluate liefert einen absoluten Wert, ist das falsch ?
D.h. wenn Weiss besser steht, liefert evaluate einen positiven Wert, wenn Schwarz besser steht einen negativen.
evaluate bekommt aber als Parameter die Farbe übergeben, die am Zug ist.

//Edit: Du hattest absolut Recht !
Die evaluate-Funktion muss für gute Stellungen der Farbe, die am Zug ist, immer POSITIVE Werte liefern :mahn:
Ich hatte positive für Weiss und negative für Schwarz. :autsch:
Jetzt funktioniert alles, wie es soll ...
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:
function TSpielfeld.alphaBeta(tiefe,alpha,beta:integer;Farbe:TSpielsteinfarbe):integer;
var
  a,i,wert:integer;
  Zugliste:TMovelist;
begin
  a := endposition;
  if (a = 1and (Farbe = Weiss)   then Result :=  10000 else //geändert
  if (a = 2and (Farbe = Weiss)   then Result := -10000 else //geändert
  if (a = 1and (Farbe = Schwarz) then Result := -10000 else //geändert
  if (a = 2and (Farbe = Schwarz) then Result :=  10000 else //geändert
  if (tiefe=0then Result := evaluate(Farbe) else  //evaluate geändert
  begin
    Zugliste:=generateMoves(Farbe);
    // Züge sortieren
    for a:=1 to 32 do if Zugliste[a] <> nil then
    begin
      doMove(Zugliste[a]);
      wert := -alphaBeta(tiefe-1,-beta,-alpha,switchcolor(Farbe));
      undoMove(Zugliste[a]);
      if wert >= beta  then
      begin
        Result:= beta;
        for i:=1 to 32 do FreeandNil(Zugliste[i]);
        exit;
      end;
      if wert > alpha then alpha :=wert;
    end;
    Result := alpha;
    for i:=1 to 32 do FreeandNil(Zugliste[i]);
  end;
end;

function TSpielfeld.getBestMove(Tiefe:integer;Farbe:TSpielsteinfarbe;movelistImage:TImage):TMove;
var
  a,alpha,beta,wert,auswahl:integer;
  Zugliste:TMoveList;
  Intliste:TIntlist;
begin
  alpha := -20000;
  beta  :=  20000;
  auswahl := 0;
  for a:=1 to 32 do Intliste[a]:=0;
  Zugliste := generateMoves(Farbe);
  for a:=1 to 32 do if Zugliste[a] <> nil then
  begin
    doMove(Zugliste[a]);
    wert :=  -alphaBeta(Tiefe,-beta,-alpha,switchcolor(Farbe)); //geändert
    undoMove(Zugliste[a]);
    Intliste[a] := wert;
    if wert >= beta  then
    begin
      Result := Zugliste[a];
      if movelistImage <> nil then movelistZeichnen(Zugliste,Intliste,movelistImage);
      exit;
    end;
    if wert > alpha then begin alpha :=wert; auswahl:=a; end;
  end;
  if auswahl = 0 then Result := TMove.create(1,1,1,1)
                 else Result := Zugliste[auswahl];
  if movelistImage <> nil then movelistZeichnen(Zugliste,Intliste,movelistImage);
end;
Thx alzaimar !!! :flehan:

Neue Version ist geupdated, www.flechtmann.net/Sushi.exe

Jetzt muss ich nur noch die Züge sortieren :)

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.


Zuletzt bearbeitet von Jetstream am Do 21.12.06 20:30, insgesamt 1-mal bearbeitet
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 21.12.06 19:08 
Hi, hab mir eben das Spiel angeschaut:

Was für eine köstlich dämliche Idee für so ein göttlich geniales Spielchen. Lass Dir diese Spielidee (wenn Sie denn von Dir ist) sofort(!) patentieren, sonst tu ich es :zwinker:

_________________
Na denn, dann. Bis dann, denn.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Do 21.12.06 19:31 
:lol: Das ist ja mal eine witzige Idee :zustimm:

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Do 21.12.06 19:38 
Ahem... kommt mir irgendwie von ICQ bekannt vor....

Aber trotzdem schöne Umsetzung!

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Jetstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 222



BeitragVerfasst: Do 21.12.06 19:46 
Das Spiel hat sich der große Bruder meine Freundin ausgedacht, gibts schon bei Amazon.

Hab grade nochmal ne neue Version hochgeladen, man konnte bisher mit jedem Stein jeden gegnerischen schlagen ;)

_________________
Die folgenden Klangbeispiele sind Ergänzungen zum methodischen Aufbau der Textbeilage und dürfen nicht losgelöst von dieser behandelt werden.
wolke
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 240



BeitragVerfasst: Do 21.12.06 21:30 
nettes spiel. kann man auch gewinnen? ;)

bin wohl zu blöd...