Das beliebte -XXO- Spiel

Hab vor ein paar Jahren auch mal ein TicTacToe in JavaScript gebaut... zu finden auf meiner JavaScript-Spieleseite. Perfekt ist die K.I. nicht, man kann sie schlagen. Ob ich das heute auch noch so programmieren würde, bezweifle ich aber *g
 
Derzeit mit einer Pseudo-KI

Code:
// tick tack toe von Christoph Maurer

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

char field[9]={0,0,0,0,0,0,0,0,0};

void printField()
{
     for(int i=0;i<9;i++)
     {       
             if(i%3==0 && i!=0)
                cout<<endl;
             if(field[i]==0)
                cout<<"_";
             else cout<<field[i];

     }
     cout<<endl;
}

// prüfen ob jemand gewonnen hat ('o'==computer,'x'==mensch,0==niemand)
char winner()
{
     // horizontal
     for(int y=0;y<3;y++)
     {
         for(int x=1;x<3;x++)
         {
                 if(field[y*3]!=field[y*3+x] || field[y*3]==0)
                    break;  
                 if(x==2)
                    return field[y*3];
         }
     }
     // vertikal
     for(int x=0;x<3;x++)
     {
         for(int y=0;y<2;y++)
         {
                 if(field[y*3+x]!=field[(y+1)*3+x] || field[y*3+x]==0)
                    break;  
                 if(y==1)
                    return field[y*3+x];
         }
     }
     // diagonal
     if((field[0]=='x' && field[4]=='x' && field[8]=='x') || (field[2]=='x' && field[4]=='x' && field[6]=='x'))
                       return 'x';
          if((field[0]=='o' && field[4]=='o' && field[8]=='o') || (field[2]=='o' && field[4]=='o' && field[6]=='o'))
                       return 'o';
     return 0;
}

// computer setzt den stein an der nächsten freien position
// er beginnt an einer zufälligen position zu suchen
void setNextFree()
{
     int startpos = rand()%9;
     for(int i=0;i<9;i++)
     {
             if(i==9) 
               i = 0;
             if(field[i+startpos]==0)
             {
               field[i+startpos]='o';
               return;
             }
     }
}

int main() 
{
    srand(time(NULL));
    char w;  
    int pos;  
    for(int i=0;i<9;i++)
    {
            system("cls");
            printField();
            cout<<"Stein setzen(0-8):";
            cin>>pos;
            field[pos]='x';
            if(w=winner())
               break;
            setNextFree();  
            if(w=winner())
               break;      
    }
    system("cls");
    printField();

    if(w)
      cout<<"The Winner is "<<w<<endl;

  system("PAUSE");
  return 0;
}
 
TicTacToe halbintelligent

Nachdem ich das Spiel an und für sich schon länger fertig hatte - allerdings für zwei menschliche Spieler - hab ich jetzt auch endlich die "KI"-Version fertig bekommen.

Das halbintelligent im Titel deshalb, weil die "KI" erst aktiv wird, sobald eine Gewinnmöglichkeit für den Spieler oder den CPU da ist - solange das nicht gegeben ist, wird per random gesetzt. Somit sind entstehende Zwickmühlen seitens des Computers reiner Zufall, kommen aber gelegentlich vor.

In der TicTacToe.zip ist der gesamte Projektordner drin, in der TicTacToeExe.zip nur die .exe (wie der Name ja schon vermuten lässt;))

Code:
Public Class TicTacToe

    Private spieler As String = ""
    Private xWin As Byte = 0
    Private oWin As Byte = 0
    Private draw As Byte = 0
    Private vsCPU As Boolean = True
    Private gewinn(2, 2) As Byte
    Private zwischen As String

    Private Sub Eintragen(ByVal sender As Object, ByVal e As EventArgs) Handles btn1.Click, btn2.Click, _
                        btn3.Click, btn4.Click, btn5.Click, btn6.Click, btn7.Click, btn8.Click, btn9.Click
        Dim ausloeser As Button = sender
        If ausloeser.Tag = 0 Then
            If spieler = "X" Then
                ausloeser.Text = "X"
                GewinnEintrag(ausloeser, 5)
            Else
                ausloeser.Text = "O"
                GewinnEintrag(ausloeser, 2)
            End If
            ausloeser.Tag = 1
            Ueberpruefen()
            SpielerAendern()
        End If
    End Sub

    Private Sub SpielerAendern()
        If spieler = "X" Then
            spieler = "O"
            If vsCPU = True Then
                CpuIntelligent()
            End If
        Else
            spieler = "X"
        End If
    End Sub

    Private Function Ueberpruefen() As Boolean
        If (btn1.Text = btn2.Text And btn2.Text = btn3.Text And btn1.Text <> "") Or _
            (btn4.Text = btn5.Text And btn5.Text = btn6.Text And btn4.Text <> "") Or _
            (btn7.Text = btn8.Text And btn8.Text = btn9.Text And btn7.Text <> "") Or _
            (btn1.Text = btn4.Text And btn4.Text = btn7.Text And btn1.Text <> "") Or _
            (btn2.Text = btn5.Text And btn5.Text = btn8.Text And btn2.Text <> "") Or _
            (btn3.Text = btn6.Text And btn6.Text = btn9.Text And btn3.Text <> "") Or _
            (btn1.Text = btn5.Text And btn5.Text = btn9.Text And btn1.Text <> "") Or _
            (btn3.Text = btn5.Text And btn5.Text = btn7.Text And btn3.Text <> "") Then
            MsgBox("Spieler " & spieler & " gewinnt!", MsgBoxStyle.Information, "Gewonnen!!!")
            If spieler = "X" Then
                xWin += 1
            Else
                oWin += 1
            End If
            Reset()
        ElseIf btn1.Text <> "" And btn2.Text <> "" And btn3.Text <> "" And btn4.Text <> "" And _
            btn5.Text <> "" And btn6.Text <> "" And btn7.Text <> "" And btn8.Text <> "" And btn9.Text <> "" Then
            draw += 1
            MsgBox("Unentschieden!", MsgBoxStyle.Information, "Unentschieden!")
            Reset()
        End If
        lblXWin.Text = "X Win: " & xWin
        lblOWin.Text = "O Win: " & oWin
        lblDraw.Text = "Draw: " & draw
    End Function

    Private Sub Reset()
        btn1.Text = ""
        btn2.Text = ""
        btn3.Text = ""
        btn4.Text = ""
        btn5.Text = ""
        btn6.Text = ""
        btn7.Text = ""
        btn8.Text = ""
        btn9.Text = ""
        btn1.Tag = 0
        btn2.Tag = 0
        btn3.Tag = 0
        btn4.Tag = 0
        btn5.Tag = 0
        btn6.Tag = 0
        btn7.Tag = 0
        btn8.Tag = 0
        btn9.Tag = 0
        For x As Byte = 0 To 2
            For y As Byte = 0 To 2
                gewinn(x, y) = 0
            Next
        Next
    End Sub

    Private Sub btnReset_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReset.Click
        Reset()
        draw += 1
        lblDraw.Text = "Draw: " & draw
    End Sub

    Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click
        End
    End Sub

    Private Sub TicTacToe_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If MsgBox("Haben Sie einen menschlichen Gegnner neben sich?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
            vsCPU = False
        Else
            CpuIntelligent()
        End If
    End Sub

    Public Sub CpuIntelligent()
        zwischen = AuswertungText()
        If zwischen = "rnd" Then
            Randomize()
            Do Until spieler = "X"
                Dim zufall As Byte = CByte(8 * Rnd() + 1)
                Dim clicker As Button = TryCast(Me.Controls("btn" & zufall), Button)
                clicker.PerformClick()
            Loop
        Else
            Dim clicker As Button = TryCast(Me.Controls(zwischen), Button)
            clicker.PerformClick()
        End If
    End Sub

    Public Sub GewinnEintrag(ByVal ausloeser As Button, ByVal x As Byte)
        Select Case ausloeser.Name
            Case "btn1"
                gewinn(0, 0) = x
            Case "btn2"
                gewinn(0, 1) = x
            Case "btn3"
                gewinn(0, 2) = x
            Case "btn4"
                gewinn(1, 0) = x
            Case "btn5"
                gewinn(1, 1) = x
            Case "btn6"
                gewinn(1, 2) = x
            Case "btn7"
                gewinn(2, 0) = x
            Case "btn8"
                gewinn(2, 1) = x
            Case "btn9"
                gewinn(2, 2) = x
        End Select
    End Sub

    Public Function AuswertungArray(ByVal arr As Array) As String
        If arr(0, 0) <> 5 And ((arr(1, 0) + arr(2, 0) = 4) Or (arr(0, 1) + arr(0, 2) = 4) Or (arr(1, 1) + arr(2, 2) = 4)) Then
            Return "btn1"
            Exit Function
        ElseIf arr(1, 0) <> 5 And ((arr(0, 0) + arr(2, 0) = 4) Or (arr(1, 1) + arr(1, 2) = 4)) Then
            Return "btn2"
            Exit Function
        ElseIf arr(2, 0) <> 5 And ((arr(0, 0) + arr(1, 0) = 4) Or (arr(2, 1) + arr(2, 2) = 4) Or (arr(1, 1) + arr(0, 2) = 4)) Then
            Return "btn3"
            Exit Function
        ElseIf arr(0, 1) <> 5 And ((arr(1, 1) + arr(2, 1) = 4) Or (arr(0, 0) + arr(0, 2) = 4)) Then
            Return "btn4"
            Exit Function
        ElseIf arr(1, 1) <> 5 And ((arr(0, 0) + arr(2, 2) = 4) Or (arr(2, 0) + arr(0, 2) = 4) Or _
                (arr(1, 0) + arr(1, 2) = 4) Or (arr(0, 1) + arr(2, 1) = 4)) Then
            Return "btn5"
            Exit Function
        ElseIf arr(2, 1) <> 5 And ((arr(2, 0) + arr(2, 2) = 4) Or (arr(0, 1) + arr(1, 1) = 4)) Then
            Return "btn6"
            Exit Function
        ElseIf arr(0, 2) <> 5 And ((arr(0, 0) + arr(0, 1) = 4) Or (arr(1, 2) + arr(2, 2) = 4) Or (arr(2, 0) + arr(1, 1) = 4)) Then
            Return "btn7"
            Exit Function
        ElseIf arr(1, 2) <> 5 And ((arr(0, 2) + arr(2, 2) = 4) Or (arr(1, 0) + arr(1, 1) = 4)) Then
            Return "btn8"
            Exit Function
        ElseIf arr(2, 2) <> 5 And ((arr(2, 0) + arr(2, 1) = 4) Or (arr(0, 2) + arr(1, 2) = 4) Or (arr(0, 0) + arr(1, 1) = 4)) Then
            Return "btn9"
            Exit Function
        ElseIf arr(0, 0) <> 2 And ((arr(1, 0) + arr(2, 0) = 10) Or (arr(0, 1) + arr(0, 2) = 10) Or (arr(1, 1) + arr(2, 2) = 10)) Then
            Return "btn1"
            Exit Function
        ElseIf arr(1, 0) <> 2 And ((arr(0, 0) + arr(2, 0) = 10) Or (arr(1, 1) + arr(1, 2) = 10)) Then
            Return "btn2"
            Exit Function
        ElseIf arr(2, 0) <> 2 And ((arr(0, 0) + arr(1, 0) = 10) Or (arr(2, 1) + arr(2, 2) = 10) Or (arr(1, 1) + arr(0, 2) = 10)) Then
            Return "btn3"
            Exit Function
        ElseIf arr(0, 1) <> 2 And ((arr(1, 1) + arr(2, 1) = 10) Or (arr(0, 0) + arr(0, 2) = 10)) Then
            Return "btn4"
            Exit Function
        ElseIf arr(1, 1) <> 2 And ((arr(0, 0) + arr(2, 2) = 10) Or (arr(2, 0) + arr(0, 2) = 10) Or _
                (arr(1, 0) + arr(1, 2) = 10) Or (arr(0, 1) + arr(2, 1) = 10)) Then
            Return "btn5"
            Exit Function
        ElseIf arr(2, 1) <> 2 And ((arr(2, 0) + arr(2, 2) = 10) Or (arr(0, 1) + arr(1, 1) = 10)) Then
            Return "btn6"
            Exit Function
        ElseIf arr(0, 2) <> 2 And ((arr(0, 0) + arr(0, 1) = 10) Or (arr(1, 2) + arr(2, 2) = 10) Or (arr(2, 0) + arr(1, 1) = 10)) Then
            Return "btn7"
            Exit Function
        ElseIf arr(1, 2) <> 2 And ((arr(0, 2) + arr(2, 2) = 10) Or (arr(1, 0) + arr(1, 1) = 10)) Then
            Return "btn8"
            Exit Function
        ElseIf arr(2, 2) <> 2 And ((arr(2, 0) + arr(2, 1) = 10) Or (arr(0, 2) + arr(1, 2) = 10) Or (arr(0, 0) + arr(1, 1) = 10)) Then
            Return "btn9"
            Exit Function
        Else
            Return "rnd"
        End If
    End Function

    Public Function AuswertungText() As String
        If btn1.Text <> "X" And ((btn2.Text = "O" And btn3.Text = "O") Or (btn4.Text = "O" And btn7.Text = "O") Or (btn5.Text = "O" And btn9.Text = "O")) Then
            Return "btn1"
            Exit Function
        ElseIf btn2.Text <> "X" And ((btn1.Text = "O" And btn3.Text = "O") Or (btn5.Text = "O" And btn8.Text = "O")) Then
            Return "btn2"
            Exit Function
        ElseIf btn3.Text <> "X" And ((btn1.Text = "O" And btn2.Text = "O") Or (btn6.Text = "O" And btn9.Text = "O") Or (btn5.Text = "O" And btn7.Text = "O")) Then
            Return "btn3"
            Exit Function
        ElseIf btn4.Text <> "X" And ((btn1.Text = "O" And btn7.Text = "O") Or (btn5.Text = "O" And btn6.Text = "O")) Then
            Return "btn4"
            Exit Function
        ElseIf btn5.Text <> "X" And ((btn2.Text = "O" And btn8.Text = "O") Or (btn4.Text = "O" And btn6.Text = "O") Or _
                                    (btn1.Text = "O" And btn9.Text = "O") Or (btn7.Text = "O" And btn3.Text = "O")) Then
            Return "btn5"
            Exit Function
        ElseIf btn6.Text <> "X" And ((btn4.Text = "O" And btn5.Text = "O") Or (btn3.Text = "O" And btn9.Text = "O")) Then
            Return "btn6"
            Exit Function
        ElseIf btn7.Text <> "X" And ((btn1.Text = "O" And btn4.Text = "O") Or (btn8.Text = "O" And btn9.Text = "O") Or (btn5.Text = "O" And btn3.Text = "O")) Then
            Return "btn7"
            Exit Function
        ElseIf btn8.Text <> "X" And ((btn7.Text = "O" And btn9.Text = "O") Or (btn2.Text = "O" And btn5.Text = "O")) Then
            Return "btn8"
            Exit Function
        ElseIf btn9.Text <> "X" And ((btn7.Text = "O" And btn8.Text = "O") Or (btn3.Text = "O" And btn6.Text = "O") Or (btn1.Text = "O" And btn5.Text = "O")) Then
            Return "btn9"
            Exit Function
        ElseIf btn1.Text <> "O" And ((btn2.Text = "X" And btn3.Text = "X") Or (btn4.Text = "X" And btn7.Text = "X") Or (btn5.Text = "X" And btn9.Text = "X")) Then
            Return "btn1"
            Exit Function
        ElseIf btn2.Text <> "O" And ((btn1.Text = "X" And btn3.Text = "X") Or (btn5.Text = "X" And btn8.Text = "X")) Then
            Return "btn2"
            Exit Function
        ElseIf btn3.Text <> "O" And ((btn1.Text = "X" And btn2.Text = "X") Or (btn6.Text = "X" And btn9.Text = "X") Or (btn5.Text = "X" And btn7.Text = "X")) Then
            Return "btn3"
            Exit Function
        ElseIf btn4.Text <> "O" And ((btn1.Text = "X" And btn7.Text = "X") Or (btn5.Text = "X" And btn6.Text = "X")) Then
            Return "btn4"
            Exit Function
        ElseIf btn5.Text <> "O" And ((btn2.Text = "X" And btn8.Text = "X") Or (btn4.Text = "X" And btn6.Text = "X") Or _
                                    (btn1.Text = "X" And btn9.Text = "X") Or (btn7.Text = "X" And btn3.Text = "X")) Then
            Return "btn5"
            Exit Function
        ElseIf btn6.Text <> "O" And ((btn4.Text = "X" And btn5.Text = "X") Or (btn3.Text = "X" And btn9.Text = "X")) Then
            Return "btn6"
            Exit Function
        ElseIf btn7.Text <> "O" And ((btn1.Text = "X" And btn4.Text = "X") Or (btn8.Text = "X" And btn9.Text = "X") Or (btn5.Text = "X" And btn3.Text = "X")) Then
            Return "btn7"
            Exit Function
        ElseIf btn8.Text <> "O" And ((btn7.Text = "X" And btn9.Text = "X") Or (btn2.Text = "X" And btn5.Text = "X")) Then
            Return "btn8"
            Exit Function
        ElseIf btn9.Text <> "O" And ((btn7.Text = "X" And btn8.Text = "X") Or (btn3.Text = "X" And btn6.Text = "X") Or (btn1.Text = "X" And btn5.Text = "X")) Then
            Return "btn9"
            Exit Function
        Else
            Return "rnd"
        End If
    End Function
End Class

Die ungenutzte Funktion "AuswertungArray" war der erste Versuch, dem Computer Setz-Anweisungen zu geben, ist aber i-wie fehlerhaft. Da ich evtl. mal gucken will, ob ich den Computer noch intelligenter bekomme, hab ich die aber mal dringelassen.

Edit: Hatte aus Versehen ne alte Version der .exe hochgeladen - jetzt passts.
 
Zuletzt bearbeitet:
Was für ein Zufall

Hallo zusammen

Da habe ich heute zufällig und unabhängig vom board mit meiner Klasse ein TicTacToe gebaut. Das Thema ist die Rekursion und da habe ich den Schülern die Mini-Max-Strategie erklärt.

Da ich das TicTacToe vorher nie programmiert hatte, ist der Code nicht perfekt (TicTacToe2.zip auspacken, der Quelltext liegt auch hier im Jar-File).

Die Lehrlinge im 2. Lehrjahr wurden nach 3 Lektionen nicht ganz damit fertig (wir werden morgen noch daran arbeiten). Ich habs in 2 Stunden geschafft (Chrisiaut scheint also mit seiner Schätzung ins Schwarze zu treffen - jedoch muss ich zu meiner Schande gestehen, dass ich schon seit 1984 programmiere, sollte also schon etwas rascher von der Tastatur gehen, gell ;)).

Was die KI anbelangt: Mit der Mini-Max-Strategie ist TicTacToe nicht zu besiegen! Soweit die Theorie, und soweit auch meine bisherigen Erfahrungen mit meinem eigenen Programm. Die Mini-Max-Strategie kann beim TicTacToe den vollen Spielbaum absuchen, und macht so garantiert nie einen Fehler! Ich habe also keine Abbruchbedingung wegen der Suchtiefe eingebaut.

Viel Spaß beim studieren des Java-Codes für die, die noch nicht soweit sind.
 
Zuletzt bearbeitet:
Ich habe das Spiel jetzt auch mal in C geschrieben. Es läuft aber endlos und der Computer zieht manchmal nicht, weil eine nicht vorhergesehene Stellung aufgetreten ist, aber ich denke, man kann es mal veröffentlichen:p
PS: Sorry für meinen Spaghetticode, aber der Compiler hat das Linken der Dateien nicht kapiertX(. Ihr könnt ja trotzdem mal versuchen den Code zu erweitern;)
 
Habe das Spiel samt Swing Oberfläche in Java geschrieben.

Es gibt zwei Modi:
Human vs. Human und
Human vs. Bot

Außerdem gibt es wie vorgeschlagen die Schwierigkeiten Easy und Hard. Man hat die Möglichkeit, selbst zu beginnen, oder kann den Bot beginnen lassen.

Unter Hard verwendet der Bot eine Modifikation des Mini-Max Algorithmus (wie von Phi vorgeschlagen). Somit ist der Bot unbesiegbar.

Lässt man den Bot beginnen und spielt nicht optimal (1. Zug in die Mitte), wird man geschlagen - der Bot wählt stets den optimalen Zug.

Probiert es mal aus;)


Gruß, SmolkaJ
 
Nochmal aufgewärmt...

Das Thema TicTacToe ist ja ein sehr beliebter Anfütterer bei Programmierlehrgängen. Ich bereite gerade einen neuen vor und bin dabei mächtig ins Basteln abgeglitten.

Eigentliches Ziel ist PHP. Angefüttert wird mit dem TicTacToe im Client/Server-Modus (also für mehrere Spieler und Beobachter) und Javascript-Freiheit. Es im vollen Umfang nachzubauen, ist nicht zwingend Ziel des Lehrgangs. Es soll vor allem das Interesse nach mehr wecken...

Tic Tac Toe

Jetzt meine Frage: Ich bin gerade dabei, online greifbare KI's per curl einzubauen, zuletzt die KI von "http://gomokuonline.com". Die ist aber nur für die Spielvariante "19x19 : 5" gedacht. Ich suche noch online-KI's, die für andere Fälle oder auch für den ganz allgemeinen Fall eines beliebig großen Spielfeldes n-in-einer-Reihe mit n = Element von (3..7) anwendbar sind.

Gibt's da Ideen?

Für Anregungen, auch unperfekte KI's (es geht ja bei diesem Beispiel vor allem darum, anhand der Bastelmöglichkeiten rund ums curl eine Anfütterung vorzunehmen, nicht um perfekte Spiele-KI's zu produzieren), wäre ich herzlich dankbar!

Für Perfektionisten: Die im allgemeinen zu habenden KI's (Minimax ohne großartige Stellungsbewertungen) sind nur für das ganz kleine Spiel "3x3:3" und eventuell bis 5x5:4 brauchbar, weiter aber nicht, weil ihre numerische Last zu schnell in die Höhe schießt. Es müßten schon spezielle Varianten sein, die krasse Beschneidungen des Entscheidungsspielraumes vornehmen. Die Version mit "thread space search" von olle L. Victor Allis ist mir zwar vom Prinzip der Herangehensweise verständlich, im Detail aber habe ich bisher nicht den Mut aufgebracht, mich dort für einen Nachbau durchzuwühlen. Auch da wäre ich für Anregungen dankbar.
 
Zuletzt bearbeitet:
Zurück
Oben