# [JAVA] Problem bei Othello/Reversi



## KamiSachiko (31. Dezember 2012)

Hallo,

ich muss für ein Praktikum das Spiel Othello/Reversi in Java programmieren.
Bin im Grunde damit fertig, bis auf ein Problem, an dem ich schon seit Tagen verzweifelt sitze.
Mein Gegenspieler (KI) soll ein Feld mit dem besten score wählen, wählt aber entweder ein Feld, welches schon besetzt ist oder eins, was für ihn gar nicht erlaubt ist zu setzen (und somit wird sein Zug übersprungen). Ich habe in der Datenstruktur das ganze eigentlich abgeklärt, es scheint aber nicht zu funktionieren.
Ich vermute den Fehler in der "Check"-Methode

OthelloKI

```
package othello;
import java.util.*;
 
import szte.mi.Move;
import szte.mi.Player;
 
public class OthelloKI implements Player{
    private OthelloDatenstruktur data;
    private int order;
    private Random rnd;
    private Status me;
    private Status opp;
    private LinkedList<Move> posMoves;
    private HashMap<Move, Integer> possibleMoves;
    int [] counter = new int[2];
    static final int squareScores[][] = new int[][]
    {{50, -1, 5, 2, 2, 5, -1, 50},
    {-1, -10, 1, 1, 1, 1, -10, -1},
    {5, 1, 1, 1, 1, 1, 1, 5},
    {2, 1, 1, 0, 0, 1, 1, 2},
    {2, 1, 1, 0, 0, 1, 1, 2},
    {5, 1, 1, 1, 1, 1, 1, 5},
    {-1, -10, 1, 1, 1, 1, -10, -1},
    {50, -1, 5, 2, 2, 5, -1, 50}};
 
    @Override
    public void init( int order, long t, Random rnd ) {
        
        this.data = new OthelloDatenstruktur();
        this.order = order;
        this.rnd = rnd;
        this.posMoves = new LinkedList<Move>();
        this.possibleMoves = new HashMap<Move, Integer>();
        
        if(this.order==0){
            
            me=Status.black;
            opp=Status.white;
        }
        else if(this.order==1){
            me=Status.white;
            opp=Status.black;
        }
        else throw new IllegalArgumentException();
        data.setRandom(this.rnd);
    }
     
 
    @Override
    public Move nextMove(Move prevMove, long tOpponent, long t ) {
              data.move(prevMove, opp);
        fillPosMoves();
        
        Move bestMove = null;
        int bestMoveScore = -1000;
        for (Map.Entry<Move, Integer> entry : possibleMoves.entrySet()) {
            if (entry.getValue() > bestMoveScore) {
                bestMove = entry.getKey();
                bestMoveScore = entry.getValue();
            }
        }
        System.out.println("Best: " + bestMove.x + "," + bestMove.y + " score: " + bestMoveScore);
        return bestMove;
    }
 
   private void fillPosMoves(){
        for(int i=0; i<8; i++)
            for(int j=0; j<8; j++)
                if(data.isValid(new Move(i,j), me))
                {
                    this.posMoves.add(new Move(i,j));
                    this.possibleMoves.put(new Move(i,j), squareScores[i][j]);
                }
    }
 
}
```

OthelloDatenstruktur

```
package othello;
import szte.mi.*;
 
import java.util.*;
 
enum Status {nil ,black , white}; 
 
public class OthelloDatenstruktur {
    Status [][] board = new Status[8][8];
    int [] counter = new int[2]; // 0 = schwarz, 1 = weiß
    boolean PassCounter;
    Random rnd;
 
    public OthelloDatenstruktur() {
        clear();
    }
 
    public Status get(int x, int y) {
        return board[x][y];
    }
 
    public void set(Move move, Status player) {
        switch (board[move.x][move.y]) {
            case white:  counter[1]--; break;
            case black:  counter[0]--; break;
        }
        board[move.x][move.y]=player;
        switch (player) {
            case white:  counter[1]++; break;
            case black:  counter[0]++; break;
        }
    }
    
    public void setRandom(Random rnd){
        this.rnd = rnd;
    }
 
    public int getCounter(Status player) {
        return counter[player.ordinal()-1];
    }
 
    public void clear() {
        for (int i = 0 ; i < 8 ; i++)
            for (int j = 0 ; j < 8 ; j++)
                board[i][j]=Status.nil;
        board[3][4]=Status.black;
        board[4][3]=Status.black;
        board[3][3]=Status.white;
        board[4][4]=Status.white;
        counter[0] = 2;
        counter[1] = 2;
        PassCounter = false;
    }
 
    public void println() {
        System.out.print("[");
        for (int i = 0 ; i < 8 ; i++) {
            for (int j = 0 ; j < 8 ; j++)
                System.out.print(board[i][j]+",");
            System.out.println((i == 7? "]":""));
            }
    }
 
    public int move(Move move, Status stat) {
        return checkBoard(move,stat);
    }
    
 
    public boolean gameEnd() {
        return counter[0]+counter[1]==64;
    }
 
    private int Check(Move move, int incx, int incy, Status stat , boolean set)  {
        Status opponent;
        int x=move.x;
        int y=move.y;
        if (stat == Status.black) opponent=Status.white; else opponent=Status.black;
        int n_inc=0;
        
        if (board[x][y] != Status.nil) {
            return 0;
        }
        if (board[x][y] == board[3][4] || board[x][y] == board[4][3] || board[x][y] == board[3][3] || board[x][y] == board[4][4]){
            return 0;
        }
            
        x+=incx; y+=incy;
 
        while ((x<8) && (x>=0) && (y<8) && (y>=0) && (board[x][y]==opponent)) {
            x+=incx; y+=incy;
            n_inc++;
        }
        if ((n_inc != 0) && (x<8) && (x>=0) && (y<8) && (y>=0) && (board[x][y]==stat)) {
             if (set)
                for (int j = 1 ; j <= n_inc ; j++) {
                x-=incx; y-=incy;
                 set(new Move(x,y),stat);
             }
            return n_inc;
        }
        else return 0;
    }
 
    public int checkBoard(Move move, Status stat) {
    
        int y=Check(move,1,0,stat,true);
        
        y+=Check(move,-1,0,stat,true);
        
        y+=Check(move,0,1,stat,true);
        
        y+=Check(move,0,-1,stat,true);
        
        y+=Check(move,1,1,stat,true);
        y+=Check(move,-1,1,stat,true);
        y+=Check(move,1,-1,stat,true);
        y+=Check(move,-1,-1,stat,true);
        if (y != 0) set(move,stat);
        return y;
    }
 
    public boolean isValid(Move move, Status stat) {
        
        if (Check(move,1,0,stat,false) != 0) return true;
        
        if (Check(move,-1,0,stat,false) != 0) return true;
        
        if (Check(move,0,1,stat,false) != 0) return true;
        
        if (Check(move,0,-1,stat,false) != 0) return true;
         
        if (Check(move,1,1,stat,false) != 0) return true;
        if (Check(move,-1,1,stat,false) != 0) return true;
        if (Check(move,1,-1,stat,false) != 0) return true;
        if (Check(move,-1,-1,stat,false) != 0) return true;
        return false;
    }
    public boolean userCanMove(Status player)  {
        for (int i = 0 ; i < 8 ; i++)
            for (int j = 0 ; j < 8 ; j++)
              if ((board[i][j] == Status.nil) && isValid(new Move(i,j),player)) return true;
        return false;
        }
    
}
```

Vielen lieben Dank für jede Hilfe.


----------



## fadade (1. Januar 2013)

also ich weiß zwar nicht wie das Spiel geht und kenne die Regeln nicht  (habe sie mir jetzt auch nicht belesen^^) aber das Prinzip was du machst  ist mir wenigstens klar.
Tipp vorneweg: *Kommentare *
Zumindest ganz kurz und an einige Variablen deren Sinn nicht ganz klar ist/zu sein scheint (bspw. _n_inc_ in der Methode _Check_)

Darüber hinaus fehlt mir irgendwo so eine Main/Update-Methode ... einfach wo z.B. folgendes getan wird:


Spiel beendet?
Player/KI dran?
warten bis Player gesetzt hat / KI Zug --> guggn was geht und ggf. bestes auswählen
goto 1)


Was passiert in der Check-Methode eigentlich bei folgender Stelle:

```
... if ((n_inc != 0) && (x<8) && (x>=0)  && (y<8) && (y>=0) &&  [B](board[x][y]==stat)[/B])  ...
```
Soweit richtig schaust du dort  doch nur, ob dein n_inc geändert wurde, also wahrscheinlich irgendein  Feld verfügbar ist, der Zug innerhalb bestimmter Grenzen ist und ....  letzter Teil?
Dein Problem klingt jedenfalls schonmal so, als würde irgendwo was vertauscht sein, wenn eben auf Felder gesetzt wird, wo eigentlich nicht erlaubt.


----------



## Defenz0r (1. Januar 2013)

fadade schrieb:


> [*]goto 1)



goto ist jetzt wirklich nur eine Übergangsmaßnahme, das würde ich mir nicht angewöhnen gg*
Wenn das alles loopen soll, besser ne *do*-*while*  oder eine While Schleife.
Ich würde dir empfehlen einen boolean zu erstellen, wenn Spieler 1 gezogen hat, ist er z.B *false* und wenn Spieler 2 gezogen hat isser wieder *true*.
if(deinBoolean == false) 
{ // mach was
}
else { // blub
}

Oder je nach deinem Stil, die if Abfragen an dem richtigen Ort innerhalb einer while - do while Schleife Platzieren


Gruß


----------



## fadade (2. Januar 2013)

Ja das mit goto war nicht so gemeint, ich weiß gar nicht, ob das in Java überhaupt geht .. sollte eher die "Hauptschleife" verdeutlichen, also Vorgänge, die immer wiederholt bei einem Zug ausgeführt werden.

Die Ästhetik des Codes ist natürlich auch noch weitreichender überarbeitbar 
Aber je nach Alter/Können sollte man sich erstmal darauf konzentrieren die Logische Komponente zum Laufen zu bringen. Und da wird wie gesagt vermutlich irgendwo einfach nur ein Dreher sein. Natürlich könnte hier eine Umstrukturierung auf 

```
if (bool_KI_Spieler_dran == true) { .... }
else { ... } //Spieler dran
```

vielleicht auch etwas helfen den Überblick zu bewahren und in den Check-Methoden die Felder auf die richtige Eigenschaft zu prüfen.


----------

