
/* cv_gtc_gsv_bug.c -- a minimal demonstration of a genuine,
 * reproducible bug in the original 1994 SAN Kit source: the
 * cv_gtc_gsv[] table (sanint.c) maps checkmate the wrong way round.
 *
 *   cv_gtc_gsv[gs_wcmt] = gtc_wwin;   // WRONG
 *   cv_gtc_gsv[gs_bcmt] = gtc_bwin;   // WRONG
 *
 * gs_wcmt means "White is checkmated" -- so Black wins -- yet it is
 * mapped to gtc_wwin, "White win". gs_bcmt is wrong the same way,
 * in the opposite direction.
 *
 * This program plays out the two shortest possible checkmates from
 * the starting position and prints, side by side, the game's actual
 * winner (ordinary chess knowledge, not computed) against what the
 * library's own table says. It relies on nothing from the SAN Kit
 * except SANStatus() itself (to identify which side got mated) --
 * the interpretation of the result is the whole point at issue.
 */

#include <stdio.h>
#include <string.h>

#include "sandef.h"
#include "sanvar.h"

#include "sanint.h"
#include "sanmnd.h"
#include "sanmpu.h"
#include "sanrst.h"

static void
Play (const char *san)
{
  sanT buf;
  mptrT mptr;

  strncpy (buf, san, sanL - 1);
  buf[sanL - 1] = '\0';

  mptr = SANDecodeAux (buf);
  if (mptr == NULL)
    {
      fprintf (stderr, "not a legal move: %s\n", san);
      return;
    };
  SANPlayMove (mptr);

  return;
}

static void
Demonstrate (const char *label, const char *moves[], int nmoves,
             const char *correct_result)
{
  int i;
  gsT gs;

  SANInit ();
  optnv[optn_nabd] = 1;
  optnv[optn_namd] = 1;

  for (i = 0; i < nmoves; i++)
    Play (moves[i]);

  gs = SANStatus ();

  printf ("%s\n", label);
  printf ("  actual winner (ordinary chess rules): %s\n", correct_result);
  printf ("  SANStatus() correctly identifies: %s\n",
          (gs == gs_wcmt) ? "gs_wcmt (White is checkmated)" :
          (gs == gs_bcmt) ? "gs_bcmt (Black is checkmated)" :
          "neither -- something is wrong with this example");
  printf ("  but the library's own table, gtcstrv[cv_gtc_gsv[gs]], "
          "says: \"%s\"\n\n", gtcstrv[cv_gtc_gsv[gs]]);

  return;
}

int
main (void)
{
  const char *foolsmate[] = { "f3", "e5", "g4", "Qh4" };
  const char *scholarsmate[] =
    { "e4", "e5", "Bc4", "Nc6", "Qh5", "Nf6", "Qxf7" };

  Demonstrate ("Fool's mate: 1.f3 e5 2.g4 Qh4# -- Black delivers mate.",
                foolsmate, 4, "0-1 (Black wins)");

  Demonstrate ("Scholar's mate: 1.e4 e5 2.Bc4 Nc6 3.Qh5 Nf6 4.Qxf7# -- "
                "White delivers mate.",
                scholarsmate, 7, "1-0 (White wins)");

  return (0);
}
