Home Previous Bottom Next

Writing a chess program in 99 steps


06  Reading user commands

Before we continue, let's get rid of some files we do not need.    Right-click on stdafx.cpp in the solution explorer, and remove that file (and choose delete to permanently delete).  Do the same with targetver.h , stdafx.h , and ReadMe.txt.

Our entry point, main(), is going to be quite short initially.  All it will do is call readCommand(), to read user input (see snippet below.  So the first step is to delete all contents of wingletx.cpp and make it look exactly like this:

 

step 2: wingletx.cpp

#include <iostream>
#include "defines.h"
#include "protos.h"
#include "globals.h"
 
int main(int argc, char *argv[])
{
       std::cout << WINGLET_PROG_VERSION << std::endl;
       readCommands();
       return 0;
}

You will notice that there are new header files to add:  In the Solution Explorer, right-click on Header Files and add them. 
defines.h holds type definitions and constants:

step 3: defines.h

#ifndef WINGLET_DEFINES_H
#define WINGLET_DEFINES_H
 
#define WINGLET_PROG_VERSION "winglet 0.0, Copyright (C) 2011, Stef Luijten"
 
#define MAX_CMD_BUFF 256   // Console command input buffer
 
typedef int BOOLTYPE;
 
#endif

protos.h contains the prototypes of all functions (we'll keep them sorted alphabetically).  This ensures that the compiler already knows how a function looks like, before actually having seen the code. We'll start with prototyping the two first functions:

step 4: protos.h

#ifndef WINGLET_PROTOS_H
#define WINGLET_PROTOS_H
 
BOOLTYPE    doCommand(const char *buf);
void        readCommands();
 
#endif

The way user input is being read and processed might seem a bit peculiar at first sight. Later, when we connect the engine to Winboard, this method will prove handy, because we only have to add more (Winboard) commands without the need to change command processing.  The two functions will be inserted in a new source code file, commands.cpp.

The 'help'-section in doCommand shows the user commands that we intend to implement initially. The coding that actually executes these commands is not there yet, it will follow later.

You will notice that the prompt is fixed now, "wt> ".  Later, when we have an internal board representation, the prompt is going to switch back and forth between "wt> " and "bl> ", depending on which side is to move next.

step 5: command.cpp

#include <iostream>
#include "defines.h"
#include "protos.h"
#include "extglobals.h"
 
void readCommands()
{
       int nextc;
 
       {
                     std::cout << "wt> ";
       }
 
       std::cout.flush();
 
//     ===========================================================================
//     Read a command and call doCommand:
//     ===========================================================================
       while ((nextc = getc(stdin)) != EOF)
       {
              if (nextc == '\n')
              {
                     CMD_BUFF[CMD_BUFF_COUNT] = '\0';
                     while (CMD_BUFF_COUNT)
                     {
                           if (!doCommand(CMD_BUFF)) return;
                     }     
 
                     {
                           std::cout << "wt> ";
                     }
 
                     std::cout.flush();
              }
              else
              {
                     if (CMD_BUFF_COUNT >= MAX_CMD_BUFF-1)
                     {
                           std::cout << "Warning: command buffer full !! " << std::endl;
                           CMD_BUFF_COUNT = 0;
                     }
                     CMD_BUFF[CMD_BUFF_COUNT++] = nextc;
              }
       }
}
 
BOOLTYPE doCommand(const char *buf)
{
 
//     =================================================================
//  return when command buffer is empty
//     =================================================================
 
       if (!strcmp(buf, ""))
       {
              CMD_BUFF_COUNT = '\0';
              return true;    
       }
 
//     =================================================================
//  help, h, or ?: show this help
//     =================================================================
       if ((!strcmp(buf, "help")) || (!strcmp(buf, "h")) || (!strcmp(buf, "?")))
       {
              std::cout << std::endl << "help:" << std::endl;
              std::cout << "black               : BLACK to move" << std::endl;
              std::cout << "cc                  : play computer-to-computer " << std::endl;
              std::cout << "d                   : display board " << std::endl;
              std::cout << "exit                : exit program " << std::endl;
              std::cout << "eval                : show static evaluation of this position" << std::endl;
              std::cout << "game                : show game moves " << std::endl;
              std::cout << "go                  : computer next move " << std::endl;
              std::cout << "help, h, or ?       : show this help " << std::endl;
              std::cout << "info                : display variables (for testing purposes)" << std::endl;
              std::cout << "move e2e4, or h7h8q : enter a move (use this format)" << std::endl;
              std::cout << "moves               : show all legal moves" << std::endl;
              std::cout << "new                 : start new game" << std::endl;
              std::cout << "perf                : benchmark a number of key functions" << std::endl;
              std::cout << "perft n             : calculate raw number of nodes from here, depth n " << std::endl;
              std::cout << "quit                : exit program " << std::endl;
              std::cout << "r                   : rotate board " << std::endl;
              std::cout << "readfen filename n  : reads #-th FEN position from filename" << std::endl;
              std::cout << "sd n                : set the search depth to n" << std::endl;
              std::cout << "setup               : setup board... " << std::endl;
              std::cout << "undo                : take back last move" << std::endl;
              std::cout << "white               : WHITE to move" << std::endl;
              std::cout << std::endl;
              CMD_BUFF_COUNT = '\0';
              return true;
       }
      
//     =================================================================
//  exit or quit: exit program
//     =================================================================
       if ((!strcmp(buf, "exit")) || (!strcmp(buf, "quit")))
       {
              CMD_BUFF_COUNT = '\0';
              return false;
       }
 
//     =================================================================
//  unknown command
//     =================================================================
       std::cout << "    command not implemented: " << buf << ", type 'help' for more info" << std::endl;
       CMD_BUFF_COUNT = '\0';
       return true;
}
 

 

step 6: globals.h

#ifndef WINGLET_GLOBALS_H
#define WINGLET_GLOBALS_H
 
#include "defines.h"
 
char CMD_BUFF[MAX_CMD_BUFF];
int CMD_BUFF_COUNT = 0;
 
#endif
 

 

step 7: extglobals.h

#ifndef WINGLET_EXTGLOBALS_H
#define WINGLET_EXTGLOBALS_H
 
#include "defines.h"
 
extern char CMD_BUFF[];
extern int CMD_BUFF_COUNT;
 
#endif
 

At this point, the program will read user input, and displays help, or some informative message. The next task is to display the chessboard's start position, which means that we have to implement the internal board representation.

there's not much to try out yet, the response is always the same...

 


Home Previous Top Next

last update: Monday 30 May 2011