package name.panitz.ludens.strategy;
import java.util.*;
import name.panitz.ludens.util.Pair;

class Othello extends AbstractRegularGame<OthelloMove>{

  Othello(){
    super((byte)8,(byte)8);
    b[3][3]=getPlayerOne();
    b[4][4]=getPlayerOne();
    b[3][4]=getPlayerTwo();
    b[4][3]=getPlayerTwo();
    movesDone=4;
  }

  public boolean noMoreMove(){return movesDone==64;}

  public boolean wins(byte player){
    return noMoreMove()&&evalState(player)>32;}

  public boolean ended(){ return noMoreMove();}

  public int evalState(byte player){
    int result=0;
    for (byte trs=0;trs<columns;trs++)
     for (byte pos=0;pos<rows;pos++)
       if(b[trs][pos]==player) result=result+1;;
    return result;
  }

  List<Pair<Byte,Byte>> toTurn(Pair<Byte,Byte> m){
    final List<Pair<Byte,Byte>> result
      = new LinkedList<Pair<Byte,Byte>>();

    if (m.fst+2<columns){
      if (b[m.fst+1][m.snd]==nextPlayer()){
        byte i=(byte)(m.fst+2);
        while (i<columns&&b[i][m.snd]!=NONE&&b[i][m.snd]!=player)
          i++;
        if (i<columns && b[i][m.snd]==player){
          for (i=(byte)(i-1);i>m.fst;i--) 
            result.add(new Pair<Byte,Byte>(i,m.snd));
        }
      }
    }
    if (m.fst-2>= 0){
      if (b[m.fst-1][m.snd]==nextPlayer()){
        byte i=(byte)(m.fst-2);
        while (i>=0 &&b [i][m.snd]!=NONE&&b[i][m.snd]!=player)
           i--;
        if (i>=0 && b[i][m.snd]==player){
          for (i=(byte)(i+1);i<m.fst;i++) result
            .add(new Pair<Byte,Byte>(i,m.snd));
        }
      }
    }
    if (m.snd+2<rows){
      if (b[m.fst][m.snd+1]==nextPlayer()){
        byte i=(byte)(m.snd+2);
        while (i<rows&&b[m.fst][i]!=NONE&&b[m.fst][i]!=player) i++;
        if (i<rows && b[m.fst][i]==player){
          for (i=(byte)(i-1);i>m.snd;i--) 
            result.add(new Pair<Byte,Byte>(m.fst,i));
        }
      }
    }
    if (m.snd-2>= 0){
      if (b[m.fst][m.snd-1]==nextPlayer()){
        byte i=(byte)(m.snd-2);
        while (i>=0 &&b[m.fst][i]!=NONE&&b[m.fst][i]!=player) 
          i--;
        if (i>=0 && b[m.fst][i]==player){
          for (i=(byte)(i+1);i<m.snd;i++) 
            result.add(new Pair<Byte,Byte>(m.fst,i));
        }
      }
    }

    if (m.fst+2<columns&&m.snd+2<rows){
      if (b[m.fst+1][m.snd+1]==nextPlayer()){
        byte i=(byte)2;
        while (  m.fst+i<columns
              && m.snd+i<rows
              && b[m.fst+i][m.snd+i]!=NONE
              && b[m.fst+i][m.snd+i]!=player) i++;

        if (   m.fst+i<columns 
            && m.snd+i<rows 
            && b[m.fst+i][m.snd+i]==player){
          for (i=(byte)(i-1);i>0;i--) 
            result.add(new Pair<Byte,Byte>
                         ((byte)(m.fst+i),(byte)(m.snd+i)));
        }
      }
    }

    if (m.fst-2>=0&&m.snd-2>=0){
      if (b[m.fst-1][m.snd-1]==nextPlayer()){
        byte i=(byte)2;
        while (   m.fst-i>=0
               && m.snd-i>=0
               &&b[m.fst-i][m.snd-i]!=NONE
               &&b[m.fst-i][m.snd-i]!=player) i++;
        if (   m.fst-i>=0 
            && m.snd-i>=0 
            && b[m.fst-i][m.snd-i]==player){
          for (i=(byte)(i-1);i>0;i--) 
            result.add(new Pair<Byte,Byte>
                        ((byte)(m.fst-i),(byte)(m.snd-i)));
        }
      }
    }

    if (m.fst+2<columns&&m.snd-2>=0){
      if (b[m.fst+1][m.snd-1]==nextPlayer()){
        byte i=(byte)2;
        while (   m.fst+i<columns
               && m.snd-i>=0
               && b[m.fst+i][m.snd-i]!=NONE
               && b[m.fst+i][m.snd-i]!=player) i++;

        if (   m.fst+i<columns 
            && m.snd-i>=0 
            && b[m.fst+i][m.snd-i]==player){
          for (i=(byte)(i-1);i>0;i--) 
            result.add(new Pair<Byte,Byte>
                           ((byte)(m.fst+i),(byte)(m.snd-i)));
        }
      }
    }
    if (m.fst-2>=0&&m.snd+2<rows){
      if (b[m.fst-1][m.snd+1]==nextPlayer()){
        byte i=(byte)2;
        while (   m.fst-i>=0
               && m.snd+i<rows
               && b[m.fst-i][m.snd+i]!=NONE
               && b[m.fst-i][m.snd+i]!=player) i++;
        if (   m.fst-i>=0 
            && m.snd+i<rows 
            && b[m.fst-i][m.snd+i]==player){
          for (i=(byte)(i-1);i>0;i--) 
            result.add(new Pair<Byte,Byte>
                             ((byte)(m.fst-i),(byte)(m.snd+i)));
        }
      }
    }

    return result;
  }

  public Othello doMove(Pair<Byte,Byte> m){
    if (b[m.fst][m.snd]==NONE){
      final List<Pair<Byte,Byte>> turn = toTurn(m);
      if (!turn.isEmpty()) 
        return doMove(new OthelloMove(m,turn));
    }
    return this;
  }

  public Othello doMove(OthelloMove om){
    final Pair<Byte,Byte> m = om.mv;
    final Othello result= (Othello)clone();
    result.player=nextPlayer();
    if (om instanceof NoMove) return result;

    result.b[m.fst][m.snd]=player;
    for (Pair<Byte,Byte>t:om.turn)
      result.b[t.fst][t.snd]=player;

    result.movesDone=this.movesDone+1;
    return result;
  }

  public Othello setAtPosition(byte column,byte row){
    return doMove(new Pair<Byte,Byte>(column,row));
  }

  public List<OthelloMove> moves(){
    final List<OthelloMove> result
      = new LinkedList<OthelloMove>();
    for (byte trs=0;trs<columns;trs++)
      for (byte pos=0;pos<rows;pos++){
        final Pair<Byte,Byte> m
          = new Pair<Byte,Byte>(trs,pos);
        if (b[trs][pos]==NONE){
          final List<Pair<Byte,Byte>> turn = toTurn(m);
          if (!turn.isEmpty()) 
            result.add(new OthelloMove(m,turn));
        }
      }
    if (result.isEmpty()) result.add(new NoMove());
    return result;
  }
}

