# TicTacToe Programmieren



## Sh00ckw4ve (3. Mrz 2014)

Hallo zusammen,
ich muss in Form einer Facharbeit (bis Dienstag  ) ein TicTacToe in Java programmieren, dass mit Hilfe des Minimax Algorithmus unbesiegbar wird. Ich habe das Spielfeld einfach mit 2 Arrays realisiert als JButton und die dann als GridLayout ausgegeben. 

```
JButton[][] knoepfe = new JButton[3][3];
```

Jetzt habe ich das Problem das ich bei den Berechnungen für den Minimax Algorithmus Integer brauche. Wie bekomme ich aus dem JButton am elegantesten Integer? Hier der präzise Fall:

```
public int bewertung(JButton[][] z)
    {
        int sum1=0, sum2=0;
        for (int i=0; i < 3; i++) {
            sum1  = z[i][0] + z[i][1] + z[i][2];  
            sum2 = z[0][i] + z[1][i] + z[2][i];
            if ((sum1 == -3)||(sum2 == -3))    
            {
                return -1;
            }
            else if ((sum1 == 3)||(sum2 == 3)) 
            {
                return  1; 
            }
        }  

        sum1  = z[0][0] + z[1][1] + z[2][2];
        sum2 = z[0][2] + z[1][1] + z[2][0];

        if ((sum1 == -3)||(sum2 == -3))    
        {
            return -1;
        }
        else if ((sum1 == 3)||(sum2 == 3))
        {
            return  1;
        }
        return 0;
    }
```

Mit freundlichen Grüßen und Danke im Vorraus,
Sh00ckw4ve


----------



## BRoll (3. Mrz 2014)

Dazu musst du halt wissen welches Zeichen welche Zahl bedeutet in deinen
JLabels. Wenn du jetzt zb die 2 Zeichen anlegst:

```
String[] symbols=new String[]{"O","X"};
```
Dann kannst über den Text des Buttons auf die ArrayID zurückschliessen:

```
String t=button.getText();
int number=0; //default fall feld leer = 0
for(int i=0; i<2; i++)
{
if(t.equals(symbols[i])
{
number=i+1;
break;
}
}
//jetzt steht number 0 für leeres Feld, number 1 für Spieler "O" und 2 für Spieler "X"
```
So hätte ich es jedenfalls gemacht.
Wobei du ja nicht über die JButtons gehen musst,
die reichen ja zur ausgabe und zum abfangen der eingabe.
Das eigentliche Integer 2d Array des Felds kannst du ja 
selber anlegen und dann verwalten entsprechend und damit
die Ausgabe anpassen (also den Button Text).


----------



## Sh00ckw4ve (3. Mrz 2014)

Ok, erstmal vielen Dank für die Hilfe, aber vielleicht sollte ich dazu sagen, dass ich ein ziemlicher Anfänger bin was Java angeht und nicht viel von deiner Lösung verstanden hab  

Daher jetzt nochmal die Frage etwas allgemeiner, wäre jemand so nett und würde mir nen Tipp geben wie ich das Problem löse, sodass diese TicTacToe Anwendung funktioniert? Das Problem ist eigentlich "nur" das ich für die Berechnung Integer benötige, aber trotzdem die Buttons nutzen möchte.


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TicTacToe extends JFrame implements ActionListener
{
    JButton[][] knoepfe = new JButton[3][3];
    JLabel titel = new JLabel("Tic Tac Toe");
    JButton startKnopf = new JButton("Start");
    JPanel feldP = new JPanel();
    JPanel startPanel = new JPanel();
    JLabel platzhalter = new JLabel(" ");
    int aktiverSpieler;
    int züge;
    int besterZug;
    int besetzt;

    public TicTacToe()
    {
        super("Tic Tac Toe");
        init();
        this.setSize(380,380);
        this.setVisible(true);
        aktiverSpieler = 1; //X = 1 || O = -1 
        züge = 0;
        besterZug = 0;
    }

    public void init()
    {
        this.setLayout(new BorderLayout());
        this.add(titel, BorderLayout.PAGE_START);
        this.add(feldP, BorderLayout.CENTER);
        this.add(startPanel, BorderLayout.PAGE_END);

        titel.setHorizontalAlignment(SwingConstants.CENTER);
        titel.setFont(titel.getFont().deriveFont(20f));

        startPanel.setLayout(new BorderLayout());
        startPanel.add(platzhalter, BorderLayout.CENTER);
        startPanel.add(startKnopf, BorderLayout.PAGE_END);
        startKnopf.addActionListener(this);

        feldP.setLayout(new GridLayout(3,3));
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                knoepfe[i][j] = new JButton(" ");
                feldP.add(knoepfe[i][j]);
                knoepfe[i][j].addActionListener(this);
            }
        }
    }

    public void actionPerformed(ActionEvent ae)
    {
        Object gedrückterKnopf;
        String inhalt = ae.getActionCommand();
        gedrückterKnopf = ae.getSource();
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if (gedrückterKnopf==knoepfe[i][j])
                {
                    if (inhalt==" ")
                    {
                        knoepfe[i][j].setText("X");
                        aktiverSpieler=0;
                    }
                    else
                        JOptionPane.showMessageDialog(null,"Feld ist bereits belegt");
                }
            }
        }
    }

    public boolean spielZuEnde()
    {
        if ((bewertung(knoepfe)!=0) || (besetzteFelder(knoepfe)==9))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public int besetzteFelder(int[][] z)
    {
        besetzt = 0;
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if (z[i][j]!=0)
                {
                    besetzt++;
                }
            }
        }
        return besetzt;
    }

    public int bewertung(int[][] z)
    {
        int sum1=0, sum2=0;
        for (int i=0; i < 3; i++) {
            sum1  = z[i][0] + z[i][1] + z[i][2];  
            sum2 = z[0][i] + z[1][i] + z[2][i];
            if ((sum1 == -3)||(sum2 == -3))    
            {
                return -1;
            }
            else if ((sum1 == 3)||(sum2 == 3)) 
            {
                return  1; 
            }
        }  

        sum1  = z[0][0] + z[1][1] + z[2][2];
        sum2 = z[0][2] + z[1][1] + z[2][0];

        if ((sum1 == -3)||(sum2 == -3))    
        {
            return -1;
        }
        else if ((sum1 == 3)||(sum2 == 3))
        {
            return  1;
        }
        return 0;
    }

    public int minimaxX(int[][] z, int tiefe)
    { 
        int bew = bewertung(z);
        if (bew != 0)
        {
            return bew;
        }
        if (besetzteFelder(z)==9)
        {
            return 0;		 
        }
        int max = -5;
        int[] gezogen = bewegungen(z);

        for (int i=0; i<gezogen.length; i++) 
        {         
            z[gezogen[i]/10][gezogen[i]%10] = 1;      
            int wert = minimaxO(z, tiefe+1);
            if (wert > max) 
            {
                max = wert;
                if (tiefe==züge)
                    besterZug = gezogen[i];        
            }                     
            z[gezogen[i]/10][gezogen[i]%10] = 0; 
        }      
        return max;
    }

    public int minimaxO(int[][] z, int tiefe)
    {   
        int bew = bewertung(z);
        if (bew != 0)
        {
            return bew;
        }
        if (besetzteFelder(z)==9)
        {    
            return 0;   
        }
        int min = 5;
        int[] gezogen = bewegungen(z);

        for (int i=0; i<gezogen.length; i++) 
        {         
            z[gezogen[i]/10][gezogen[i]%10] = -1;  
            int wert = minimaxX(z, tiefe+1);
            if (wert < min) 
            {
                min = wert;
                if (tiefe==züge)
                    besterZug = gezogen[i];         
            }                     
            z[gezogen[i]/10][gezogen[i]%10] = 0;  
        }	  	 
        return min;
    }

    private int[] bewegungen(int[][] z)
    {
        int[] gezogen = new int[9-besetzteFelder(z)];  // wieviele Züge gibt es?
        int anzahlZüge = 0;
        for (int i=0; i < 3; i++)
        {
            for (int j=0; j < 3; j++)
            {
                if (z[i][j]==0)
                {
                    gezogen[anzahlZüge++] = i*10+j;
                } 
            }
        }                      
        return gezogen;
    }
}
```


----------



## JavaMeister (3. Mrz 2014)

Kannst du dir eine fertige Lösung einfach ergoogeln und hier dazu Fragen stellen?

Die naive implementierung ist ja hier nicht zielführend vor allem in Bezig auf min max.


----------



## Gucky (3. Mrz 2014)

Ich kenne minimax nicht aber habe ich das richtig verstanden, dass du das Spielfeld mit seinen Zuständen in Integers ausdrücken musst?
Gib jedem Button einen Eintrag in einem zweiten int Array (bei 9 Buttons geht das noch ohne schlauen Algorithmus) und bei einem Klick auf diesen Button vom Nutzer wird der Eintrag in dem Array auf 1 gesetzt und der Button wird mit setEnabled(false) unbenutzbar gemacht. Setzt der minimax eine Markierung, so wird der entsprechende Eintrag auf 2 gesetzt und ebenfalls der Button (welcher praktischerweise denselben Index hat) unbenutzbar gemacht.
Bei einem Klick auf einen retry Button wird das Spielfeld neu aufgebaut.

PS: ich weiß nicht genau, ob es setEnabled() war. Ist es das nicht, musst du einfach mal in der API Dokumentation nach dem JButton suchen.


----------

