Logo Search packages:      
Sourcecode: yics version File versions  Download package

topcodes.c

/*
 * YICS: Connect a FICS interface to the Yahoo! Chess server.
 * Copyright (C) 2004  Chris Howie
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if defined(__GNUC__)
#include <sys/time.h>
#endif
#include "types.h"
#include "topcodes.h"
#include "network.h"
#include "sockets.h"
#include "console.h"
#include "globals.h"
#include "util.h"
#include "movecheck.h"
#include "vars.h"
#include "style.h"
#include "debug.h"
#include "formula.h"
#include "lists.h"

static bool makemove(Table *table, Move *move, bool noend);

static void top_inprogress(Table *, String *);  /* 0x30 */
static void top_message(Table *, String *);     /* 0x31 */
static void top_newhost(Table *, String *);     /* 0x35 */
static void top_startgamerequest(Table *, String *);  /* 0x39 */
static void top_gameover_resign(Table *, String *);   /* 0x5b */
static void top_moves(Table *, String *); /* 0x61 */
static void top_clear(Table *, String *); /* 0x62 */
static void top_kibitz(Table *, String *);      /* 0x63 */
static void top_clock(Table *, String *); /* 0x6c */
static void top_move(Table *, String *);  /* 0x6d */
static void top_gameover_flag(Table *, String *);     /* 0x69 */
static void top_promote(Table *, String *);     /* 0x70 */

TableOpcode topcodes[] = {
      {0x30,      top_inprogress},
      {0x31,      top_message},
      {0x35,      top_newhost},
      {0x39,      top_startgamerequest},
      {0x5b,      top_gameover_resign},
      {0x61,      top_moves},
      {0x62,      top_clear},
      {0x63,      top_kibitz},
      {0x64,      NULL},
      {0x6c,      top_clock},
      {0x6d,      top_move},
      {0x69,      top_gameover_flag},
      {0x70,      top_promote},
      {0x74,      NULL},
      {-1,  NULL},
};

void refresh(Table *table) {
      StyleHandler style;

      if ((table->number != primary) && variables[VAR_SINGLEBOARD].number)
            return;

      if (table->finished)
            return;

      style = getstyle(variables[VAR_STYLE].number);
      if (style == NULL)      /* This should never happen */
            return;

      (*style)(table);
}

static void gameover(Table *table, char *message) {
      refresh(table);
      printf("%s", message);
      //initGame(table->game);

      table->finished = true;

      iprintf("Removing game %d from observation list.\n", table->number);
      prompt();

      iprintf("You are now observing game %d.\n", table->number);
      prompt();
}

static void top_inprogress(Table *table, String *packet) {  /* 0x30 */
      table->inprogress = true;
}

static void top_message(Table *table, String *packet) {     /* 0x31 */
      unpackutfString(packet, packet);
      iprintf("Game %d: %s\n", table->number, packet->string);
      prompt();
}

static void top_newhost(Table *table, String *packet) {     /* 0x35 */
      Player *p;

      unpackutfString(packet, packet);
      p = findPlayer(packet->string);

      table->host = p;
      iprintf("Game %d: Host is now %s.\n", table->number,
            phandle(p));
      prompt();
}

static void top_startgamerequest(Table *table, String *packet) {  /* 0x39 */
      char color = (uchar)packet->string[0];
      char *unr, *etime;
      char wr[8], br[8];

      if (color == -1) {
            iprintf("Game %d: Start requests reset.\n", table->number);
            prompt();
            table->start[0] = false;
            table->start[1] = false;
      } else if (table->finished && ((color == 0) || (color == 1))) {
            iprintf("Game %d: %s requests to start the game.\n",
                  table->number, phandle(table->players[(int)color]));
            prompt();

            table->start[(int)color] = true;

            /*
             * Sometimes both players can request to start the game, then
             * one will stand up, but the other requests this AFTER the
             * player stands up, and the server doesn't send the reset
             * right away.  So we also need to make sure that someone is
             * sitting down to prevent a segmentation fault.
             */
            if ((table->start[0] && table->start[1]) &&
                        (table->players[0] != NULL) &&
                        (table->players[1] != NULL)) {
                  lastopp = (table->players[0] == pme) ?
                        table->players[1] : table->players[0];
                  unr = tablerated(table) ? "" : "un";

                  etime = strGameType(table);

                  prating(wr, table->players[0]->rating, 0);
                  prating(br, table->players[1]->rating, 0);

                  printf("\nCreating: %s (%s) %s (%s) %srated %s %ld %ld\n",
                        phandle(table->players[0]), wr,
                        phandle(table->players[1]), br,
                        unr, etime, tabletime(table), tableinc(table));

                  printf("{Game %d (%s vs. %s) Creating %srated %s match.}\n",
                        table->number, phandle(table->players[0]),
                        phandle(table->players[1]), unr, etime);
                  prompt();

                  initGame(table->game);
                  table->finished = false;
                  table->result = "*";

                  refresh(table);
            } else if ((table->players[(int)color] != pme) &&
            (table->players[1 - (int)color] == pme) &&
            variables[VAR_AUTOSTART].number) {
                  if (inList(&lists[LIST_NOPLAY], table->players[(int)color]->lhandle)) {
                        iprintf("Game %d: Opponent is censored; not "
                              "auto-starting.\n", table->number);
                  } else if (!checkFormula(table)) {
                        iprintf("Game %d: Formula check failed; not "
                              "auto-starting.\n", table->number);
                  } else {
                        iprintf("Game %d: Auto-starting.\n", table->number);

                        nprinttop(table->number, TOP_START, NULL, 0);
                  }

                  prompt();
            }
      }
}

static void top_gameover(Table *table, String *packet, bool flag) {     /* 0x5b and 0x69 */
      int result = packet->string[0];
      static char res[128], st[256];

      if (result == -2) {
            strcpy(res, "Game drawn} 1/2-1/2");
            table->result = "1/2-1/2";
      } else if ((result == 0) || (result == 1)) {
            snprintf(res, sizeof(res), "%s %s} %d-%d",
                  phandle(table->players[result]),
                  flag ? "forfeits on time" : "resigns", result,
                  1 - result);
            table->result = (result == 1) ? "1-0" : "0-1";
      } else {
            snprintf(res, sizeof(res), "Unknown (%d)} *", result);
            table->result = "*";
      }

      snprintf(st, sizeof(st), "\n{Game %d (%s vs. %s) %s\n",
            table->number,
            phandle(table->players[0]),
            phandle(table->players[1]),
            res);

      gameover(table, st);
}

static void top_gameover_resign(Table *table, String *packet) {   /* 0x5b */
      top_gameover(table, packet, false);
}

static void top_moves(Table *table, String *packet) { /* 0x61 */
      unsigned int moves;
      Move move_st;
      unsigned short move, *p;

      initGame(table->game);

      memcpy(&moves, &packet->string[4], 4);
      moves = ntohl(moves);

      p = (unsigned short *)&packet->string[8];

      while (moves--) {
            memset(&move_st, 0, sizeof(move_st));

            move = ntohs(*(p++));

            move_st.x1 = (uchar)(move & 7);
            move >>= 3;
            move_st.y1 = (uchar)(7 - (move & 7));
            move >>= 3;
            move_st.x2 = (uchar)(move & 7);
            move >>= 3;
            move_st.y2 = (uchar)(7 - (move & 7));
            switch (move >> 3) {
            case 4:
                  move_st.promoteTo = KNIGHT;
                  break;

            case 6:
                  move_st.promoteTo = BISHOP;
                  break;

            case 8:
                  move_st.promoteTo = ROOK;
                  break;

            case 10:
                  move_st.promoteTo = QUEEN;
                  break;

            default:
                  move_st.promoteTo = EMPTY;
                  break;
            }

            makemove(table, &move_st, false);
      }

      refresh(table);

      if (!table->inprogress)
            table->finished = true;
      else
            table->inprogress = false;
}

static void top_clear(Table *table, String *packet) { /* 0x62 */
      initGame(table->game);
      table->finished = false;
      refresh(table);
}

static void top_kibitz(Table *table, String *packet) {      /* 0x63 */
      String *who, *what;
      Player *p;
      char rating[16];

      who = unpackutfStringP(StringNull(), packet);

      if (inList(&lists[LIST_CENSOR], who->string)) {
            StringFree(who);
            return;
      }

      what = unpackutfStringP(StringNull(), packet);

      p = findPlayer(who->string);
      if (p == NULL) {
            StringFree(who);
            StringFree(what);
            return;
      }

      prating(rating, p->rating, 0);

      iprintf("%s(%s)[%d] kibitzes: %s\n",
            p->handle, rating, table->number, what->string);
      prompt();

      StringFree(who);
      StringFree(what);
}

static void top_clock(Table *table, String *packet) { /* 0x6c */
      uchar color;
      i64_t time;

      color = (uchar)packet->string[0];
      memcpy(&time, &packet->string[1], sizeof(i64_t));
      time = ntohll(time);

      if (time < 0) {
            table->clock[color] = 0;
            return;
      } else if (table->game->turn != (color ? BLACK : WHITE)) {
            table->clock[color] = -time;
      } else {
            table->clock[color] = time + gettimeofdayll();
      }

#if CLOCK_UPDATE
      if (color)
            refresh(table);
#endif
}

static bool makemove(Table *table, Move *move, bool noend) {
      Game *game = table->game;
      int pfrom, pto, result;
      static char donemsg[1024];
      char reason[128], *text;
      struct timeval tv;
      i64_t now;

      table->finished = false;

      pfrom = game->board[move->x1][move->y1];
      pto   = game->board[move->x2][move->y2];

      if (pfrom == EMPTY)
            debugGame(game, table->number, "No piece on the source square.",
                        move);

      if (!iscolor(pfrom, game->turn))
            debugGame(game, table->number, "The moved piece does not belong to the active player.",
                  move);

      if ((pto != EMPTY) && iscolor(pto, game->turn))
            debugGame(game, table->number, "The captured piece has the same color as the capturing piece.",
                  move);

      /* Promotion info is sent later. */
      if ((move->promoteTo == EMPTY) && (piecetype(pfrom) == PAWN) &&
                  ((move->y2 == 0) || (move->y2 == 7))) {
            game->lastmove.present = true;
            game->lastmove.move = *move;
            return false;
      }

      /* If a pawn isn't moving to the edge, it can't be a promotion. */
      if ((piecetype(pfrom) != PAWN) || ((move->y2 != 0) && (move->y2 != 7)))
            move->promoteTo = EMPTY;

      game->captured = EMPTY;

      if ((!legal_move(game, move->x1, move->y1, move->x2, move->y2)) ||
                  (move_calculate(game, move, move->promoteTo) == MOVE_ILLEGAL))
            debugGame(game, table->number, "The move does not appear to be legal.", move);

      game->halfmoves++;

      result = execute_move(game, move, 1);

      if ((addRepetition(game) >= 3) && (result == MOVE_OK)) {
            result = MOVE_REPETITION;
      } else if ((game->lastirrev != -1) && ((game->halfmoves - game->lastirrev) >= 100)) {
            result = MOVE_50MOVES;
      }

      now = gettimeofdayll();
      move->timeTaken = now - game->movetime;
      game->movetime = now;

      addMove(game, move);

      if ((result != MOVE_OK) && !noend) {
            text = "1/2-1/2";

            switch (result) {
            case MOVE_CHECKMATE:
                  snprintf(reason, sizeof(reason), "%s checkmated",
                        phandle(table->players[(game->turn == BLACK) ? 1 : 0]));
                  text = (game->turn == BLACK) ? "1-0" : "0-1";
                  break;

            case MOVE_STALEMATE:
                  strcpy(reason, "Game drawn by stalemate");
                  break;

            case MOVE_NOMATERIAL:
                  strcpy(reason, "Neither player has mating material");
                  break;

            case MOVE_REPETITION:
                  strcpy(reason, "Game drawn by repetition");
                  break;

            case MOVE_50MOVES:
                  strcpy(reason, "Game drawn by the 50 move rule");
                  break;

            default:
                  strcpy(reason, "Unknown");
                  text = "*";
                  break;
            }

            snprintf(donemsg, sizeof(donemsg),
                  "\n{Game %d (%s vs. %s) %s} %s\n",
                  table->number,
                  phandle(table->players[0]),
                  phandle(table->players[1]),
                  reason,
                  text
            );
            gameover(table, donemsg);
            table->result = text;
      }

      for (pto = 0; pto < 2; pto++) {
            gettimeofday(&tv, NULL);
            if ((game->turn == (pto ? BLACK : WHITE)) && (table->clock[pto] < 0)) {
                  table->clock[pto] = tv2ll(tv) - table->clock[pto];
            } else if ((game->turn != (pto ? BLACK : WHITE)) && (table->clock[pto] >= 0)) {
                  table->clock[pto] = -table->clock[pto] + tv2ll(tv);
            }
      }

      return true;
}

static void top_move(Table *table, String *packet) {  /* 0x6d */
      Move move;

      /* The side that moved is [0] but we don't need that */
      move.x1 = packet->string[1];
      move.y1 = (uchar)(7 - packet->string[2]);
      move.x2 = packet->string[3];
      move.y2 = (uchar)(7 - packet->string[4]);
      move.promoteTo = EMPTY;
      move.alg[0] = '\0';
      move.desc[0] = '\0';

      if (makemove(table, &move, false))
            refresh(table);
}

static void top_gameover_flag(Table *table, String *packet) {     /* 0x69 */
      top_gameover(table, packet, true);
}

static void top_promote(Table *table, String *packet) {     /* 0x70 */
      char piece = 0;

      if (!table->game->lastmove.present)
            return;
      table->game->lastmove.present = false;

      /* The side that moved is [0] but we don't need that */
      switch (packet->string[1]) {
      case 4:
            piece = KNIGHT;
            break;

      case 6:
            piece = BISHOP;
            break;

      case 8:
            piece = ROOK;
            break;

      case 10:
            piece = QUEEN;
            break;

      default:
            dief("Unknown piece type in promotion: %d", piece);
      }

      table->game->lastmove.move.promoteTo = piece;

      makemove(table, &table->game->lastmove.move, false);

      refresh(table);
}

Generated by  Doxygen 1.6.0   Back to index