/*
 * Playground+ - ttt.c
 * TicTacToe game written by Bron Gondwana
 *
 * The Mind Of The Machine 1.3 by Urmas Rosenberg (aka Sassist)
 *   Contact : uraes@ut.ee
 * ---------------------------------------------------------------------------
 *
 *  Changes made:
 *    - Modifications to presentation
 *    - Changed to compile cleanly under PG+ flags
 *    - Added 'ttt computer'
 */

/* headers */

#include <stdlib.h>
#include <string.h>

#include "include/config.h"
#include "include/player.h"
#include "include/proto.h"


/* interns */
void ttt_end_game(player * p, int winner);
void computer_move(player *p);

//comment this, if you wanna make Machine to be no so smart
#define SMART 1

/* the game!! */

int ttt_is_end(player * p)
{
  int i, board[9], draw = 1;

  for (i = 0; i < 9; i++)
  {
    board[i] = (p->ttt_board >> (i * 2)) % 4;
    if (!(board[i]))
      draw = 0;
  }

  if ((board[0] && ((board[0] == board[1]) && (board[0] == board[2]))) ||
      (((board[0] == board[3]) && (board[0] == board[6]))))
    return board[0];
  if ((board[4] && ((board[4] == board[0]) && (board[4] == board[8]))) ||
      (((board[4] == board[1]) && (board[4] == board[7]))) ||
      (((board[4] == board[2]) && (board[4] == board[6]))) ||
      (((board[4] == board[3]) && (board[4] == board[5]))))
    return board[4];
  if ((board[8] && ((board[8] == board[2]) && (board[8] == board[5]))) ||
      (((board[8] == board[7]) && (board[8] == board[6]))))
    return board[8];
  if (draw)
    return 3;

  return 0;
}

void ttt_print_board(player * p)
{
  int i, temp, gameover = 0;
  char *oldstack, cells[9];

  oldstack = stack;
if (!p->against_computer){
  if (!(p->ttt_opponent))
  {
    TELLPLAYER(p, " TTT: EEEK.. seems we've lost your opponent!\n");
    return;
  }
  if (((p->ttt_board) % (1 << 17)) != ((p->ttt_opponent->ttt_board) % (1 << 17)))
  {
    TELLPLAYER(p, " TTT: EEEK.. seems like you're playing on different boards!\n");
    ttt_end_game(p, 0);
    return;
  }
}//end of against computer

  for (i = 0; i < 9; i++)
  {
    temp = ((p->ttt_board) >> (i * 2)) % 4;
    switch (temp)
    {
      case 0:
    cells[i] = ' ';
    break;
      case 1:
    cells[i] = 'O';
    break;
      case 2:
    cells[i] = 'X';
    break;
      default:
    TELLPLAYER(p, " TTT: EEEK.. corrupt board file!!\n");
    return;
    }
  }

if (!p->against_computer){
  if (p->ttt_board & TTT_MY_MOVE)
    ADDSTACK(" It's your move - with the board as:\n\n");
  else if (p->ttt_opponent->ttt_board & TTT_MY_MOVE)
    ADDSTACK(" %s to move - with the board as:\n\n", p->ttt_opponent->name);
  else
  {
    ADDSTACK(" The final board was:\n");
    gameover++;
  }
} else //end of against_computer
  if (p->ttt_board & TTT_MY_MOVE)
    ADDSTACK(" It's your move - with the board as:\n\n");
  else
  {
    ADDSTACK(" The final board was:\n");
    gameover++;
  }

  ADDSTACK("  +-------+  +-------+\n");
  for (i = 0; i < 9; i += 3)
  {
    ADDSTACK("  | %c %c %c |  | %d %d %d |\n",
         cells[i], cells[i + 1], cells[i + 2], i + 1, i + 2, i + 3);
  }
  ADDSTACK("  +-------+  +-------+\n");
  if (!gameover)
  {
    if (p->ttt_board & TTT_AM_NOUGHT)
    {
      ADDSTACK("  You are playing NOUGHTS\n");
    }
    else
    {
      ADDSTACK("  You are playing CROSSES\n");
    }
  }
  stack++;

  TELLPLAYER(p, oldstack);
  stack = oldstack;

}

void ttt_end_game(player * p, int winner)
{
  int plyr = 1;
  if ((!(p->ttt_opponent)) && (!p->against_computer))
  {
    TELLPLAYER(p, " TTT: EEEK.. seems we've lost your opponent!\n");
    return;
  }
  if (!(p->ttt_board & TTT_AM_NOUGHT))
    plyr++;

tell_player(p,"END\n");

if (!p->against_computer)
{
  if (winner == 3)
  {
    TELLPLAYER(p, " Your TTT game with %s is a draw.\n", p->ttt_opponent->name);
    TELLPLAYER(p->ttt_opponent, " Your TTT game with %s is a draw.\n", p->name);
    p->ttt_draw++;
    (p->ttt_opponent)->ttt_draw++;
  }
  else if (winner && (winner != plyr))
  {
    TELLPLAYER(p, " Doh!! You lost TTT to %s.\n", p->ttt_opponent->name);
    TELLPLAYER(p->ttt_opponent, " Yippee!! You beat %s at TTT.\n", p->name);
    p->ttt_loose++;
    (p->ttt_opponent)->ttt_win++;
  }
  else if (winner)
  {
    TELLPLAYER(p, " Yippee!! You beat %s at TTT.\n", p->ttt_opponent->name);
    TELLPLAYER(p->ttt_opponent, " Doh!! you lost TTT to %s.\n", p->name);
    p->ttt_win++;
    (p->ttt_opponent)->ttt_loose++;
  }
  else
  {
    TELLPLAYER(p, " You abort your TTT game against %s.\n", p->ttt_opponent->name);
    TELLPLAYER(p->ttt_opponent, " %s aborts your TTT game.\n", p->name);
  }
}
else //if against_computer
{
  if (winner == 3)
  {
    tell_player(p, " Your TTT game against computer is a draw.\n");
    p->ttt_draw++;
  }
  else if (winner && (winner != plyr))
  {
    tell_player(p, " Doh!! You lost TTT to computer.\n");
    p->ttt_loose++;
  }
  else if (winner)
  {
    tell_player(p, " Yippee!! You beat The Mind Of The Machine at TTT.\n");
    p->ttt_win++;
  }
  else
  {
    tell_player(p, " You abort your TTT game against computer.\n");
  }
}//end of against_computer

  p->ttt_board &= ~TTT_MY_MOVE;

  if (!p->against_computer)
      p->ttt_opponent->ttt_board &= ~TTT_MY_MOVE;

  ttt_print_board(p);
  if (!p->against_computer)
      ttt_print_board(p->ttt_opponent);

  if (!p->against_computer){
      p->ttt_opponent->ttt_opponent = 0;
      p->ttt_opponent = 0;
  }
  if (p->against_computer)
      p->against_computer=0;
}

void ttt_new_game(player * p, char *str)
{
  player *p2;

  if (!*str)
  {
    TELLPLAYER(p, " Format:  ttt <player | computer>\n");
    TELLPLAYER(p, "          ttt <commands>\n");
    return;
  }

/*Here starts The Mind Of The Machine*/
  if (!strcmp(str , "computer")){
      tell_player(p," You started TTT against The Mind Of The Machine\n");
      p->against_computer=1;
      p->ttt_board = 0;
      p->ttt_board = TTT_MY_MOVE + TTT_AM_NOUGHT;
      computer_move(p);
      ttt_print_board(p);
      return;
  }

  p2 = find_player_global(str);
  if (!p2)
    return;

#ifdef ROBOTS
  if (p2->residency & ROBOT_PRIV)
  {
    tell_player(p, " You cannot play TTT against a robot\n");
    return;
  }
#endif

  if (p == p2)
  {
    TELLPLAYER(p, " Do you have NO life???  Sheesh - Forget it...\n");
    return;
  }

  if ((p2->ttt_opponent) || (p2->against_computer))
  {
    TELLPLAYER(p, " Sorry, but %s is currently playing someone else\n", p2->name);
    return;
  }

  if (!p2->residency)
  {
    TELLPLAYER(p, " You can't play %s, because %s is not resident\n", p2->name, gstring(p2));
    return;
  }

  p->ttt_board = 0;
  p2->ttt_board = TTT_MY_MOVE + TTT_AM_NOUGHT;
  p->ttt_opponent = p2;
  p2->ttt_opponent = p;

  TELLPLAYER(p2, " %s has offered a game of Tic Tac Toe (\"ttt abort\" to cancel)\n", p->name);
  ttt_print_board(p2);
  ttt_print_board(p);
}

void ttt_make_move(player * p, char *str)
{
  int winner, temp;

  if (!*str)
  {
    TELLPLAYER(p, " You're playing a game, so\n Format:  ttt <square to play>\n"
           " Type \"aborttt\" to abort this game\n");
    return;
  }
if(!p->against_computer){
  if (((p->ttt_board) % (1 << 17)) != ((p->ttt_opponent->ttt_board) % (1 << 17)))
  {
    TELLPLAYER(p, " Seems you're playing on different boards!");
    ttt_end_game(p, 0);
  }
}//end of against_computer

  temp = atoi(str);

  if ((temp < 1) || (temp > 9))
  {
    TELLPLAYER(p, " Please play to a square on the board!!\n");
    ttt_print_board(p);
    return;
  }
  temp--;
  temp *= 2;

  if (p->ttt_board & (3 << temp))
  {
    TELLPLAYER(p, " Sorry, that square is already taken.. please choose another\n");
    ttt_print_board(p);
    return;
  }
  if (p->ttt_board & TTT_AM_NOUGHT)
  {
    p->ttt_board |= (1 << temp);
    if (!p->against_computer)
    p->ttt_opponent->ttt_board |= (1 << temp);
  }
  else
  {
    p->ttt_board |= (2 << temp);
    if(!p->against_computer)
    p->ttt_opponent->ttt_board |= (2 << temp);
  }

if (!p->against_computer){
  p->ttt_board &= ~TTT_MY_MOVE;
  p->ttt_opponent->ttt_board |= TTT_MY_MOVE;
}//end of against_computer

  winner = ttt_is_end(p);
  if (winner)
  {
    ttt_end_game(p, winner);
  }
  else
  {
    if(p->against_computer){
    computer_move(p);
      winner = ttt_is_end(p);
      if (winner)
      {
        ttt_end_game(p, winner);
        return;
      }
    }
    ttt_print_board(p);
    if(!p->against_computer)
    ttt_print_board(p->ttt_opponent);
  }
}



/*****************************************************
 *  The Mind Of The Machine (which should be better) *
 *                                                   *
 *****************************************************/

int can_we_win(player *p, int xx, int oo){
  int i,j,k,board[3][3],board2[9];
  int x,o,buttons=0;

  for (i = 0; i < 9; i++)
    board2[i] = (p->ttt_board >> (i * 2)) % 4;

  for (j = 0; j < 3; j++)
    for (i = 0; i < 3; i++)
    board[j][i] = board2[j*3+i];

/*1.2 (19072000)*/
  for (j = 0; j < 3; j++)
    for (i = 0; i < 3; i++)
    if ((board[j][i] == 1)||(board[j][i] == 2))
         buttons++;
  //If on the board is 2 buttons...
  if (buttons==2){

//if both buttons are at the top of same diagonal
    if ((board[0][0]==1 && board[2][2]==2)||
        (board[0][2]==1 && board[2][0]==2)||
        (board[2][2]==1 && board[0][0]==2)||
        (board[2][0]==1 && board[0][2]==2)||

//if they are at the top of same line
        (board[0][0]==1 && board[0][2]==2)||
        (board[0][2]==1 && board[2][2]==2)||
        (board[2][2]==1 && board[2][0]==2)||
        (board[2][0]==1 && board[0][0]==2)
       )

        return 5; //Yea! That's cool:)
    }

/*
Now.. do we have two crosses on the line so that the 3rd place is
emty? If we have than let computer win that game
*/

/*Horizontal check*/
  x=o=0;
  for (j = 0; j < 3; j++){
    for (i = 0; i < 3; i++){
    if (board[j][i] == 1) o++;
    if (board[j][i] == 2) x++;
    }
  if ((x==xx) && (o==oo))
      {for(k=0;k<3;k++){
          if (board[j][k]!=1 && board[j][k]!=2 && board[j][k]!=0){
          tell_player(p,"There is some problem with board\n");
          return -1;
          }
          if (board[j][k]==0){
          return j*3+k+1;
          }
      }
      }
  x=o=0;
  }

/*Vertical check*/
  x=o=0;
  for (i = 0; i < 3; i++){
    for (j = 0; j < 3; j++){
    if (board[j][i] == 1) o++;
    if (board[j][i] == 2) x++;
    }
  if ((x==xx) && (o==oo))
      {for(k=0;k<3;k++){
          if (board[k][i]!=1 && board[k][i]!=2 && board[k][i]!=0){
          tell_player(p,"There is some problem with board\n");
          return -1;
          }
          if (board[k][i]==0){
          return (k*3+i+1);
          }
      }
      }
  x=o=0;
  }

/*Diagonaal '\' */
  x=o=0;

  for (i = 0,j = 0; i < 3; i++,j++){
    if (board[j][i] == 1) o++;
    if (board[j][i] == 2) x++;
    }
  if ((x==xx) && (o==oo))
      {
    if (board[0][0]==0)return 1;
    if (board[1][1]==0)return 5;
    if (board[2][2]==0)return 9;
    tell_player(p,"There is an problem in mind of mashine(1)\n");
        return -1;
      }


/*Diagonaal '/' */
  x=o=0;
  for (i = 0,j = 2; i < 3; i++,j--){
    if (board[j][i] == 1) o++;
    if (board[j][i] == 2) x++;
        }
  if ((x==xx) && (o==oo))
      {
    if (board[0][2]==0)return 3;
    if (board[1][1]==0)return 5;
    if (board[2][0]==0)return 7;
    tell_player(p,"There is an problem in mind of mashine(2)\n");
        return -1;
      }


/*Hmm..*/

/* Special situations (ver 1.3)*/
/*
    That is the last point where computer could make a mistake and let users
    to win.
*/
#ifdef SMART
    if(buttons==2){
      if((board[0][1]==2 && board[2][2]==1)||
         (board[0][1]==2 && board[2][0]==1)||

         (board[2][1]==2 && board[0][0]==1)||
         (board[2][1]==2 && board[0][2]==1)||

         (board[1][0]==2 && board[0][2]==1)||
         (board[1][0]==2 && board[2][2]==1)||

         (board[1][2]==2 && board[0][0]==1)||
         (board[1][2]==2 && board[2][0]==1))return 5;

    }
#endif

return -2;
}

void computer_move(player *p){
  int temp,temp2=0,nowin=0,allright;
  allright=0;
  random();

    while (!allright){
      temp=(rand()%9)+1; /*Let's do random move*/
      temp--;
      temp *= 2;

       /*
         * NEXT STEP :
         * xx==2 && oo==0 This is where computer can win. On the line
         *    is two crosses and the third place is emty..
         *
         * xx==0 && oo==2 Oww. Player is near to win. Let's goin' to
         *  to be evil.. the third place is emty and we can't win...
         *
         * xx==1 && oo==0 We have one cross on the line and we can't
         *  win and player can't also so why must we choose square
         *  randomly without check maybe there is better square to
         *  choose.
         *
         */


      if (!nowin)
          if ((temp2=can_we_win(p,2,0))<0)
              if ((temp2=can_we_win(p,0,2))<0)
                  temp2=can_we_win(p,1,0);


      if (temp2 < 0)nowin = 1; /*Just incase*/
      if (!nowin)
        if (temp2>0){
      temp = temp2;
      temp--;
      temp *=2;
      }

          if (!(p->ttt_board & (3 << temp)))
          {
            p->ttt_board |= (2 << temp);
            allright=1;
          }

    }/*while allright*/
}

/* wrappers */

void ttt_print(player * p, char *str)
{
  if ((!p->ttt_opponent) && (!p->against_computer))
    TELLPLAYER(p, " But you aren't playing a game!");
  else
    ttt_print_board(p);
}

void ttt_abort(player * p, char *str)
{
  if ((!p->ttt_opponent) && (!p->against_computer))
    TELLPLAYER(p, " But you aren't playing a game!\n");
  else
    ttt_end_game(p, 0);
}

void ttt_ver(player *p){
tell_player(p,"\n -=> Tic Tac Toe by Bron Gondwana\n");
#ifdef SMART
   tell_player(p," -=> The Mind Of The Machine 1.3 (SMART)(08112001) by Urmas Rosenberg\n");
#else
   tell_player(p," -=> The Mind Of The Machine 1.3 (08112001) by Urmas Rosenberg\n");
#endif
}

void ttt_commands(player *p){
tell_player(p," Tic Tac Toe with T.M.O.T.M. - Commands\n");
tell_player(p,"    ttt <player | computer>\n"
          "    ttt version\n"
          "    ttt abort\n"
          "    ttt print\n"
          "    ttt [square]\n"
          "    ttt commands\n");
}

/* Yuk!!! This should be written as ttt <sub_command>!
   Oh well, some peoples programing style ... --Silver */

void ttt_cmd(player * p, char *str)
{
  if (!strcmp(str, "version"))
    ttt_ver(p);
  else if (!strcmp(str, "commands"))
    ttt_commands(p);
  else if ((!(p->ttt_opponent)) && (!p->against_computer))
    ttt_new_game(p, str);
  else if (!strcmp(str, "abort"))
    ttt_abort(p, "");
  else if (!strcmp(str, "print"))
    ttt_print(p, "");
  else if (p->ttt_board & TTT_MY_MOVE)
    ttt_make_move(p, str);
  else
  {
    TELLPLAYER(p, " Sorry, but %s gets to make the next move\n", p->ttt_opponent->name);
    ttt_print_board(p);
  }
}

/* Mind you I suppose it does have its advantages ... */