NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Modelle zum Nachbauen oder wo gibt es etwas interessantes oder Projekte?

Moderator: Moderatoren

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 29. Sep 2011 09:12

Hallo,
mein neues Projekt: ein Schach-Programm (NXC) für den NXT.
Ein richtiges schlaues Programm ist es jetzt am Anfang zwar noch nicht, aber er kann immerhin schon korrekte Züge machen und kennt größtenteils die Schachregeln.
Man kann manuell ziehen (mit Pfeiltasten Figur auswählen, dann BtnCenter, dann Zielfeld auswählen, nochmal BtnCenter: er prüft, ob Zug erlaubt ist, wenn ja: nochmal BtnCenter oder Abbruch mit BtnExit ) -
oder
man lässt ihn automatisch ziehen (wenn "auto" blinkt: BtnCenter), dann rechnet er die besten Züge aus (am Schluss wird der Zug angezeigt, dann nochmal BtnCenter drücken)


(Achtung! Neuere Versionen weiter unten im Thread:)
http://www.mindstormsforum.de/viewtopic.php?f=70&t=6790#p57269

Code: Alles auswählen

Alpha-Version gelöscht, Beta-Versionen mit größerer Suchtiefe s.u. im Thread!


keywords:
NXC NXT autonom autonomer Schach Roboter Schachroboter Arm Roboterarm Zuggenerator Micromax Muller
autonomous autonomously chess robot arm engine move generator
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
Golfi123
Enorm-Viel-Schreiber
Enorm-Viel-Schreiber
Beiträge: 601
Registriert: 5. Mär 2009 18:48
Wohnort: Mainz
Kontaktdaten:

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon Golfi123 » 29. Sep 2011 15:01

Klasse....Respekt :prima: !

Sieht wirklich gut aus. Sieht man ja nicht oft, dass jemand ein Schachprogramm noch "selber" schreitb. Die meisten bedienen sich aus Vorlagen, was ja auch legitim ist.

Freue mich wenns fertig ist.....

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 29. Sep 2011 15:24

Danke, für das Lob!
...aber "fertig" wird es sicher nie sein. Es lässt sich sicher immer was optimieren (reine Rechengeschwindigkeit, Speicherbedarf, Strategien, Auswahl unter scheinbar gleichwertigen Zügen, Vermeidung von Hin- und Herziehen, Eröffnungsbibliotheken, Musterpartien, Hash-Funktion, Tiefensuch-Algorithmus wie Alpha-Beta-, MiniMax- und Quiescence Search, usw usw.)

Der Weg ist das Ziel...

ps:
die neue Version erkennt nun ebenfalls man. + autom. herbeigeführtes Abzugs-Schach.

Benutzeravatar
NXT pro
Super-Enorm-Viel-Schreiber
Super-Enorm-Viel-Schreiber
Beiträge: 943
Registriert: 27. Sep 2010 21:38

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon NXT pro » 29. Sep 2011 20:48

Wenn man immer nur Auto drückt, kommt dann, wenn man das Spiel danach nochmal startet, noch einmal genau die gleiche Zugfolge wie vorher oder eine andere?
Real coders don't comment their code - it was hard to write, it should be hard to understand!

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 9. Okt 2011 14:21

NXT pro hat geschrieben:Wenn man immer nur Auto drückt, kommt dann, wenn man das Spiel danach nochmal startet, noch einmal genau die gleiche Zugfolge wie vorher oder eine andere?

ich habe das Programm inzwischen geändert (ich hatte auch deine Frage falsch verstanden).
Es wird nicht mehr der erste gefundene von den allerbesten (gleich guten) Zügen genommen, sondern unter den allerbesten Zügen randomisiert, so dass auch andere Zugvarianten mit gleich gutem Score eine Chance haben. Es werden sich also bestimmt verschiedene Spielvarianten entwickeln.
...
Hatte doch tatsächlich auch eine Variable falsch initialisiert. :(
Also, nochmal aufs Neue:
(die Codes passen wegen ihrer Größe z.T nicht mehr in die Codebox, daher als zips!)

NXC Chess Schach-Programm für den NXT

2 volle Ebenen (+ Schach-Test-Ebenen) plus eine verkürzte 3. Ebene als eine Art Quiescence Search:
chess 405.zip
2+1Q Ebenen Suchtiefe
(11.75 KiB) 834-mal heruntergeladen

3 volle Ebenen Suchtiefe (+ Schach-Test-Ebenen):
chess 406.zip
3 volle Ebenen Suchtiefe
(11.76 KiB) 562-mal heruntergeladen


mal zum Vergleich, wie schnell sowas als kompiliertes C Programm (8-9 Ebenen) auf dem PC läuft...:
chess40003.zip
C exe file
(6.93 KiB) 608-mal heruntergeladen

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 1. Nov 2011 22:39

der nächste Schritt:
vom Schach-Programm zum Schach-Roboter!


Der Roboter hat 5 Freiheitsgrade:
Drehkranz / Oberkörper re/li,
Oberarm / Schulter auf/ab,
Unterarm /Ellbogen auf/ab
Hand"gelenk"lifter auf/ab
Greifer auf/zu (pneumatisch)

chessBot.jpg
mit nur 1 NXT ohne Pneumatik-Druck-Regulierung (Fehler in jpg Datei)
chessBot.jpg (52.37 KiB) 26022 mal betrachtet

chessBot1.jpg
mit nur 1 NXT ohne Pneumatik-Druck-Regulierung; neu hochgeladen


neu: für die Pneumatik werden eine Pumpe mit Drucksensorsteuerung und 2 elektromagnetische 3/2-Wege-Ventile verwendet, zusätzlich wird jetzt ein 2. NXT dafür und zur chess-engine-Parallelisierung per BT eingesetzt:
chessbot2.jpg
inkl. 2.NXT mit Blick auf pneumatische Pumpe,
Drucksensor + elekromagnetische Ventile
chessbot2.jpg (87.42 KiB) 25306 mal betrachtet


hier zur Orientierung, wie die Roboter-Steuerung auf dem Master NXT funktioniert
( BT-Steuerung und Chess-Engine (=Schach-Move Generator, s. oben) wurden in Header File ausgelagert):

Code: Alles auswählen

/******************************************************************************/
//                             Robo-NXT Chess
//                          CHESS ROBOT for NXT
//                    inspired by micro-Max (by G. Muller)
//                    NXC/Bricxcc ab 3.3.8.10 (2011-07-02)
/******************************************************************************/
//string version="428RoBTMaster"

#include "BT_JHS_TOOLS_H.nxc"
#include "CHESS_AI_MOVE_GENERATOR.nxc"

#define debug

char _NOS_;  // number of slaves

// The connection channel to the Slave.

#define BT_CONN_1 1 // Slave 1
#define OUTBOX_1  1 // out
#define INBOX_11  2 // sensors (continuously)
#define INBOX_12  3 // motors, values (requested)

#define BT_CONN_2 2 // Slave 2
#define OUTBOX_2  4 // out
#define INBOX_21  5 // sensors (continuously)
#define INBOX_22  6 // motors, values (requested)

#define BT_CONN_3 3 // Slave 3
#define OUTBOX_3  7 // out
#define INBOX_31  8 // sensors (continuously)
#define INBOX_32  9 // motors, values (requested)

// Name of the Slave NXT.
string SLAVE[4] = {"000","001","002","003"};

// tone signals for debug
int  TONE[5] = {TONE_C4,TONE_E4,TONE_G4,TONE_C5,TONE_E5};


#define debug


/******************************************************************************/
int Menu (string text, string choice) {
/******************************************************************************/
   int BTN;
   ClearScreen();
   TextOut(6*(16-strlen(text))/2,16,text);
   TextOut(6*(16-strlen(choice))/2, 8,choice);
   TextOut(0, 0,"< L  ok/ESC   R >", DRAW_OPT_INVERT);
   BTN=getchar();
   ClearScreen();
   return BTN;

}


/*forward*/ void BTSendBoard(char K, char L, char turn,
                             char EP, char RK, char CK, char CM,
                             char board[], byte ID);
                             
/*forward*/ void RobotTransportFromTo(int START, int TARGET, char board[]);

/*forward*/ task DisplayValues();


long tTT[129], tA1[129], tA2[129];


/******************************************************************************/
// Init +  setup
/******************************************************************************/


/******************************************************************************/
void Init(){
/******************************************************************************/
  SetLongAbort(true);
  ResetSleepTimer();
  SetSleepTimeout(0);
}

/******************************************************************************/
void InitIOports() {
/******************************************************************************/
  SetSensor(0, SENSOR_TOUCH);
  SetSensor(1, SENSOR_TOUCH);
  SetSensor(2, SENSOR_TOUCH);
  SetSensor(3, SENSOR_TOUCH);
  SetMotorRegulationTime (10);
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



long SensorRemoteArray[3][11];  // [3 slaves][10 "sensors"][4 values each]
#define BT1_Sensor1  SensorRemoteArray[0][S1]
#define BT1_Sensor2  SensorRemoteArray[0][S2]
#define BT1_Sensor3  SensorRemoteArray[0][S3]
#define BT1_Sensor4  SensorRemoteArray[0][S4]

#define BT1_AutoMvRdy SensorRemoteArray[0][3]
#define BT1_AutoMv_K  SensorRemoteArray[0][4]
#define BT1_AutoMv_L  SensorRemoteArray[0][5]
#define BT1_AutoMvScr SensorRemoteArray[0][6]
#define BT1_AutoMv_EP SensorRemoteArray[0][7]
#define BT1_AutoMv_RK SensorRemoteArray[0][8]

#define BT2_AutoMvRdy SensorRemoteArray[1][3]
#define BT2_AutoMv_K  SensorRemoteArray[1][4]
#define BT2_AutoMv_L  SensorRemoteArray[1][5]
#define BT2_AutoMvScr SensorRemoteArray[1][6]
#define BT2_AutoMv_EP SensorRemoteArray[1][7]
#define BT2_AutoMv_RK SensorRemoteArray[1][8]





//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline int checksum(string s) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    int cs=0;
    for (int i=0;i<strlen(s);++i) cs+=s[i];
    return cs;
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
safecall void BTSend(char ID, string cmd) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  char INBOX, OUTBOX;

  INBOX = 3*ID;
  OUTBOX= INBOX -2;

  int ack=0;
  int ch=checksum(cmd);
  while (ack!=ch)  {
    SendRemoteString(ID, OUTBOX, cmd);
    do {Wait(1);} while (ReceiveRemoteNumber(INBOX, true, ack)!= NO_ERR);
    ReceiveRemoteNumber(INBOX, true, ack);
    Wait(30);
  }

}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline long GetMuxSensorValue(char slot, char port)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
     long MyValue;
     MyValue= SensorRemoteArray[slot][port];
     return MyValue;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
safecall void ParseBTResponseMsg(char ID, string str)  // slaveID=0...2
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
    string pstr, rstr, vstr, sp, sn;
    int i, n, len, v;

    len=strlen(str);   //

    for (i=0; i<11; ++i)    {
       sn=SubStr(str,0,1);       // dec
       n=StrToNum(sn);

       vstr=SubStr(str, 1, n);   // n= length of value string
       v=StrToNum(vstr);
       SensorRemoteArray[ID][i]=v;

       rstr=SubStr(str, 1+n, len);
       str=rstr;
       len=strlen(str);
    }
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task ReceiveSlaveData()    // NOS = Number of Slaves
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
   string _msg;

   while(true)   {
     if (_NOS_>=1) {
       do {Wait(1);} while(JHSReceiveRemoteString(INBOX_11, true, _msg) != NO_ERR);
       ParseBTResponseMsg(0, _msg) ;
       Wait(10);
     }

     if (_NOS_>=2) {
       do {Wait(1);} while(JHSReceiveRemoteString(INBOX_21, true, _msg) != NO_ERR);
       ParseBTResponseMsg(1, _msg) ;
       Wait(10);
     }

     if (_NOS_==3) {
       do {Wait(1);} while(JHSReceiveRemoteString(INBOX_31, true, _msg) != NO_ERR);
       ParseBTResponseMsg(2, _msg) ;
       Wait(10);
      }

     Wait(30);
   }
}




//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void BTOnFwd(byte ID, byte outp, char powr)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
  string  buf, cmd="F";
  string  soutp, spowr;
  char len, INBOX, OUTBOX;

  soutp= NumToStr(outp);
  len=strlen(soutp);
  while (len<4)
  {
     soutp=StrCat(" ",soutp);
     len=strlen(soutp);
  }

  spowr= NumToStr(powr);
  len=strlen(spowr);
  while (len<4)   {
     spowr=StrCat(" ",spowr);
     len=strlen(spowr);
  }

  cmd=StrCat(cmd,soutp,spowr);

  BTSend(ID, cmd);

}

#define CLAW            OUT_B  // BT motor for hand up/dn at remote NXT OUT_B
#define BT_CLAW_open()  BTOnFwd(1, CLAW, -100);
#define BT_CLAW_close() BTOnFwd(1, CLAW,  100);

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void BT_HAND_up()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
  string  buf, cmd="0";
  string  outp, spowr;
  char len, INBOX, OUTBOX, ID=1;

  BTSend(ID, cmd);

}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void BT_HAND_md()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
  string  buf, cmd="1";
  string  soutp, spowr;
  char len, INBOX, OUTBOX, ID=1;

  BTSend(ID, cmd);
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void BT_HAND_dn()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
  string  buf, cmd="2";
  string  soutp, spowr;
  char len, INBOX, OUTBOX, ID=1;

  BTSend(ID, cmd);

}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void BTStop(byte ID, byte outp)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
  string  buf, cmd="S";
  string  soutp;
  char len, INBOX, OUTBOX;

  soutp= NumToStr(outp);
  len=strlen(soutp);
  while (len<4)  {
     soutp=StrCat(" ",soutp);
     len=strlen(soutp);
  }

  cmd=StrCat(cmd,soutp);

  BTSend(ID, cmd);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void BTCoast(byte ID, byte outp)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
  string  buf, cmd="C";
  string  soutp;
  char len, INBOX, OUTBOX;

  soutp= NumToStr(outp);
  len=strlen(soutp);
  while (len<4) {
     soutp=StrCat(" ",soutp);
     len=strlen(soutp);
  }

  cmd=StrCat(cmd,soutp);

  BTSend(ID, cmd);

}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void BTSendArray(byte ID, string part, byte outp[])
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
  string  buf, cmd;
  string  soutp;
  char INBOX, OUTBOX;

  soutp= ByteArrayToStr(outp);
  cmd=StrCat(part,soutp);

  BTSend(ID, cmd);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
safecall void BTSendBoard(char K, char L, char turn,
                 char EP, char RK, char CK, char CM,
                 char board[], byte ID) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  char part[];
  int i;

  ClearScreen();
  TextOut(64,56,"Send"); NumOut(88,56, ID);

  ArraySubset(part, board, 0,43);             // board 0-42
  Wait(1);
  TextOut(0,48,FlattenVar(part));
  BTSendArray(ID, "[", part);
  Wait(10);

  ArraySubset(part, board,43,43);             // board 43-85
  Wait(1);
  TextOut(0,40,FlattenVar(part));
  BTSendArray(ID, "#", part);
  Wait(10);

  ArraySubset(part, board,86,43);             // board 86-129
  Wait(1);
  TextOut(0,32,FlattenVar(part));
  BTSendArray(ID, "]", part);
  Wait(10);

  ArrayBuild (part, K, L, turn, EP, RK, CK, CM);  // board moves and flags
  for(i=1;i<=7;++i) { NumOut(0,56-8*(i),part[i-1]); }
  Wait(1);
  TextOut(0,24,FlattenVar(part));
  BTSendArray(ID, "&", part);
  Wait(10);

  ClearScreen();
  PrintBoard(K, L, turn, CK, CM, RK, board);
  Wait(1);

}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void BTAutoMove(byte ID) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  char part[]={'A'};                            // dummy
  BTSendArray(ID, "$", part);
}



//------------------------------------------------------------------------------
#define TT 0
#define A1 1
#define A2 2
#define maxTT +5300
#define minTT -5300
#define minA1     0
#define maxA1 +5200
#define minA2 -5900
#define maxA2     0

#define MEnc(m) MotorRotationCount(m)
#define SRaw(s) SensorRaw(s)
#define STouch(s) SensorValue(s)
//------------------------------------------------------------------------------


int  D_=0;     // counter for piece drop area
char F_=1;
/******************************************************************************/
void RobotMovePiece(int &K, int &L, char turn, char &EP, char &RK, char &board[]) {
/******************************************************************************/
  char PP=0;                                                // move from K to L

   if (board[K]&32) board[K]-=32;       // remove virgin flag
   if (board[L]) {
     RobotTransportFromTo(L,127,board); // clear target field
     D_+=16;
     if (D_==128)  D_=1;                // next drop area
     else if (D_==129){ D_=7; F_=-1;}
     else if (D_==134){ D_=8; F_=-1;}
     else if (D_&0x88){ D_=0; F_= 1;}
     tTT[127]=F_*-900+tTT[D_];          // new coord
     tA1[127]=tA1[D_];
     tA2[127]=tA2[D_];
   }

   RobotTransportFromTo(K, L, board);
   board[L]=board[K];                   // move K -> L
   board[K]=0;                          // start K=empty

   if (EP) {                            // E.P. move done
     RobotTransportFromTo(board[board[127]],127,board);   // remove E.P. pawn field
     board[board[127]]=0;               // delete opponent pawn at E.P. sqr
     EP=0;                              // delete E.P.
   }
   else
   if (board[126]!=turn) {
     board[126]=0;                      // delete markers for possible E.P.
     board[127]=0;
     board[128]=0;
   }

   if (RK) {
     RobotTransportFromTo(board[board[124]], board[board[125]] ,board);
     board[board[124]]=board[board[125]]&15;
     board[board[125]]=0;
     board[125]=0;                      // delete markers for castling=Rochade
     board[124]=0;
     RK=0;
   }
}



long TTtarget;
char TTrdy;
//------------------------------------------------------------------------------
task  RotateToTargetTT() {
//------------------------------------------------------------------------------
  char port=TT, pwr=-80;
  long dabs, oldabs;
  TTrdy=0;

  while (!(inArea(MEnc(port),TTtarget,5))) {
    dabs=abs(MEnc(port)-TTtarget);
    if (dabs>=100) pwr=-80;
    if (dabs <80) pwr=-dabs;
    if (dabs<=40) pwr=-30;

    if ((oldabs<=dabs)&&(dabs<80)) pwr-=20;
    if ((inArea(MEnc(port),TTtarget,5))) { Off(port); Wait(10);}
    else {
     if (MEnc(port)<TTtarget) { OnFwd(port,-pwr);}
     if (MEnc(port)>TTtarget) { OnFwd(port, pwr);}
    }
    Wait(3);
    oldabs=dabs;
  }
  Off(port);
  Wait(50);
  TTrdy= true;
}


long A1target;
char A1rdy;
//------------------------------------------------------------------------------
task  RotateToTargetA1() {
//------------------------------------------------------------------------------
  long dabs, oldabs;
  char port=A1, pwr=-100;

  A1rdy=0;
  while (!(inArea(MEnc(port),A1target,5))) {
    dabs=abs(MEnc(port)-A1target);
    if (dabs>=100) pwr=-100;
    if (dabs<100) pwr=-dabs;
    if (dabs<=30) pwr=-40;

    if ((oldabs<=dabs)&&(dabs<80)) pwr-=20;
    if ((inArea(MEnc(port),A1target,5))) { Off(port); Wait(10);}
    else {
     if (MEnc(port)<A1target) { OnFwd(port,-pwr);}
     if (MEnc(port)>A1target) { OnFwd(port, pwr);}
    }
    Wait(3);
    oldabs=dabs;
  }
  Off(port);
  Wait(50);
  A1rdy= true;
}


long A2target;
char A2rdy;
//------------------------------------------------------------------------------
task  RotateToTargetA2() {
//------------------------------------------------------------------------------
  long dabs, oldabs;
  char port=A2, pwr=-100;

  A2rdy=0;
  while (!(inArea(MEnc(port),A2target,5))) {
    dabs=abs(MEnc(port)-A2target);
    if (dabs>=100) pwr=-100;
    if (dabs<100) pwr=-dabs;
    if (dabs<=40) pwr=-40;

    if ((oldabs<=dabs)&&(dabs<80)) pwr-=20;
    if ((inArea(MEnc(port),A2target,5))) { Off(port); Wait(10);}
    else {
     if (MEnc(port)<A2target) { OnFwd(port,-pwr);}
     if (MEnc(port)>A2target) { OnFwd(port, pwr);}
    }
    Wait(3);
    oldabs=dabs;
  }
  Off(port);
  Wait(50);
  A2rdy= true;
}


//------------------------------------------------------------------------------
task ResetTT() {
//------------------------------------------------------------------------------
  char state, speed=70;
  TTrdy=0;
  OnFwd(TT,-speed);
  Wait(3000);
  while(!(state==2)) {
    if (state==0) {
      OnFwd(TT, speed);
      if (STouch(TT)) {
        Off(TT);
        Wait(10);
        state=1;
      }
    }
    if (state==1) {
      OnFwd(TT,-speed);
      Wait(50);
      if (!STouch(TT)) {
        Off(TT);
        Wait(10);
        state=2;
      }
    }
    Wait(1);
  }
  Wait(200);
  if (state==2) ResetRotationCount(TT);
  Wait(200); Coast(TT);
  TTrdy=1;
}


//------------------------------------------------------------------------------
task ResetA1() {
//------------------------------------------------------------------------------
  char state, speed=-100;
  A1rdy=0;
  while(!(state==2)) {
    if (state==0) {
      OnFwd(A1, speed);
      if (STouch(A1)) {
        Off(A1);
        Wait(10);
        state=1;
      }
    }
    if (state==1) {
      OnFwd(A1,70);
      Wait(50);
      if (!STouch(A1)) {
        Off(A1);
        Wait(10);
        state=2;
      }
    }
    Wait(1);
  }
  Wait(200);
  if (state==2) ResetRotationCount(A1);
  Wait(200); Coast(A1);
  A1rdy=1;
}


//------------------------------------------------------------------------------
task ResetA2() {
//------------------------------------------------------------------------------
  char state, speed=100;
  A2rdy=0;
  while(!(state==2)) {
    if ((state==0)&&(MEnc(A1)<2500)) {
      if (MEnc(A1)<2500) {OnFwd(A2, speed);}
      if (STouch(A2)) {
        Off(A2);
        Wait(10);
        state=1;
      }
    }
    if (state==1) {
      OnFwd(A2,-70);
      Wait(50);
      if (!STouch(A2)) {
        Off(A2);
        Wait(10);
        state=2;
      }
    }
    Wait(1);
  }
  Wait(200);
  if (state==2) ResetRotationCount(A2);
  Wait(200); Coast(A2);
  A2rdy=1;
}


//------------------------------------------------------------------------------
void InitLookupTable() {
//------------------------------------------------------------------------------
  int p;

//      sqr            TT               sh.ri             el.le
    p= 119;  tTT[p]= 1050;       tA1[p]=5210;     tA2[p]=-1880; // h1
    p= 118;  tTT[p]=  760;       tA1[p]=4700;     tA2[p]=-2535; //
    p= 117;  tTT[p]=  510;       tA1[p]=4690;     tA2[p]=-2600;
    p= 116;  tTT[p]=  250;       tA1[p]=4700;     tA2[p]=-2600;
    p= 115;  tTT[p]=  -30;       tA1[p]=4700;     tA2[p]=-2580;
    p= 114;  tTT[p]= -234;       tA1[p]=4850;     tA2[p]=-2370;
    p= 113;  tTT[p]= -500;       tA1[p]=5020;     tA2[p]=-2140;
    p= 112;  tTT[p]= -740;       tA1[p]=5370;     tA2[p]=-1420; // a1

    p= 103;  tTT[p]= 1080;       tA1[p]=4180;     tA2[p]=-3235; // h2
    p= 102;  tTT[p]=  770;       tA1[p]=3945;     tA2[p]=-3485;
    p= 101;  tTT[p]=  500;       tA1[p]=3930;     tA2[p]=-3535;
    p= 100;  tTT[p]=  200;       tA1[p]=3895;     tA2[p]=-3570;
    p=  99;  tTT[p]= -100;       tA1[p]=3920;     tA2[p]=-3640; // d2
    p=  98;  tTT[p]= -340;       tA1[p]=3985;     tA2[p]=-3535;
    p=  97;  tTT[p]= -610;       tA1[p]=4180;     tA2[p]=-3375;
    p=  96;  tTT[p]= -830;       tA1[p]=4370;     tA2[p]=-3090; // a2

    p=  87;  tTT[p]= 1160;       tA1[p]=3530;     tA2[p]=-3995; // h3
    p=  86;  tTT[p]=  850;       tA1[p]=3395;     tA2[p]=-4135;
    p=  85;  tTT[p]=  500;       tA1[p]=3200;     tA2[p]=-4220;
    p=  84;  tTT[p]=  240;       tA1[p]=3220;     tA2[p]=-4230;
    p=  83;  tTT[p]=  -80;       tA1[p]=3225;     tA2[p]=-4205;
    p=  82;  tTT[p]= -380;       tA1[p]=3320;     tA2[p]=-4135;
    p=  81;  tTT[p]= -690;       tA1[p]=3455;     tA2[p]=-4035;
    p=  80;  tTT[p]=-1000;       tA1[p]=3630;     tA2[p]=-3830; // a3

    p=  71;  tTT[p]= 1230;       tA1[p]=2905;     tA2[p]=-4455; // h4
    p=  70;  tTT[p]=  930;       tA1[p]=2840;     tA2[p]=-4665;
    p=  69;  tTT[p]=  570;       tA1[p]=2840;     tA2[p]=-4665;
    p=  68;  tTT[p]=  330;       tA1[p]=2655;     tA2[p]=-4730;
    p=  67;  tTT[p]= -130;       tA1[p]=2710;     tA2[p]=-4750; // d4
    p=  66;  tTT[p]= -425;       tA1[p]=2825;     tA2[p]=-4610;
    p=  65;  tTT[p]= -745;       tA1[p]=2870;     tA2[p]=-4525;
    p=  64;  tTT[p]=-1060;       tA1[p]=3180;     tA2[p]=-4330; // a4

    p=  55;  tTT[p]= 1415;       tA1[p]=2380;     tA2[p]=-4970; // h5
    p=  54;  tTT[p]= 1000;       tA1[p]=2210;     tA2[p]=-5080;
    p=  53;  tTT[p]=  605;       tA1[p]=2210;     tA2[p]=-5200;
    p=  52;  tTT[p]=  240;       tA1[p]=2210;     tA2[p]=-5160;
    p=  51;  tTT[p]= -150;       tA1[p]=2160;     tA2[p]=-5160;
    p=  50;  tTT[p]= -490;       tA1[p]=2180;     tA2[p]=-5070;
    p=  49;  tTT[p]= -860;       tA1[p]=2360;     tA2[p]=-4980;
    p=  48;  tTT[p]=-1240;       tA1[p]=2530;     tA2[p]=-4760; // a5

    p=  39;  tTT[p]= 1505;       tA1[p]=2055;     tA2[p]=-5290; // h6
    p=  38;  tTT[p]= 1075;       tA1[p]=1785;     tA2[p]=-5355;
    p=  37;  tTT[p]=  670;       tA1[p]=1610;     tA2[p]=-5410;
    p=  36;  tTT[p]=  300;       tA1[p]=1515;     tA2[p]=-5440;
    p=  35;  tTT[p]= -220;       tA1[p]=1610;     tA2[p]=-5460;
    p=  34;  tTT[p]= -580;       tA1[p]=1730;     tA2[p]=-5450;
    p=  33;  tTT[p]= -970;       tA1[p]=1910;     tA2[p]=-5340;
    p=  32;  tTT[p]=-1300;       tA1[p]=2090;     tA2[p]=-5130; // a6

    p=  23;  tTT[p]= 1700;       tA1[p]=1505;     tA2[p]=-5580; // h7
    p=  22;  tTT[p]= 1230;       tA1[p]=1215;     tA2[p]=-5650;
    p=  21;  tTT[p]=  800;       tA1[p]=1340;     tA2[p]=-5830;
    p=  20;  tTT[p]=  330;       tA1[p]=1120;     tA2[p]=-5770;
    p=  19;  tTT[p]= -180;       tA1[p]=1068;     tA2[p]=-5740;
    p=  18;  tTT[p]= -660;       tA1[p]=1260;     tA2[p]=-5830;
    p=  17;  tTT[p]=-1095;       tA1[p]=1420;     tA2[p]=-5600;
    p=  16;  tTT[p]=-1480;       tA1[p]=1530;     tA2[p]=-5360; // a7

    p=   7;  tTT[p]= 1975;       tA1[p]=1130;     tA2[p]=-5880; // h8
    p=   6;  tTT[p]= 1480;       tA1[p]= 920;     tA2[p]=-6100;
    p=   5;  tTT[p]=  945;       tA1[p]= 935;     tA2[p]=-6100;
    p=   4;  tTT[p]=  380;       tA1[p]= 900;     tA2[p]=-6100;
    p=   3;  tTT[p]= -155;       tA1[p]= 775;     tA2[p]=-5960;
    p=   2;  tTT[p]= -810;       tA1[p]= 930;     tA2[p]=-5960;
    p=   1;  tTT[p]=-1230;       tA1[p]= 980;     tA2[p]=-5890;
    p=   0;  tTT[p]=-1685;       tA1[p]=1260;     tA2[p]=-5685; // a8

    p= 128;  tTT[p]=    0;       tA1[p]=   0;     tA2[p]=minA2; // align board

    p= 127; tTT[p]=-900+tTT[0];       tA1[p]=tA1[0];   tA2[p]=tA2[0]; // drop area

}

//------------------------------------------------------------------------------
void MoveClawTo(int sqr) {
//------------------------------------------------------------------------------
  printf1(0, 56, "target sqr=%4d",sqr);

  if (MEnc(A1)>=(tA1[sqr]-1000) && (MEnc(A2)>=tA2[sqr])-1000)  {

    TTtarget=tTT[sqr];    start RotateToTargetTT;
    if(MEnc(A1)>3000) { A1target=max(tA1[sqr],3000); start RotateToTargetA1; }
    while (!A1rdy);
    A1target=tA1[sqr];    start RotateToTargetA1;
    A2target=tA2[sqr];    start RotateToTargetA2;
  }

  else  {
    TTtarget=tTT[sqr];    start RotateToTargetTT;

    A2target=min(MEnc(A2)+1000,0);    start RotateToTargetA2;
    Wait(100);
    while (!A2rdy);

    A1target=tA1[sqr];      start RotateToTargetA1;
    A2target=tA2[sqr];      start RotateToTargetA2;
    Wait(100);
  }

  while (!TTrdy);
  while (!A1rdy);
  while (!A2rdy);

  Off(OUT_ABC);
  while(btn (BTNLEFT));
  if(btn (BTNRIGHT)) {
    while(btn (BTNRIGHT));
    tTT[sqr]= MEnc(TT);     tA1[sqr]=MEnc(A1);     tA2[sqr]=MEnc(A2);
    PlayTones(sndBlipBlip);
  }
  Wait(200);

}

//------------------------------------------------------------------------------
inline void CheckSquare(int sqr) {
//------------------------------------------------------------------------------

    BT_HAND_up();      while (!BT1_Sensor3);        // hand up!

    MoveClawTo(sqr);  PlayTones(sndChordUp);
    Coast(OUT_ABC); Wait(200);

    BT_HAND_dn(); while (!BT1_Sensor1);             // hand down!

    while(!btnhit() );                    // wait until Btn pressed
    if(btn (BTNRIGHT)) {
      tTT[sqr]= MEnc(TT);     tA1[sqr]=MEnc(A1);     tA2[sqr]=MEnc(A2);
      PlayTones(sndBlipBlip);
    }
    if(btn (BTNLEFT)) return;
}

//------------------------------------------------------------------------------
void CalibrateAllSquares() {
//------------------------------------------------------------------------------
  int sqr;
  BT_CLAW_open(); Wait(200);          // claw open!

  for (sqr=119; sqr>=0; --sqr ) {
    if (sqr & 0x88) continue;
    CheckSquare(sqr);
  }
}

//------------------------------------------------------------------------------
void Calibrate_9_Squares(){
//------------------------------------------------------------------------------
  CheckSquare( 87);
  CheckSquare( 86);
  CheckSquare( 85);
 
  CheckSquare(100);
  CheckSquare( 99);
  CheckSquare( 98);
 
  CheckSquare( 84);
  CheckSquare( 83);
  CheckSquare( 82);
 

}

//------------------------------------------------------------------------------
void RobotTransportFromTo(int START, int TARGET, char board[]) {
//------------------------------------------------------------------------------
  char BigPiece=0;

  BT_CLAW_open();   Wait(100);                              // claw open!
  BT_HAND_up();     Wait(10);  while (!BT1_Sensor3);         // hand up!



  MoveClawTo(START);  PlayTones(sndBuzz);  Coast(OUT_ABC);

  if ( ((board[START]&7)==3)||((board[START]&7)==4)||((board[START]&7)==7) ) {
    BigPiece=1;
    BT_HAND_md();  Wait(10);  while (!BT1_Sensor2);          // hand med
  }
  else {
    BT_HAND_dn();  Wait(10);  while (!BT1_Sensor1);          // hand down!
  }
  PlayTones(sndBeep);  Coast(OUT_ABC);  Wait(200);
 
  BT_CLAW_close(); Wait(100);                    // claw close! => grab piece
  BT_HAND_up();    Wait(10);  while (!BT1_Sensor3);          // hand up!
 
  MoveClawTo(TARGET);  PlayTones(sndBuzz);  Coast(OUT_ABC);
 
  if ( BigPiece ) {
    BT_HAND_md();  Wait(10);  while (!BT1_Sensor2);
  }
  else {
    BT_HAND_dn();  Wait(10);  while (!BT1_Sensor1);
  }

  BT_CLAW_open();  Wait(100);                    // claw open! => drop piece
  BT_HAND_up();    Wait(10);  while (!BT1_Sensor3);         // hand up!
}



//------------------------------------------------------------------------------
void RobotArmsZeroInit() {
//------------------------------------------------------------------------------
   start ResetTT;
   start ResetA1;
   Wait(4000); start ResetA2;

   while(!(TTrdy&&A1rdy&&A2rdy));
}


//------------------------------------------------------------------------------
task DisplayValues() {
//------------------------------------------------------------------------------
  ClearScreen();
  while(1) {

    printf1(0,48,"S1%d",STouch(TT)); printf1(24,48, "TT%5d",MEnc(TT)); printf1(66,48,"run%2d",MotorRunState(TT));
    printf1(0,40,"S2%d",STouch(A1)); printf1(24,40, "A1%5d",MEnc(A1)); printf1(66,40,"run%2d",MotorRunState(A1));
    printf1(0,32,"S3%d",STouch(A2)); printf1(24,32, "A2%5d",MEnc(A2)); printf1(66,32,"run%2d",MotorRunState(A2));
   
    printf1(0,24, "BT1_S1 %d", BT1_Sensor1);
    printf1(0,16, "BT1_S2 %d", BT1_Sensor2);
    printf1(0, 8, "BT1_S3 %d", BT1_Sensor3);
    printf1(0, 0, "MovRdy %d", BT1_AutoMvRdy);

    Wait(10);
  }
}

//------------------------------------------------------------------------------
task EmergencyStop() {
//------------------------------------------------------------------------------
  while(true) {
    while (STouch(S4)) {
      for (int i=1; i<=_NOS_; ++i) {   // send twice each time
        Yield(); while (BluetoothStatus(i) != NO_ERR);
        RemoteStopProgram(i);
        Wait(10);
      }
      StopAllTasks();
    }
    Wait(10);
  }
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
bool Init_BT(char max_conn)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
    int iResult;
    bool bSlave1Ready;
    char conn;

    _NOS_ = max_conn;

    // In case it is already connected to something.
    for ( conn=1; conn<=_NOS_; ++conn) {
      DisconnectBT(conn);
    }

    PlayTone(TONE_C4, 200);   Wait(1000);

    for ( conn=1; conn<=_NOS_; ++conn) {
      until (ConnectBT(conn, SLAVE[conn])) ;
      PlayTone(TONE[conn], 200);  Wait(200);
    }

}





/******************************************************************************/
task main(){
/******************************************************************************/
  char EP,                            // flag: en passant
       RK,                            // flag: castling=Rochade
       CK, CM,                        // flag: check!=Schach! (1&8, 1&16)
       turn,                          // side on turn
       chosen;                        // manual or auto move from stdin input;
  char board[129];                    // Piece K_start-> L_dest
  int K, L,                           // score local, remote
      score, rscore1, rscore2, rscore3, idum, buf;
  char PMOD=0, m1, m2, m3;
  string s;


// init all defauts
  Init();
  InitIOports();
  Init_BT(2);

  InitLookupTable();

  start EmergencyStop;

  start ReceiveSlaveData;
  start DisplayValues;

// chess robot setup
  BT_CLAW_open();  Wait(100);  BT_HAND_up();  while (!BT1_Sensor3);
  RobotArmsZeroInit(); PlayTones(sndChordUp);

  // align board center base line
  BT_CLAW_close(); Wait(1000);
  MoveClawTo(128); PlayTones(sndChordUp); Coast(OUT_ABC); Wait(200);

  // single chess square alignment
  BT_HAND_up();  while (!BT1_Sensor3);  BT_CLAW_open(); Wait(200);

  stop DisplayValues;
  buf=Menu("Calibrate ?", "/9  /ALL  /no");

  start DisplayValues;
  if(buf==BTNLEFT)   Calibrate_9_Squares();
  else
  if(buf==BTNCENTER) CalibrateAllSquares();
  BT_HAND_up();  while (!BT1_Sensor3);

  stop DisplayValues;
  // finished: "real" chess board setup

  // start "virtual" chess board and Hal AI setup
  EP=RK=CK=CM=0;
  K=-1; L=-1;
  turn= 8;                                   // 8=white
  BoardSetup(board);

  ClearScreen();
  PrintBoard (K, L, turn, CK, CM, RK, board);

  while(true){
    chosen=false;                              // get choice auto/manually
    //permanent auto mode: outcomment while loop!
    //while (!(chosen=GetHIDinput(K, L, turn, EP, RK, CK, CM, board)));
                                               // (pass move + flags)

    if (L!=-1) {                               // L>=0: manual move chosen
      start DisplayValues;
      RobotMovePiece(K, L, turn, EP, RK, board);
      stop DisplayValues;
    }
    else {                                        // L=-1: auto move required
                                                  // parallelizing:
      BTSendBoard(K, L, turn, EP, RK, CK, CM, board, 1);   // auto move (remote)
      Wait(20);
      BTAutoMove(1);
      Wait(20);

      BTSendBoard(K, L, turn, EP, RK, CK, CM, board, 2);   // auto move (remote)
      Wait(20);
      BTAutoMove(2);
      Wait(20);

      score=AutoMove(K, L, turn, EP, RK, CK, CM, board, PMOD);    // auto move (local)

      ClearScreen();
      BT1_AutoMvScr=-INFINITY;
      BT2_AutoMvScr=-INFINITY;

      if(turn==8)s="white"; else s="black";
      TextOut(0,56, s);    TextOut(36,56," 1   2   3 ");

    do {
      printf1(0,48,"K%3d", K);   printf1(24,48,"%4d", BT1_AutoMv_K);  printf1(48,48,"%4d", BT2_AutoMv_K);
      printf1(0,40,"L%3d", L);   printf1(24,40,"%4d", BT1_AutoMv_L);  printf1(48,40,"%4d", BT2_AutoMv_L);
      printf1(0,32,"EP%2d",EP);  printf1(24,32,"%4d", BT1_AutoMv_EP); printf1(48,32,"%4d", BT2_AutoMv_EP);
      printf1(0,24,"RK%2d",RK);  printf1(24,24,"%4d", BT1_AutoMv_RK); printf1(48,24,"%4d", BT2_AutoMv_RK);

      printf1(0, 8,"rdy%d", 1);  printf1(24, 8,"%4d", BT1_AutoMvRdy); printf1(48, 8,"%4d", BT2_AutoMvRdy);
      printf1(0, 0,"%4d",score); printf1(24, 0,"%4d", BT1_AutoMvScr); printf1(48, 0,"%4d", BT2_AutoMvScr);

      Wait(50);
    } until ( (BT1_AutoMvRdy && BT2_AutoMvRdy) );

      printf1(0,48,"K%3d", K);   printf1(24,48,"%4d", BT1_AutoMv_K);  printf1(48,48,"%4d", BT2_AutoMv_K);
      printf1(0,40,"L%3d", L);   printf1(24,40,"%4d", BT1_AutoMv_L);  printf1(48,40,"%4d", BT2_AutoMv_L);
      printf1(0,32,"EP%2d",EP);  printf1(24,32,"%4d", BT1_AutoMv_EP); printf1(48,32,"%4d", BT2_AutoMv_EP);
      printf1(0,24,"RK%2d",RK);  printf1(24,24,"%4d", BT1_AutoMv_RK); printf1(48,24,"%4d", BT2_AutoMv_RK);

      printf1(0, 8,"rdy%d", 1);  printf1(24, 8,"%4d", BT1_AutoMvRdy); printf1(48, 8,"%4d", BT2_AutoMvRdy);
      printf1(0, 0,"%4d",score); printf1(24, 0,"%4d", BT1_AutoMvScr); printf1(48, 0,"%4d", BT2_AutoMvScr);





#ifdef debug
      getchar();
#endif
      rscore1= BT1_AutoMvScr;
      rscore2= BT2_AutoMvScr;
      if(tWHITE) {
        m1= ((rscore1>rscore2)?1:2);
        m2= ((score >= max(rscore1,rscore2))?4:3);

        if ((m2==3)&&(m1=1))   {
          K= BT1_AutoMv_K;
          L= BT1_AutoMv_L;
          EP=BT1_AutoMv_EP;   // <<<<<<<<<<<<<<<<<<<<<<<<<<
          RK=BT1_AutoMv_RK;
        }
        else
        if ((m2==3)&&(m1=2))   {
          K= BT2_AutoMv_K;
          L= BT2_AutoMv_L;
          EP=BT2_AutoMv_EP;   // <<<<<<<<<<<<<<<<<<<<<<<<<<
          RK=BT2_AutoMv_RK;
        }
      }
      else
      if(tBLACK) {
        m1= ((rscore1<rscore2)?1:2);
        m2= ((score <= min(rscore1,rscore2))?4:3);

        if ((m2==3)&&(m1=1))   {
          K= BT1_AutoMv_K;
          L= BT1_AutoMv_L;
          EP=BT1_AutoMv_EP;   // <<<<<<<<<<<<<<<<<<<<<<<<<<
          RK=BT1_AutoMv_RK;
        }
        else
        if ((m2==3)&&(m1=2))   {
          K= BT2_AutoMv_K;
          L= BT2_AutoMv_L;
          EP=BT2_AutoMv_EP;   // <<<<<<<<<<<<<<<<<<<<<<<<<<
          RK=BT2_AutoMv_RK;
        }
      }


      start DisplayValues;
      RobotMovePiece(K, L, turn, EP, RK, board);
      stop DisplayValues;
    }

    ClearScreen();
    if(CM) {
      TextOut(24,40,"GAME OVER");
      TextOut(18,24,"CHECK MATE/");
      TextOut(12,16,"KING CAPTURED");
      PlayTones(sndFuneral);
      Wait(1000);
      ClearScreen();
      PrintBoard (K, L, turn, CK, CM, RK, board);
      SetLongAbort(true);
      while(true) {
        MarkPos(-1, FindKing((24-turn),board), board); Wait(200);
      }
    }

    PrintBoard (K, L, (24-turn), CK, CM, RK, board);

    K=-1;
    L=-1;
    CursPos=120;
    turn=24-(turn);          // toggle 8 -> 16 -> 8 ->...

    Wait(1);
  }
}

Code: Alles auswählen

/******************************************************************************/
// HID unit:    choose - |auto mode|  - or -  |take piece manually|
/******************************************************************************/

/******************************************************************************/
char GetHIDinput(int &K, int &L, char turn,
                 char &EP, char &RK, char &CK, char &CM, char &board[]){
/******************************************************************************/
    char valid, buf, chosen,
         uK, LK, OtherTurn, tboard[129], uboard[129];;

//..............................................................................
    key=-1;
    chosen=false;
    OtherTurn=24-(turn);

    if  (CursPos==120)  {SetAbortFlag(BTNSTATE_LONG_PRESSED_EV); }
    else                {SetAbortFlag(BTNSTATE_NONE); }

    MarkPos(K, CursPos, board);

    if (btnhit()) {
      PlayTones(sndBlip);
      key=btnin();
    }
//..............................................................................
//..............................................................................

    if (((key==BTNLEFT) || (key==BTNRIGHT))&&(L==-1)) {
      if (key==BTNLEFT) {
        if (CursPos==0)  CursPos=120;
        else
        if (CursPos>0) {
          CursPos--;
          if (CursPos&8)  CursPos-=8;
        }
      }
      else
      if (key==BTNRIGHT){
        if (CursPos>=120) CursPos=0;
        else
        if (CursPos==119) CursPos=120;  // border field for choice: auto move!
        else {
          CursPos++;
          if ((CursPos)&8) CursPos+=8;
        }
      }
      if (CursPos==120) {
        TextOut(68,32,"     ");
        TextOut(68,24,"     ");
        TextOut(68,16,"     ");
        TextOut(68, 8,"     ");
      }
      else if ((K==-1)&&(CursPos!=120)) {
        TextOut(68,32, SubStr(pieces, board[CursPos]&15,1)+num2anot(CursPos)+"  ");
        printf1(68,16, "K %3d", CursPos);
        printf1(68, 0, "p %3d",board[CursPos]);
      }
      else if (K>=0) {
        TextOut(68,32, SubStr(pieces, board[K]&15,1)+num2anot(K)+num2anot(CursPos));
        printf1(68,16, "K %3d", K);
        printf1(68, 8, "L %3d", CursPos);
        printf1(68, 0, "p %3d", board[CursPos]);
      }
    }

//..............................................................................
//..............................................................................

    else
    if (key==BTNCENTER) {

      if ((K==-1 ) && (L==-1 )) {                      // nothing chosen yet
                                                           // choice = start!
        if (CursPos==120) {                                // auto play
           PlayTones(sndBoop);
           chosen=true;
        }
        else                                               // try to take piece
        {
           if (!board[CursPos]) PlayTones(sndError);        // invalid- empty field
           else
           if (!(board[CursPos]&turn)) PlayTones(sndError); // invalid- not his turn

          else {                                          // K valid chosen
             K=CursPos;
             buf=board[K];
             PlayTones(sndBlipBlip);
             TextOut(68,32, SubStr(pieces, board[K]&15,1)+num2anot(K));
             printf1(68,16, "K %3d", CursPos);
             printf1(68, 0, "p %3d", board[CursPos]);
           }
        }
      }

      else

      if ((K!=-1 ) && (L==-1 )) {                 // start ok, no dest yet

        if (K==CursPos)  PlayTones(sndError);     // choice: invalid (start=dest)


//..............................................................................
        else {                                    // choice: destination
          valid=true;
          ArrayBuild(tboard, board);

          MovePiece(K, CursPos, turn, EP, RK, tboard); // virtual test move
          LK=FindKing(turn,tboard);
//..............................................................................
          // recognizes: discovered check of own king by own piece
          if (FieldInCheck(turn, LK, tboard)) valid=false; // forbidden move

          if (valid) valid=ValidityTest(K,CursPos,turn,board);

          if (valid) {
            PlayTones(sndBeep);

//..............................................................................
            if(valid) L=CursPos;
            if(valid==2) {   EP=1;  }                     // flag: En Passant
            if(valid==3) {   RK=1;  }                     // flag: Castling

            printf1(68, 8, "%4d", L);

            if (((board[L]&7)==4)&& !(board[L]&turn)) {   // dest=opponent King
                    CM=24-(turn);
            }

//..............................................................................
            // recognizes:   KING CAPTURE / CHECK MATE!
            LK=FindKing(OtherTurn,board); // find opponent king at sqr(LK)

            if(L==LK) {                   // opp. king already put in CHECK! ?
              CM=OtherTurn;
              return chosen;              // KING CAPTURE! CHECK MATE!
            }
//..............................................................................
            // recognizes: discovered check of opp. king by own piece
             ArrayBuild(uboard, board);    // copy board for test search
             MovePiece(K, L, turn, buf, buf, uboard);
                                           // opponent king put in CHECK! ??
             buf=FieldInCheck(OtherTurn, LK, uboard);   // LK = opponent king
             if (buf) {
               CK=OtherTurn;
             }
             else CK=0;

          }

//..............................................................................
          else PlayTones(sndError);       // invalid validity test
        }
      }
//..............................................................................
      else
      if ((K!=-1)&&(L!=-1)&&(K!=L))  {    // choice: valid, ready to move
        PlayTones(sndChord);
        chosen=true;
      }
    }

//..............................................................................
//..............................................................................

    else
    if (key==BTNEXIT) {

      if ((K==-1 ) && (L==-1 ) && (CursPos!=120)) {  // Cursor scroll up
        if (!((CursPos-16)&0x88)) CursPos-=16;
        else
        CursPos=CursPos+112;
        TextOut(68,32, SubStr(pieces, board[CursPos]&15,1)+" "+num2anot(CursPos));
        printf1(68,16, "K %3d", CursPos);
        Wait(100);
      }

      if ((K!=-1 ) && (L!=-1 )) {          // choice: undo destination
        PlayTones(sndBuzz);
        L=-1;
        TextOut(68, 16, "      ");
      }
      else
      if ((K!=-1 ) && (L==-1 )) {          // choice: undo choose piece
        PlayTones(sndBuzz);
        K=-1;
        TextOut(68, 24, "      ");
        TextOut(68,  8, "      ");
        board[K]=buf;                      // in case: reset virgin bit
      }
    }

//..............................................................................

    if(CursPos==120)
      TextOut(68, 0," auto");                     // AI auto mode
    else
      printf1(68, 0, "p %3d", board[CursPos]);    // sqr value = piece code
//..............................................................................


    return chosen;
}


tito
Schreibt ab und zu
Schreibt ab und zu
Beiträge: 43
Registriert: 13. Okt 2011 11:56

Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter

Beitragvon tito » 2. Nov 2011 11:10

wirklich cool! was ist das für ein Roboter-Baukasten? Man sieht Lego-Motor(en), hinten ein NXT, aber der Rest ist doch kein Tetrix, oder? Wird dann doch wohl direkt über den NXT gesteuert, oder läuft das über PC-Fernsteuerung?
Und kannst du vielleicht was zu dem Programmcode sagen? Ich werde da nicht recht schlau draus, gebe ich zu :)

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 2. Nov 2011 13:23

jo, danke!
Der Roboter beruht auf Fischertechnik (das ursprüngliche Modell stammt aus den 90ern), die Lego-Motoren sind per Achs-Adapter mit den ft-Elementen verbunden.
Ich finde diesen Roboterarm mit Alu-Elementen genial, er ist mechanisch irrsinnig stabil und exakt, ft hat mE seitdem kaum mehr etwas so geniales auf den Markt gebracht.

Gesteuert wird er vom NXT autonom, also ohne PC dazwischen. Da 4 Motoren plus 2 elektrische Ventile plus eine Pneumatikpumpe bewegt werden müssen, wird ein 2. NXT benötigt, der per BT vom 1. aus gesteuert wird. Da der 2. sowieso für die zusätzliche Mechanik gebraucht wird, benutze ich ihn auch, um die Rechenzeit für die Schachzugberechnungen zu verkürzen (auch über BT), ein 3. und evt. ein 4. kommen vllt noch dazu, damit die Rechenzeit bei entsprechend vielen Ebenen Suchtiefe erträglich wird (derzeit - je nachdem - noch einige Stunden, dann wohl < 1/2 Stunde mit erträglicher Spielstärke). Aber es geht mir hier auch mehr um's Prinzip.

Zum Programm: das ist nicht in 1, 2 Sätzen zu erklären. Es hat über ein Jahr gebraucht, bis ich die Ideen von H.G. Muller zu verstand. Ich hatte lange keine Chance gesehen, sie umsetzen zu können (schon gar nicht ohne Rekursionen) und auch nicht wirklich vorgehabt, ein eigenes Schachprogramm zu schreiben. Irgendwann hat's aber "klick" gemacht und ich konnte anfangen.
H.G. Muller's MicroMax Chess mit seitenweise Erklärungen findest du hier:
http://home.hccnet.nl/h.g.muller/max-src2.html
ABER: es ist nicht geschrieben, um verständlich zu sein, sondern um den Rekord für den minimalistischsten Code zu brechen (1024 Zeichen war sein ursprüngliches Ziel). Daher sehr kryptisch, für manche ist es schlichtweg "obfuscated" (was streng genommen nicht stimmt). Im Gegenteil: Sein Code ist klar durchdacht und die ausführlichen Erläuterungen sind sehr hilfreich.

So habe ich jetzt auch gar nicht versucht, seinen Code zu kopieren, sondern zu verstehen und per NXC selber zu programmieren. Da die Grundideen aber identisch sind, wird man manche Ähnlichkeiten nicht verleugnen können. ;)
Die meisten seiner Optimierungen gehen bei mir aber verloren (z.B. die Hash-Table, die viel Rechenzeit spart, aber auch extrem viel Speicher braucht),
mein eigener Code ist auch sonst sicher exponentiell umständlicher (wenngleich auch exponentiell lesbarer ;) ).
Das "Brett" beruht auf einem 0x88 Board Design (Array mit 128 Länge, quasi "gefaltet", plus ein zusätzliches Dummy-Element), wenn du nach "Schachprogramme/Schachprogrammierung" googelst oder in der Wikipedia suchst, wirst du viel dazu finden.

Spezielle Fragen zu einzelnen Code-Elementen beantworte ich ntl gerne! :)

ps
Habe ich schon woanders mal geschrieben:
"Mein" NXC-Schachprogramm hatte und hat nicht den Anspruch, ein ernstzunehmendes Schachprogramm zu sein und mit "richtigen" Schachprogrammen mithalten zu können (und wird diesen Anspruch auch nie haben), dazu ist NXC einfach viel zu langsam (für ein vernünftiges Schachprogramm müsste es mindestens 1000x so schnell sein, das geht nur mit nativen C-Compilern).
Es war für mich aber ein Test und eine Herausforderung in mehrfacher Hinsicht:
Schaffe ich es, die komplexen Regeln (Figuren mit verschiedenenen Zug-Mustern, einfache/mehrfache Zugfelder per Schritt/Gleiten, Schach bieten/Abzugsschach auslösen und erkennen, Schachmatt feststellen, samt Spezialzügen wie u.a. En-Passant-Schlagen der Bauern und Rochade), plus eine Bewertung von Zügen und ein Suchen über mehrere Zugebenen in die Zukunft, und das noch ohne Rekursionen (die man ja bei NXC leider nicht hat), hinzukriegen? Nun ja, ich denke: zumindest ansatzweise schon. Mehr zu wollen auf der Basis von Legosteinen halte ich momentan, ehrlich gesagt, auch für überzogen.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 2. Nov 2011 14:53

@tito: weil das wegen des Codes vllt in dieselbe Richtung geht wie deine Frage:
hassenplug (in: Mindboards Forum) hat geschrieben:That's pretty cool. I'd be interested to know a couple things:
1) How does it evaluate the board (to determine if a move is "good")
2) How do you plan to distribute the processing across multiple NXTs.

Steve


the evaluation is made by 3 things:
1st, the "piece balance sheet" before/after the move (considering the balance after all deepenings: it's sort of Alpha-Beta-Search);
2nd, if the opponent is put in check (in the previous code weighted too high);
3rd, some other criteria by this subroutine which evaluates the stationing by very simple criteria (they have to be kept simple not to induce completely wrong strategies in some cases):

Code: Alles auswählen

/******************************************************************************/
void Score (char CK, char RK, char &board[]) {
/******************************************************************************/
// scBlackP 104                 // score of piece values
// scBlackS 105                 // score for strategy (positioning)
// scBlackC 106                 // score for check
// scWhiteP 108
// scWhiteS 109
// scWhiteC 110


  float pwi,pbl,    // sum of piece values
        cwi,cbl,    // sum of check values
        swi,sbl;    // sum of strategy values
  int   n,          // current sqr number index
        b,          // square number
        pv,         // piece value
        piece;      // piece type
  char  WiK, BlK;   // flags for king found


  cwi=cbl=pwi=pbl=swi=sbl=0;
  WiK=BlK=false;

  for (n=0;n<120;++n) {
    b=board[n];                              // square number
    piece=b&7;                               // piece type

    if (!(n&0x88)) {                         // valid square
       pv=pvalue[b&piece];                   // piece value

       if (b&8)  {                           // white
         if (pv<0) WiK=true;                 // King found
             else pwi+=pv;                   // add piece value to score
         if ((b&32) && (piece==4)) swi+=1;   // bonus for virgin K
         if ((b&32) && (piece==6)) swi+=0.6; // bonus for virgin R
         if ((piece==1)&&(n<72))   swi+=0.5; // bonus for pawn ahead
         if ((piece==1)&&(n<23))   swi+=1;   // bonus for pawn at opp.side
         if ((piece==1)&&                    // opening: P in center pos
              ( ( (n==68)&& (!board[67]))||( (n==67)&&(!board[68]) ) )
              &&(board[97]&32)&&(board[98]&32)&&(board[101]&32)&&(board[102]&32))
             swi+=2;
         if ((piece==3)&&(n<112)&&(n>8)) ++swi;    // bonus for knight off 1||8
         if ((pv==1)&&(n<8)) swi+=16;   // pawn->Queen (+extra Queen piece value)
       }

       else
       if (b&16) {                           // black
         if (pv<0) BlK=true;                 // King found
             else pbl+=pv;                   // add piece value to score
         if ((b&32) && (piece==4)) sbl+=1;   // bonus for virgin K
         if ((b&32) && (piece==6)) sbl+=0.6; // bonus for virgin R
         if ((piece==2)&&(n>47))   sbl+=0.5; // bonus for pawn ahead
         if ((piece==2)&&(n>95))   sbl+=1;   // bonus for pawn at opp.side
         if ((piece==2)&&                    // opening: P in center pos
              (( (n==51)&&(!board[52]))||((n==52)&&(!board[51])))
              &&(board[17]&32)&&(board[18]&32)&&(board[21]&32)&&(board[22]&32))
             sbl+=2;
         if ((piece==3)&&(n<112)&&(n>8)) ++sbl;    // bonus for knight off 1||8
         if ((pv==1)&&(n>111)) sbl+=16; // pawn->Queen (+extra Queen piece value)
       }
    }
  }


  if((CK & 8)) {cwi=-1;  }
  if((CK &16)) {cbl=-1;  }

  if (!WiK) {pwi=cwi=swi=-120; }  // king capture marker
  if (!BlK) {pbl=cbl=sbl=-120; }

  board[104]=pbl; board[105]=sbl; board[106]=cbl;
  board[108]=pwi; board[109]=swi; board[110]=cwi;

}


The parallelizing is made by the main routine:
on 2 NXTs, it will start the 1st ply search including all follow-up-deepenings on all even fields on the master and on all odd fields on the BT slave.
Having 3 or 4 bricks it will be based on subsets like modulo 3 or 4 so that not 1 brick is supposed to have all the work on the first (or last) 2 ranks at the start.
It waits until all slaves are finished, then it compares the board scores of all subset moves, and takes the best one.
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

HiTek
Schreibt viel
Schreibt viel
Beiträge: 76
Registriert: 5. Mai 2010 10:46

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HiTek » 28. Nov 2011 11:54

Ford,
wau, Respekt! Das Programm kann sich sehen lassen.

Darf ich dich mal was fragen? Wie kriegst du raus, welchen Zug ein Mensch auf dem Schachbrett zieht? Ich hatte bei meinem Schach-Roboter-Versuch zwei Lösungen im Kopf, aber beide verworfen: Die erste war die Verwendung eines DGT-Schachbrettes, bei dem man eine Stellung relativ leicht per PC auslesen kann. Ein DGT-Brett ist aber aber sehr groß, so dass man einen RIESIGEN Schachroboter bauen müsste. Die zweite war die Verwendung einer Bildverarbeitungssoftware mit einer Webcam, was für mich viel zu schwer zum Programmieren wäre. Außerdem müsste man die notwendigen Bildverarbeitungsalgorithmen auf dem Rechner laufen lassen, so dass es mit einer NXT-ohne-PC-Lösung nichts wäre.

Diese Fragen nur aus Neugier...

Grüße, HiTek

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 28. Nov 2011 19:34

hallo,
danke für die Blumen! :)
Wie kriegst du raus, welchen Zug ein Mensch auf dem Schachbrett zieht?

nur dadurch, dass der, der manuell zieht, es auch manuell am NXT eingibt. Damit kennt das Programm Start-und Zielfeld und weiß, wer wann wo steht.

Der Robot kriegt daher die Feldnummern mitgeteilt (nicht im obigen Code enthalten!) und bewegt die Figur entspechend, bei manuellen Zügen genau wie bei automatisch generierten (wenn Zielfeld nicht leer - also beim Schlagen - : vorher fremde Figur abräumen).
Wenn man Figuren selber bewegt ohne es dem NXT mitzuteilen und ohne den NXT dann auch den manuellen Zug durchführen zu lassen, kriegt der ntl nix mit ;)

Ausschnitt aus dem letzten Single-NXT-Programm mit Sensor/Motor-Multiplexern:

Code: Alles auswählen

/******************************************************************************/
//                             Robo-NXT Chess
//                          CHESS ROBOT for NXT
//                    inspired by micro-Max (by G. Muller)
//                    NXC/Bricxcc ab 3.3.8.10 (2011-07-02)
/******************************************************************************/
//string version="459singleNXT"

#include "CHESS_AI_ENGINE.h"

#define debug


/******************************************************************************/
// wire setup ,alias
/******************************************************************************/

char     PCF8574[9];         // to store the  mux touchvalues

#define  SEmergencyTouch  Sensor(S1)
#define  RCXMMux_Port   S2
#define  PPS35_Port     S3
#define  PCF8574_Port   S4

#define  SensorT_TT  PCF8574[1]
#define  SensorT_A1  PCF8574[2]
#define  SensorT_A2  PCF8574[3]
#define  SensorT_Hup PCF8574[4]
#define  SensorT_Hmd PCF8574[5]
#define  SensorT_Hdn PCF8574[6]
#define  SensorT_TT2 PCF8574[7]

#define  OUT_TT      OUT_A  // turn Table
#define  OUT_A1      OUT_B  // shoulder
#define  OUT_A2      OUT_C  // elbow

#define  OUT_HAND    1      // Hand up-med-down (RCX motor) at RCX MMux
#define  OUT_PValve  2      // Claw open-close (EM pneum valve) at RCX MMux
#define  OUT_PPump   3      // pneumatic NXT motor pump at RCX MMux

#define  HAND_MOTOR(speed) OUT_MSMux(RCXMMux_Port, OUT_HAND, speed)
#define  CLAW_MOTOR(speed) OUT_MSMux(RCXMMux_Port, OUT_PValve, speed)
#define  PUMP_MOTOR(speed) OUT_MSMux(RCXMMux_Port, OUT_PPump, speed)

#define  MEnc(m)     MotorRotationCount(m)
#define  SRaw(s)     SensorRaw(s)
#define  STouch(s)   SensorValue(s)


#define  maxTT +5300
#define  minTT -5300
#define  minA1     0
#define  maxA1 +5200
#define  minA2 -5900
#define  maxA2     0


string  clrln="                     ";
string  statusline;


/******************************************************************************/
#define  PCF8574_ADDR 0x4E   // the PCF8574 touch muxer i2c addr

int PCF8574ReadPort(byte NXTPort, byte I2C_ADDR, byte input) {
/******************************************************************************/
    byte cnt = 0x02;
    byte I2CMsg[];
    byte inbuf[];
    byte Address = I2C_ADDR;
    byte nByteReady = 0;
    int  result = -1;
    int loop;

    ArrayBuild(I2CMsg, Address);
    Wait(1);
    while (loop == STAT_COMM_PENDING)   {
          loop = I2CStatus(PCF8574_Port, nByteReady);
    }

    if (I2CBytes(NXTPort, I2CMsg, cnt, inbuf))   {
        result = inbuf[1];
    }

    if( result == (result | (1<<input-1)) )   {
       result = 0;
    }
    else  {
       result = 1;
    }

    if(result==-1) {
      TextOut(0, LCD_LINE7, "Error:PCF8574");
      Wait(500);
      ClearScreen();
    }
    return result;
}




/******************************************************************************/
#define MC_FLOAT      0x00
#define MC_COAST      0x00
#define MC_FORWARD    0x01
#define MC_REVERSE    0x02
#define MC_BRAKE      0x03
#define RCXMMux_ADDR  0xB4




/******************************************************************************/
// OUT_MSMux speed= -100...0...+100 : 0=coast, 1000=break
// muxmot= 1...4
safecall  void OUT_MSMux(char NXTport, byte muxmot, int speed)
/******************************************************************************/
{
  byte motcmd=0;
 
  byte location;
  byte message[20];
  byte nByteReady = 0;

  if (speed>=1000) { motcmd= MC_BRAKE; speed=255; } // <=== special brake value
  else {

    if (speed>0) { motcmd= MC_FORWARD; speed= speed*255/100; }
    else
    if (speed<0) { motcmd= MC_REVERSE; speed=-speed*255/100; }
    else
    if (speed==0) { motcmd= MC_COAST; speed=0; }

    if(speed>255) speed=255;
  }

  location = 0x40 + muxmot*2;
 
  ArrayBuild(message, RCXMMux_ADDR, location, motcmd, speed);
  while (I2CStatus(RCXMMux_Port, nByteReady) ==  STAT_COMM_PENDING);
  I2CWrite(NXTport, 0, message);
  while (I2CStatus(RCXMMux_Port, nByteReady) ==  STAT_COMM_PENDING);

}


/******************************************************************************/
int Menu (string text, string choice) {
/******************************************************************************/
   int BTN;
   ClearScreen();
   TextOut(6*(16-strlen(text))/2,16,text);
   TextOut(6*(16-strlen(choice))/2, 8,choice);
   TextOut(0, 0,"< L  ok/ESC   R >", DRAW_OPT_INVERT);
   BTN=getchar();
   ClearScreen();
   return BTN;

}


/*forward*/ void RobotTransportFromTo(int START, int TARGET, char board[]);

/*forward*/ task DisplayValues();


long tTT[129], tA1[129], tA2[129];                // lookup table for chess sqrs


/******************************************************************************/
// Init +  setup
/******************************************************************************/

/******************************************************************************/
void Init(){
/******************************************************************************/
  SetLongAbort(true);
  ResetSleepTimer();
  SetSleepTimeout(0);
}



/******************************************************************************/
void InitIOports() {
/******************************************************************************/

  SetSensorTouch(S1);                // (default)
  SetSensorTouch(PPS35_Port);        // pneumatic pressure sensor
  SetSensorLowspeed(RCXMMux_Port);   // RCX_RMux  for claw up/md/dn
  SetSensorLowspeed(PCF8574_Port);   //

  SetMotorRegulationTime (10);

}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
float PPS35_PSI (byte port) {return ( -0.0574 * SensorRaw(port) + 56.8); }
int   p_hPa;

task PneumPressurePump()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
   string msg;
  float  PSI;

   while (true) {
    PSI  = PPS35_PSI (PPS35_Port);
    p_hPa= PSI * 68.95;

    if (p_hPa<700)      { PUMP_MOTOR(100);  }
      else if (p_hPa>850) { PUMP_MOTOR( 0 );  }
      
      Wait (500);
  }
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline int checksum(string s) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    int cs=0;
    for (int i=0;i<strlen(s);++i) cs+=s[i];
    return cs;
}


//------------------------------------------------------------------------------
char CmdRdy;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void MotorOff(const byte &port)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
   SetOutput(port, Power, 0,
             OutputMode,  OUT_MODE_COAST,
             RegMode,     OUT_REGMODE_IDLE,
             RunState,    OUT_RUNSTATE_IDLE,
             UpdateFlags, UF_UPDATE_MODE + UF_UPDATE_SPEED);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void Hand_up() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

   CmdRdy=false;

   Wait(1);
   while(!(SensorT_Hup)) {  // dn pos = S3
     HAND_MOTOR(-100);
     Wait(1);
     if (SensorT_Hup) {
        HAND_MOTOR(1024);
        Wait(50);
     }
  }
  HAND_MOTOR(0);
 
  CmdRdy=true;
  Wait(1);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void Hand_md() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  char speed ;

  CmdRdy=false;

  Wait(1);
  while(!(SensorT_Hmd)) {
      if(SensorT_Hdn) speed=-100;
      HAND_MOTOR(speed);
      Wait(1);
      if (SensorT_Hmd) {
        HAND_MOTOR(1024);
        speed=0;
        Wait(50);
      }
  }
  HAND_MOTOR(0);
 
  CmdRdy=true;
  Wait(1);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void Hand_dn() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  CmdRdy=false;

  Wait(1);
  while(!(SensorT_Hdn)) {
      HAND_MOTOR(100);
      Wait(1);
      if (SensorT_Hdn) {
        HAND_MOTOR(1024);
        Wait(50);
      }
  }
  HAND_MOTOR(0);
 
  CmdRdy=true;
  Wait(1);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  Claw_open()  { CLAW_MOTOR(-100); Wait(1); }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  Claw_close() { CLAW_MOTOR( 100); Wait(1); }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void  Claw_idle()  { CLAW_MOTOR(  0 ); Wait(1); }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++




/******************************************************************************/

int  D_=0;     // counter for piece drop area
char F_=1;

/******************************************************************************/
void RobotMovePiece(int &K, int &L, char turn, char &EP, char &RK, char &board[])
/******************************************************************************/
{
   char PP=0;                                                // move from K to L

   if (board[K]&32) board[K]-=32;       // remove virgin flag
   if (board[L]) {
     RobotTransportFromTo(L,127,board); // clear target field
     D_+=16;
     if (D_==128)  D_=1;                // next drop area
     else if (D_==129){ D_=7; F_=-1;}
     else if (D_==134){ D_=8; F_=-1;}
     else if (D_&0x88){ D_=0; F_= 1;}
     tTT[127]=F_*-900+tTT[D_];          // new coord
     tA1[127]=tA1[D_];
     tA2[127]=tA2[D_];
   }

   RobotTransportFromTo(K, L, board);
   board[L]=board[K];                   // move K -> L
   board[K]=0;                          // start K=empty

   if (EP) {                            // E.P. move done
     RobotTransportFromTo(board[board[127]],127,board);   // remove E.P. pawn field
     board[board[127]]=0;               // delete opponent pawn at E.P. sqr
     EP=0;                              // delete E.P.
   }
   else
   if (board[126]!=turn) {
     board[126]=0;                      // delete markers for possible E.P.
     board[127]=0;
     board[128]=0;
   }

   if (RK) {
     RobotTransportFromTo(board[board[124]], board[board[125]] ,board);
     board[board[124]]=board[board[125]]&15;
     board[board[125]]=0;
     board[125]=0;                      // delete markers for castling=Rochade
     board[124]=0;
     RK=0;
   }
}



long TTtarget;
char TTrdy;
//------------------------------------------------------------------------------
task  RotateToTargetTT() {
//------------------------------------------------------------------------------
  char port=OUT_TT, pwr=-80;
  long dabs, oldabs;
  TTrdy=0;

  while (!(inArea(MEnc(port),TTtarget,5))) {
    dabs=abs(MEnc(port)-TTtarget);
    if (dabs>=100) pwr=-80;
    if (dabs <80) pwr=-dabs;
    if (dabs<=40) pwr=-30;

    if ((oldabs<=dabs)&&(dabs<80)) pwr-=20;
    if ((inArea(MEnc(port),TTtarget,5))) { Off(port); Wait(10);}
    else {
     if (MEnc(port)<TTtarget) { OnFwd(port,-pwr);}
     if (MEnc(port)>TTtarget) { OnFwd(port, pwr);}
    }
    Wait(3);
    oldabs=dabs;
  }
  Off(port);
  Wait(50);
  TTrdy= true;
}


long A1target;
char A1rdy;
//------------------------------------------------------------------------------
task  RotateToTargetA1() {
//------------------------------------------------------------------------------
  long dabs, oldabs;
  char port=OUT_A1, pwr=-100;

  A1rdy=0;
  while (!(inArea(MEnc(port),A1target,5))) {
    dabs=abs(MEnc(port)-A1target);
    if (dabs>=100) pwr=-100;
    if (dabs<100) pwr=-dabs;
    if (dabs<=30) pwr=-40;

    if ((oldabs<=dabs)&&(dabs<80)) pwr-=20;
    if ((inArea(MEnc(port),A1target,5))) { Off(port); Wait(10);}
    else {
     if (MEnc(port)<A1target) { OnFwd(port,-pwr);}
     if (MEnc(port)>A1target) { OnFwd(port, pwr);}
    }
    Wait(3);
    oldabs=dabs;
  }
  Off(port);
  Wait(50);
  A1rdy= true;
}


long A2target;
char A2rdy;
//------------------------------------------------------------------------------
task  RotateToTargetA2() {
//------------------------------------------------------------------------------
  long dabs, oldabs;
  char port=OUT_A2, pwr=-100;

  A2rdy=0;
  while (!(inArea(MEnc(port),A2target,5))) {
    dabs=abs(MEnc(port)-A2target);
    if (dabs>=100) pwr=-100;
    if (dabs<100) pwr=-dabs;
    if (dabs<=40) pwr=-40;

    if ((oldabs<=dabs)&&(dabs<80)) pwr-=20;
    if ((inArea(MEnc(port),A2target,5))) { Off(port); Wait(10);}
    else {
     if (MEnc(port)<A2target) { OnFwd(port,-pwr);}
     if (MEnc(port)>A2target) { OnFwd(port, pwr);}
    }
    Wait(3);
    oldabs=dabs;
  }
  Off(port);
  Wait(50);
  A2rdy= true;
}


//------------------------------------------------------------------------------
task ResetTT() {
//------------------------------------------------------------------------------
  char state, speed=70;
  TTrdy=false;
  OnFwd(OUT_TT,-speed);
  until (SensorT_TT || SensorT_TT2);
 
  while(!(state==2)) {
    if (state==0) {
      OnFwd(OUT_TT, speed);
      if (SensorT_TT) {
        Off(OUT_TT);
        Wait(10);
        state=1;
      }
    }
    if (state==1) {
      OnFwd(OUT_TT,-speed);
      Wait(50);
      if (!SensorT_TT) {
        Off(OUT_TT);
        Wait(10);
        state=2;
      }
    }
    Wait(1);
  }
  Wait(200);
  if (state==2) ResetRotationCount(OUT_TT);
  Wait(200); Coast(OUT_TT);
  TTrdy=true;
}


//------------------------------------------------------------------------------
task ResetA1() {
//------------------------------------------------------------------------------
  char state;
  A1rdy=false;
  while(!(state==2)) {
    if (state==0) {
      OnFwd(OUT_A1, -100);
      if (SensorT_A1) {
        Off(OUT_A1);
        Wait(10);
        state=1;
      }
    }
    if (state==1) {
      OnFwd(OUT_A1,70);
      Wait(50);
      if (!SensorT_A1) {
        Off(OUT_A1);
        Wait(10);
        state=2;
      }
    }
    Wait(1);
  }
  Wait(200);
  if (state==2) ResetRotationCount(OUT_A1);
  Wait(200); Coast(OUT_A1);
  A1rdy=1;
}


//------------------------------------------------------------------------------
task ResetA2() {
//------------------------------------------------------------------------------
  char state, speed=100;
  A2rdy=false;
  while(!(state==2)) {
    if ((state==0)&&(MEnc(OUT_A1)<2500)) {
      if (MEnc(OUT_A1)<2500) {OnFwd(OUT_A2, speed);}
      if (SensorT_A2) {
        Off(OUT_A2);
        Wait(10);
        state=1;
      }
    }
    if (state==1) {
      OnFwd(OUT_A2,-70);
      Wait(50);
      if (!SensorT_A2) {
        Off(OUT_A2);
        Wait(10);
        state=2;
      }
    }
    Wait(1);
  }
  Wait(200);
  if (state==2) ResetRotationCount(OUT_A2);
  Wait(200); Coast(OUT_A2);
  A2rdy=1;
}


//------------------------------------------------------------------------------
void InitLookupTable() {
//------------------------------------------------------------------------------
  int p;

//      sqr            OUT_TT               sh.ri             el.le
    p= 119;  tTT[p]= 1050;       tA1[p]=5210;     tA2[p]=-1880; // h1
    p= 118;  tTT[p]=  760;       tA1[p]=4700;     tA2[p]=-2535;
    p= 117;  tTT[p]=  510;       tA1[p]=4690;     tA2[p]=-2600;
    p= 116;  tTT[p]=  250;       tA1[p]=4700;     tA2[p]=-2600; // e1 wht.King
    p= 115;  tTT[p]=  -30;       tA1[p]=4700;     tA2[p]=-2580; // d1 wht.Queen
    p= 114;  tTT[p]= -234;       tA1[p]=4850;     tA2[p]=-2370;
    p= 113;  tTT[p]= -500;       tA1[p]=5020;     tA2[p]=-2140;
    p= 112;  tTT[p]= -740;       tA1[p]=5370;     tA2[p]=-1420; // a1

    p= 103;  tTT[p]= 1080;       tA1[p]=4180;     tA2[p]=-3235; // h2
    p= 102;  tTT[p]=  770;       tA1[p]=3945;     tA2[p]=-3485;
    p= 101;  tTT[p]=  500;       tA1[p]=3930;     tA2[p]=-3535;
    p= 100;  tTT[p]=  200;       tA1[p]=3895;     tA2[p]=-3570; // e2 K.pawn
    p=  99;  tTT[p]= -100;       tA1[p]=3920;     tA2[p]=-3640; // d2 Q.pawn
    p=  98;  tTT[p]= -340;       tA1[p]=3985;     tA2[p]=-3535;
    p=  97;  tTT[p]= -610;       tA1[p]=4180;     tA2[p]=-3375;
    p=  96;  tTT[p]= -830;       tA1[p]=4370;     tA2[p]=-3090; // a2

    p=  87;  tTT[p]= 1160;       tA1[p]=3530;     tA2[p]=-3995; // h3
    p=  86;  tTT[p]=  850;       tA1[p]=3395;     tA2[p]=-4135;
    p=  85;  tTT[p]=  500;       tA1[p]=3200;     tA2[p]=-4220;
    p=  84;  tTT[p]=  240;       tA1[p]=3220;     tA2[p]=-4230;
    p=  83;  tTT[p]=  -80;       tA1[p]=3225;     tA2[p]=-4205;
    p=  82;  tTT[p]= -380;       tA1[p]=3320;     tA2[p]=-4135;
    p=  81;  tTT[p]= -690;       tA1[p]=3455;     tA2[p]=-4035;
    p=  80;  tTT[p]=-1000;       tA1[p]=3630;     tA2[p]=-3830; // a3

    p=  71;  tTT[p]= 1230;       tA1[p]=2905;     tA2[p]=-4455; // h4
    p=  70;  tTT[p]=  930;       tA1[p]=2840;     tA2[p]=-4665;
    p=  69;  tTT[p]=  570;       tA1[p]=2840;     tA2[p]=-4665;
    p=  68;  tTT[p]=  330;       tA1[p]=2655;     tA2[p]=-4730;
    p=  67;  tTT[p]= -130;       tA1[p]=2710;     tA2[p]=-4750; // d4
    p=  66;  tTT[p]= -425;       tA1[p]=2825;     tA2[p]=-4610;
    p=  65;  tTT[p]= -745;       tA1[p]=2870;     tA2[p]=-4525;
    p=  64;  tTT[p]=-1060;       tA1[p]=3180;     tA2[p]=-4330; // a4

    p=  55;  tTT[p]= 1415;       tA1[p]=2380;     tA2[p]=-4970; // h5
    p=  54;  tTT[p]= 1000;       tA1[p]=2210;     tA2[p]=-5080;
    p=  53;  tTT[p]=  605;       tA1[p]=2210;     tA2[p]=-5200;
    p=  52;  tTT[p]=  240;       tA1[p]=2210;     tA2[p]=-5160;
    p=  51;  tTT[p]= -150;       tA1[p]=2160;     tA2[p]=-5160;
    p=  50;  tTT[p]= -490;       tA1[p]=2180;     tA2[p]=-5070;
    p=  49;  tTT[p]= -860;       tA1[p]=2360;     tA2[p]=-4980;
    p=  48;  tTT[p]=-1240;       tA1[p]=2530;     tA2[p]=-4760; // a5

    p=  39;  tTT[p]= 1505;       tA1[p]=2055;     tA2[p]=-5290; // h6
    p=  38;  tTT[p]= 1075;       tA1[p]=1785;     tA2[p]=-5355;
    p=  37;  tTT[p]=  670;       tA1[p]=1610;     tA2[p]=-5410;
    p=  36;  tTT[p]=  300;       tA1[p]=1515;     tA2[p]=-5440;
    p=  35;  tTT[p]= -220;       tA1[p]=1610;     tA2[p]=-5460;
    p=  34;  tTT[p]= -580;       tA1[p]=1730;     tA2[p]=-5450;
    p=  33;  tTT[p]= -970;       tA1[p]=1910;     tA2[p]=-5340;
    p=  32;  tTT[p]=-1300;       tA1[p]=2090;     tA2[p]=-5130; // a6

    p=  23;  tTT[p]= 1700;       tA1[p]=1505;     tA2[p]=-5580; // h7
    p=  22;  tTT[p]= 1230;       tA1[p]=1215;     tA2[p]=-5650;
    p=  21;  tTT[p]=  800;       tA1[p]=1340;     tA2[p]=-5830;
    p=  20;  tTT[p]=  330;       tA1[p]=1120;     tA2[p]=-5770; // e7 K.pawn
    p=  19;  tTT[p]= -180;       tA1[p]=1068;     tA2[p]=-5740; // d7 Q.pawn
    p=  18;  tTT[p]= -660;       tA1[p]=1260;     tA2[p]=-5830;
    p=  17;  tTT[p]=-1095;       tA1[p]=1420;     tA2[p]=-5600;
    p=  16;  tTT[p]=-1480;       tA1[p]=1530;     tA2[p]=-5360; // a7

    p=   7;  tTT[p]= 1975;       tA1[p]=1130;     tA2[p]=-5880; // h8
    p=   6;  tTT[p]= 1480;       tA1[p]= 920;     tA2[p]=-6100;
    p=   5;  tTT[p]=  945;       tA1[p]= 935;     tA2[p]=-6100;
    p=   4;  tTT[p]=  380;       tA1[p]= 900;     tA2[p]=-6100; // e8 blk.King
    p=   3;  tTT[p]= -155;       tA1[p]= 775;     tA2[p]=-5960; // d8 blk.Queen
    p=   2;  tTT[p]= -810;       tA1[p]= 930;     tA2[p]=-5960;
    p=   1;  tTT[p]=-1230;       tA1[p]= 980;     tA2[p]=-5890;
    p=   0;  tTT[p]=-1685;       tA1[p]=1260;     tA2[p]=-5685; // a8

    p= 128;  tTT[p]=    0;       tA1[p]=   0;     tA2[p]=minA2; // align board

    p= 127; tTT[p]=-900+tTT[0];       tA1[p]=tA1[0];   tA2[p]=tA2[0]; // drop area

}

//------------------------------------------------------------------------------
void MoveClawTo(int sqr) {
//------------------------------------------------------------------------------
  statusline= "=>sqr."+NumToStr(sqr);

  if (MEnc(OUT_A1)>=(tA1[sqr]-1000) && (MEnc(OUT_A2)>=tA2[sqr])-1000)  {

    TTtarget=tTT[sqr];    start RotateToTargetTT;
    if(MEnc(OUT_A1)>3000) { A1target=max(tA1[sqr],3000); start RotateToTargetA1; }
    while (!A1rdy);
    A1target=tA1[sqr];    start RotateToTargetA1;
    A2target=tA2[sqr];    start RotateToTargetA2;
  }

  else  {
    TTtarget=tTT[sqr];    start RotateToTargetTT;

    A2target=min(MEnc(OUT_A2)+1000,0);    start RotateToTargetA2;
    Wait(100);
    while (!A2rdy);

    A1target=tA1[sqr];      start RotateToTargetA1;
    A2target=tA2[sqr];      start RotateToTargetA2;
    Wait(100);
  }

  while (!TTrdy);
  while (!A1rdy);
  while (!A2rdy);

  Off(OUT_ABC);
  while(btn (BTNLEFT));
  if(btn (BTNRIGHT)) {
    while(btn (BTNRIGHT));
    tTT[sqr]= MEnc(OUT_TT);     tA1[sqr]=MEnc(OUT_A1);     tA2[sqr]=MEnc(OUT_A2);
    beep(TONE_C6,10);
  }
  Wait(200);

}

//------------------------------------------------------------------------------
inline void CheckSquare(int sqr) {
//------------------------------------------------------------------------------

    Hand_up();      while (!SensorT_Hup);        // hand up!

    MoveClawTo(sqr);  beep(TONE_E5,400);
    Coast(OUT_ABC); Wait(200);

    Hand_dn();  while (!SensorT_Hdn);             // hand down!

    while(!btnhit() );                    // wait until Btn pressed
    if(btn (BTNRIGHT)) {
      tTT[sqr]= MEnc(OUT_TT);     tA1[sqr]=MEnc(OUT_A1);     tA2[sqr]=MEnc(OUT_A2);
      beep(TONE_C6,50);
    }
    if(btn (BTNLEFT)) return;
}

//------------------------------------------------------------------------------
void CalibrateAllSquares() {
//------------------------------------------------------------------------------
  int sqr;
  Claw_open();           // claw open!

  for (sqr=119; sqr>=0; --sqr ) {
    if (sqr & 0x88) continue;
    CheckSquare(sqr);
  }
}


//------------------------------------------------------------------------------
void Calibrate_9_Squares(){
//------------------------------------------------------------------------------
  CheckSquare( 87);
  CheckSquare( 86);
  CheckSquare( 85);
 
  CheckSquare(100);
  CheckSquare( 99);
  CheckSquare( 98);
 
  CheckSquare( 84);
  CheckSquare( 83);
  CheckSquare( 82);

}


//------------------------------------------------------------------------------
void RobotTransportFromTo(int START, int TARGET, char board[]) {
//------------------------------------------------------------------------------
  char BigPiece=0;

  Claw_open();                               // claw open!
  Hand_up();     Wait(10);  while (!SensorT_Hup);         // hand up!



  MoveClawTo(START);  beep(TONE_C3,200);  Coast(OUT_ABC);

  if ( ((board[START]&7)==3)||((board[START]&7)==4)||((board[START]&7)==7) ) {
    BigPiece=1;
    Hand_md();  Wait(10);  while (!SensorT_Hmd);          // hand med
  }
  else {
    Hand_dn();  Wait(10);  while (!SensorT_Hdn);          // hand down!
  }
  beep(TONE_C5,400);  Coast(OUT_ABC);  Wait(200);
 
  Claw_close(); Wait(100);                    // claw close! => grab piece
  Hand_up();    Wait(10);  while (!SensorT_Hup);          // hand up!
 
  MoveClawTo(TARGET);  beep(TONE_C3,200);  Coast(OUT_ABC);
 
  if ( BigPiece ) {
    Hand_md();  Wait(10);  while (!SensorT_Hmd);
  }
  else {
    Hand_dn();  Wait(10);  while (!SensorT_Hdn);
  }

  Claw_open();                   // claw open! => drop piece
  Hand_up();    Wait(10);  while (!SensorT_Hup);         // hand up!
}



//------------------------------------------------------------------------------
void RobotArmsZeroInit() {
//------------------------------------------------------------------------------
   statusline="zero init";

   start ResetTT;
   start ResetA1;
   Wait(4000);
   start ResetA2;

   while(!(TTrdy&&A1rdy&&A2rdy));
   
   statusline="zero ok  ";
}


//------------------------------------------------------------------------------
task DisplayValues() {
//------------------------------------------------------------------------------
  ClearScreen();

  while(1) {
    printf1(0,48,"S1%d",PCF8574[1]); printf1(24,48,"OUT_TT%5d",MEnc(OUT_TT)); printf1(66,48,"run%2d",MotorRunState(OUT_TT));
    printf1(0,40,"S2%d",PCF8574[2]); printf1(24,40,"OUT_A1%5d",MEnc(OUT_A1)); printf1(66,40,"run%2d",MotorRunState(OUT_A1));
    printf1(0,32,"S3%d",PCF8574[3]); printf1(24,32,"OUT_A2%5d",MEnc(OUT_A2)); printf1(66,32,"run%2d",MotorRunState(OUT_A2));
    printf1(0,24,"up%d",PCF8574[4]); printf1(24,24,"md%d",PCF8574[5]); printf1(48,24,"dn%d",PCF8574[6]);
    printf1(0,16,"pr%4d",p_hPa);
    printf1(0, 0,"%s", statusline);
    Wait(10);
  }
}


//------------------------------------------------------------------------------
task GetPCF8574Values() {
//------------------------------------------------------------------------------
  while(true) {
    //Acquire(tmutex);
    for (char i=1; i<9; ++i) {
      PCF8574[i]= PCF8574ReadPort(PCF8574_Port, PCF8574_ADDR, i);
    }
    //Release(tmutex);
    Wait(20);
  }
}


//------------------------------------------------------------------------------
task EmergencyStop() {
//------------------------------------------------------------------------------
  while(true) {
    while (!SEmergencyTouch) {
   
      OUT_MSMux(RCXMMux_Port, 1, 0); Wait(1);
      OUT_MSMux(RCXMMux_Port, 2, 0); Wait(1);
      OUT_MSMux(RCXMMux_Port, 3, 0); Wait(1);
      OUT_MSMux(RCXMMux_Port, 4, 0); Wait(1);
     
      MotorOff(OUT_A); Wait(1);
      MotorOff(OUT_B); Wait(1);
      MotorOff(OUT_C); Wait(1);

      SetSensor(S1, SENSOR_TOUCH); Wait(1); ResetSensor(S1); Wait(1);
      SetSensor(S2, SENSOR_TOUCH); Wait(1); ResetSensor(S2); Wait(1);
      SetSensor(S3, SENSOR_TOUCH); Wait(1); ResetSensor(S3); Wait(1);
      SetSensor(S4, SENSOR_TOUCH); Wait(1); ResetSensor(S4); Wait(1);
     
      StopAllTasks();
    }
    Wait(50);
  }
}



/******************************************************************************/
task main(){
/******************************************************************************/
  char EP,                            // flag: en passant
       RK,                            // flag: castling=Rochade
       CK, CM,                        // flag: check!=Schach! (1&8, 1&16)
       turn,                          // side on turn
       chosen;                        // manual or auto move from stdin input;
  char board[129];                    // Piece K_start-> L_dest
  int K, L,                           // score local, remote
      score, rscore1, rscore2, rscore3, idum, buf;
  char PMOD=0, m1, m2, m3;
  string s;


// init all defauts
  Init();
  InitIOports();
  InitLookupTable();

  start EmergencyStop;
  start GetPCF8574Values;
  start PneumPressurePump;
  start DisplayValues;

// chess robot setup

  Claw_close(); Wait(500);
  Claw_open();  Wait(500);
  Hand_up();    while (!SensorT_Hup);
 

  RobotArmsZeroInit();
  beep(TONE_G5,400);            // <<<< blocks if not outcommented
 
 
  // align board center base line
  Claw_close(); Wait(500);

 
  statusline="=> sqr. 128  ";
  MoveClawTo(128);
 
  beep(TONE_G5,400);           // <<<< blocks if not outcommented
 
  Coast(OUT_ABC); Wait(200);

  // single chess square alignment
  Hand_up();  while (!SensorT_Hup);  Claw_open();

  stop DisplayValues; statusline=clrln;
  buf=Menu("Calibrate ?", "/9  /ALL  /no");

  start DisplayValues;
  if(buf==BTNLEFT)   Calibrate_9_Squares();
  else
  if(buf==BTNCENTER) CalibrateAllSquares();
  Hand_up();  while (!SensorT_Hup);

  stop DisplayValues;
  // finished: "real" chess board setup

  // start "virtual" chess board and Hal AI setup
  EP=RK=CK=CM=0;
  K=-1; L=-1;
  turn= 8;                                     // 8=white begins
  BoardSetup(board);

  ClearScreen();
  PrintBoard (K, L, turn, CK, CM, RK, board);

  while(true){
    chosen=false;                              // get choice auto/manually

    //permanent auto mode: outcomment while loop!
    while (!(chosen=GetHIDinput(K, L, turn, EP, RK, CK, CM, board)));
                                               // (pass move + flags)

    if (L!=-1) {                               // L>=0: manual move chosen
      start DisplayValues;
      RobotMovePiece(K, L, turn, EP, RK, board);
      stop DisplayValues;
    }
    else {                                        // L=-1: auto move required


      score=AutoMove(K, L, turn, EP, RK, CK, CM, board, PMOD);    // auto move (local)

      ClearScreen();

      if(turn==8)s="white"; else s="black";
      TextOut(0,56, s);


#ifdef debug
      getchar();
#endif

      start DisplayValues;
      RobotMovePiece(K, L, turn, EP, RK, board);
      stop DisplayValues;
    }

    ClearScreen();
    if(CM) {
      TextOut(24,40,"GAME OVER");
      TextOut(18,24,"CHECK MATE/");
      TextOut(12,16,"KING CAPTURED");
      beep(TONE_A5,100); beep(TONE_E5,100); beep(TONE_C4,100); beep(TONE_A4,500);
      Wait(1000);
      ClearScreen();
      PrintBoard (K, L, turn, CK, CM, RK, board);
      SetLongAbort(true);
      while(true) {
        MarkPos(-1, FindKing((24-turn),board), board); Wait(200);
      }
    }

    PrintBoard (K, L, (24-turn), CK, CM, RK, board);

    K=-1;
    L=-1;
    CursPos=120;
    turn=24-(turn);          // toggle 8 -> 16 -> 8 ->...

    Wait(1);
  }
}


NXC pseudo-recursive chess-engine:

Code: Alles auswählen

#ifndef CHESS_AI_MOVE_GENERATOR_H

  #define CHESS_AI_MOVE_GENERATOR_H


//string chessversion ="4.24.RoBT.M";
                    // playing manually + automatically  possible
                    // featuring: E.P., Castling, Pawn Promotion
                    // validity test ok! (P+, P-, N, K, B, R, Q)
                    // recognizes: put king in CHECK! (man. + auto)
                    // recognizes: king still in CHECK! => King-Capture !
                    // recognizes: king wants to move to CHECK-threatened sqr
                    // recognizes: discovered check (own + opp. king)
                    // recognizes CHECKMATE
                    // able to move out of CHECK!
                    // auto opening: prefers K.Pawn or Q.Pawn  (d4/e4)

                    // M2 AI auto move generator: 3 complete ply layers

/******************************************************************************/
// (c) H. Wunder 2011
/******************************************************************************/

mutex   tmutex, mmutex, smutex;   //  ToneMutex, MotorMutex, SensorMutex

// (local) char board[129];       // board[sqr-number]= (piece value or (empty=0)


// valid square number: (!= square_number & 0x88), 0<=square_number<=119
// invalid off board i-p file: (square_number & 0x08)
// invalid off board <a/>h rank: (square_number & 0x80)

// white piece:    (board[n] &  8)
// black piece:    (board[n] & 16)
// virgin piece:   (board[n] & 32)
// coloured piece: (board[n] & 15)
// piece type:     (board[n] &  7)     (1,2,3,4,5,6,7)
// sliding piece:  (board[n] &  7) > 4 (5,6,7)
// crawling piece: (board[n] &  7) < 5 (1,2,3,4)
// pawns:          (board[n] &  7) < 3 (1,2)

char pvalue[]={0,2,2,6,-1,7,10,18};// piece value {empty, P+, P-,N, K, B, R, Q}
//piece number:0 1 2 3  4 5  6  7  // Figurenwert: leer,  B+  B- S  K  L  T  D



//string pieces=".?+nkbrq?*?NKBRQ";   // pieces for print; UpperCase=white
  string pieces="-?*skltd?*?SKLTD";   // Figuren-Symbole;  GROSS-Buchstaben=weiß

char dirlst[]={
    16, 15, 17, 0,                    // 0-3:   1=white pawn(up):16=move; 15/17=beat
   -16,-15,-17, 0,                    // 4-7:   2=black pawn(dn):-16;    -15/-17
   14,18,-14,-18,31,33,-31,-33, 0,    // 8-16:  3=knight=Springer
   1,16,15,17,-1,-16,-15,-17,3,-2,0,  // 17-27: 4=king=König
   15,17,-15,-17, 0,                  // 28-32: 5=bishop=Läufer
   1,16,-1,-16, 0,                    // 33-37: 6=rook=Turm
   1,16,15,17,-1,-16,-15,-17, 0};     // 38-46: 7=queen=Dame


char o[]= {0,  0, 4, 8, 17, 28, 33, 38 }; // o[Piece_type]= first dir.in dirlst[]
           //  1  2  3   4   5   6   7
           //  P+ P- N   K   B   R   Q


#define tWHITE (turn==8)
#define tBLACK (turn==16)

#define INFINITY 999

#define mOffb 0x88;                   // mask 136=0x88: board system
#define mRank 0x70;                   // mask 112=0x70: rank mask



#define scBlackP 104                  // score of piece values
#define scBlackS 105                  // score for strategy (positioning)
#define scBlackC 106                  // score for check

#define scWhiteP 108                  // score of piece values
#define scWhiteS 109                  // score for strategy (positioning)
#define scWhiteC 110                  // score for check

#define RookNew  124                  // Rook pos after Castling
#define RookEdge 125                  // Rook pos original before castling

#define EPturn   126                  // turn which makes E.P. move possible
#define EPpawn   127                  // pos of E.P. pawn to be beaten
#define EPdest   128                  // pos of beating pawn after E.P. beat


char AUTOMV_RDY=false;

char fontWi=7, fontHi=8,              // font sizes
     loc[]={0,8,16,24,32,40,48,56};   // lines (files) starting at bottom line
     

/******************************************************************************/
// Basics
/******************************************************************************/

char key;
char CursPos=120;
/******************************************************************************/
string __sval1__;
#define printf1( _x, _y, _format1, _value1) { \
  __sval1__ = FormatNum(_format1, _value1); \
  TextOut(_x, _y, __sval1__); \
}

/******************************************************************************/
#define min(a,b) (a<b?a:b)
/******************************************************************************/
#define max(a,b) (a>b?a:b)

/******************************************************************************/
inline long round(float f)
{ return (f<0?f-0.5:f+0.5); }

/******************************************************************************/
inline char inArea(long x, long v, long thr) {
  return ((x>=v-thr)&&(x<=v+thr));
}


/******************************************************************************/
#define btn(b) ButtonPressed(b, false)

/******************************************************************************/
inline bool btnhit(){
/******************************************************************************/
   char test;
   test=( ButtonPressed(BTN1, false) || ButtonPressed(BTN2, false)
       || ButtonPressed(BTN3, false) || ButtonPressed(BTN4, false));
   return test;
}


/******************************************************************************/
inline char btnin() {
/******************************************************************************/
  char result = -1;

    if (ButtonPressed(BTNCENTER, false))
      result = BTNCENTER;
    else if (ButtonPressed(BTNEXIT, false))
      result = BTNEXIT;
    else if (ButtonPressed(BTNLEFT, false))
      result = BTNLEFT;
    else if (ButtonPressed(BTNRIGHT, false))
      result = BTNRIGHT;

    return result;
}

/******************************************************************************/
string num2anot(int i) {   // field number-> algebr.notation of chess fields
/******************************************************************************/
  char file, rank;
  string sfile, srank;

   file=97+(i&15);            // generates chess square notation, e.g.
   rank=8-(i>>4);             // lower left (112) = a1, lower right (119) = h1
   sfile=" ";                 // upper left ( 0 ) = a8, upper right ( 7 ) = h8
   sfile[0]=file;
   srank=NumToStr(rank);
   return (sfile+srank);
}

/******************************************************************************/
// Sound: PlayTones
/******************************************************************************/

safecall void beep(int frq,int dur) {
   PlayTone(frq, dur); Wait(dur);
}


safecall void PlayTonesSCall(Tone snd[]) {
  Acquire(tmutex);
  PlayTones (snd);
  Release(tmutex);
}


Tone sndBeep[]      = {TONE_G5,200};
Tone sndBeepBeep[]  = {TONE_C5,200 , 0,100, TONE_C5,200};
Tone sndBoop[]      = {TONE_C4,200};
Tone sndChordUp[]   = {TONE_C4,50, TONE_E4,50, TONE_G4,50,
                        TONE_C5,50, TONE_E5,50, TONE_G5,50, TONE_C6,200};
Tone sndChordDn[]   = {TONE_C6,50, TONE_G5,50, TONE_E5,50,
                        TONE_C5,50, TONE_G4,50, TONE_E4,50,  TONE_C4,200};
Tone sndChord[]     = {TONE_C4,50, TONE_E4,50, TONE_G4,50, TONE_C5,50};
Tone sndBlip[]      = {TONE_C7,10 };
Tone sndBlipBlip[]  = {TONE_C7,10, 0,20, TONE_C7,10 };
Tone sndBuzz[]      = {TONE_C4/2, 200 };
Tone sndError[]     = {TONE_C4,50, 0,50, TONE_C4,50, 0,50, TONE_C4,50};
Tone sndTaDaa[]     = {TONE_G4,100, 0,100, TONE_C5,200};
Tone sndTaDoo[]     = {TONE_G4,100, 0,100, TONE_C4,200};
Tone sndFuneral[]   = {TONE_C4,450, 0,50, TONE_C4,450, 0,50, TONE_C4,450, 0,50,
                        TONE_CS4,400, TONE_C4,150, 0,50, TONE_C4,400, TONE_AS3,150,
                        0,50,TONE_AS3,400, TONE_A3,150, 0,50, TONE_AS3,400 };




/******************************************************************************/
void BoardSetup(char &board[]) {
/******************************************************************************/
  char i, j, t;
  string stat, virg, stat6, stat5, stat4, stat3, stat2, stat1, stat0, virg1, virg0;

  // start positionings for testing
  // verschiedene Start-Aufstellungen zum Testen

  stat = "tsldklst" +       // standard
         "bbbbbbbb" +
         "........" +
         "........" +
         "........" +
         "........" +
         "BBBBBBBB" +
         "TSLDKLST" ;

  stat1= "Ls..klst" +       // B x t => pawn->Queen
         ".l.b.b.b" +
         "....b.b." +
         ".b......" +
         "........" +
         "...DS..." +
         "B.BBBBBB" +
         "T...KLST" ;

  stat2= ".....lst" +       // L x s => CHECK!
         ".DL.kb.b" +
         "........" +
         "s...b..." +
         "......b." +
         "....S..." +
         "B.BBBBBB" +
         "T...KLST" ;

  stat3= "tsl.klst" +       // B x t => pawn->Queen
         ".B.b.b.b" +
         "....b.b." +
         ".b......" +
         "d...L..." +
         "...DS..." +
         "B.BBBBBB" +
         "T...KLST" ;

  stat4= "......s." +       // CHECK!
         "k....l.." +
         "........" +
         "........" +
         "......b." +
         "....S..." +
         ".......K" +
         "......S." ;

  stat5= "....l.s." +       // CHECKMATE!
         "k......." +
         "........" +
         "........" +
         ".D....b." +
         "..T.S..." +
         "........" +
         "....K..." ;

  stat6= "......k." +
         "..b..b.." +
         "...t..b." +
         "........" +
         "...t...." +
         "..D....B" +
         "......BK" +
         "........" ;

  // virgin flags : markieren der unberührten Figuren

  virg = "XXXXXXXX" +       // standard flags for standard start pos.
         "XXXXXXXX" +       // Standard-Markierungen für Standard-Startpos.
         "........" +
         "........" +
         "........" +
         "........" +
         "XXXXXXXX" +
         "XXXXXXXX" ;

  virg1= ".XXXXXXX" +       // test flags
         ".....XXX" +
         "........" +
         "........" +
         "........" +
         "........" +
         "XXXXXXXX" +
         "XXXXXXXX" ;

  virg0 = "........" +       // test flags
         ".XXX...X." +
         "........" +
         "........" +
         "........" +
         "........" +
         "......X." +
         "........" ;

  j=0;
  for (i=0; i<64; ++i) {
          if (stat[i]==  46) t= 0;      // .
    else  if (stat[i]== 116) t=6+16;    // t
    else  if (stat[i]==  84) t=6+ 8;    // T
    else  if (stat[i]== 115) t=3+16;    // s
    else  if (stat[i]==  83) t=3+ 8;    // S
    else  if (stat[i]== 108) t=5+16;    // l
    else  if (stat[i]==  76) t=5+ 8;    // L
    else  if (stat[i]== 100) t=7+16;    // d
    else  if (stat[i]==  68) t=7+ 8;    // D
    else  if (stat[i]== 107) t=4+16;    // k
    else  if (stat[i]==  75) t=4+ 8;    // K
    else  if (stat[i]==  98) t=2+16;    // b
    else  if (stat[i]==  66) t=1+ 8;    // B
    else t=0;

    if ((virg[i]>65)&&(t>0)) t+=32;    // 16=black, 8=white, 32=virgin bit
    j=(i%8)+16*(i/8);
    board[j++]=t;
  }
}



/******************************************************************************/
void Score (char CK, char RK, char &board[]) {
/******************************************************************************/
// scBlackP 104                 // score of piece values
// scBlackS 105                 // score for strategy (positioning)
// scBlackC 106                 // score for check
// scWhiteP 108
// scWhiteS 109
// scWhiteC 110


  float pwi,pbl,    // sum of piece values
        cwi,cbl,    // sum of check values
        swi,sbl;    // sum of strategy values
  int   n,          // current sqr number index
        b,          // square number
        pv,         // piece value
        piece;      // piece type
  char  WiK, BlK;   // flags for king found


  cwi=cbl=pwi=pbl=swi=sbl=0;
  WiK=BlK=false;

  for (n=0;n<120;++n) {
    b=board[n];                              // square number
    piece=b&7;                               // piece type

    if (!(n&0x88)) {                         // valid square
       pv=pvalue[b&piece];                   // piece value

       if (b&8)  {                           // white
         if (pv<0) WiK=true;                 // King found
             else pwi+=pv;                   // add piece value to score
         if ((b&32) && (piece==4)) swi+=1;   // bonus for virgin K
         if ((b&32) && (piece==6)) swi+=0.6; // bonus for virgin R
         if ((piece==1)&&(n<72))   swi+=0.5; // bonus for pawn ahead
         if ((piece==1)&&(n<23))   swi+=1;   // bonus for pawn at opp.side
         if ((piece==1)&&                    // opening: P in center pos
              ( ( (n==68)&& (!board[67]))||( (n==67)&&(!board[68]) ) )
              &&(board[97]&32)&&(board[98]&32)&&(board[101]&32)&&(board[102]&32))
             swi+=2;
         if ((piece==3)&&(n<112)&&(n>8)) ++swi;    // bonus for knight off 1||8
         if ((pv==1)&&(n<8)) swi+=16;   // pawn->Queen (+extra Queen piece value)
       }

       else
       if (b&16) {                           // black
         if (pv<0) BlK=true;                 // King found
             else pbl+=pv;                   // add piece value to score
         if ((b&32) && (piece==4)) sbl+=1;   // bonus for virgin K
         if ((b&32) && (piece==6)) sbl+=0.6; // bonus for virgin R
         if ((piece==2)&&(n>47))   sbl+=0.5; // bonus for pawn ahead
         if ((piece==2)&&(n>95))   sbl=+1;   // bonus for pawn at opp.side
         if ((piece==2)&&                    // opening: P in center pos
              (( (n==51)&&(!board[52]))||((n==52)&&(!board[51])))
              &&(board[17]&32)&&(board[18]&32)&&(board[21]&32)&&(board[22]&32))
             sbl+=2;
         if ((piece==3)&&(n<112)&&(n>8)) ++sbl;    // bonus for knight off 1||8
         if ((pv==1)&&(n>111)) sbl+=16; // pawn->Queen (+extra Queen piece value)
       }
    }
  }


  if((CK & 8)) {cwi=-1;  }
  if((CK &16)) {cbl=-1;  }

  if (!WiK) {pwi=cwi=swi=-120; }  // king capture marker
  if (!BlK) {pbl=cbl=sbl=-120; }

  board[104]=pbl; board[105]=sbl; board[106]=cbl;
  board[108]=pwi; board[109]=swi; board[110]=cwi;

}


/******************************************************************************/
// GUI tools: print board and squares on display
/******************************************************************************/

/******************************************************************************/
void MarkPos(int K, int i, char board[]){
/******************************************************************************/
  char x, y, rank, color=0, xp, yp, rankp, colorp=0;
  string cs, ps;

   rank=7-(i>>4);
   y=loc[rank];

   x=11+(i&15)*fontWi;
   cs=SubStr(pieces, board[i]&15,1);

   if (i&8) {cs=" auto"; Wait(50); }
   color=!(board[i]&16);                  // color=?   <<<<<<<<<<<<<<<<
   TextOut(x, y, cs, color?4:0);

   if ((K!=-1 )) {
     rankp=7-(K>>4);

     yp=loc[rankp];
     xp=11+(K&15)*fontWi;

     ps=SubStr(pieces, board[K]&15,1);
     colorp=!(board[i]&16);               // color=?   <<<<<<<<<<<<<<<<
     TextOut(xp, yp, ps, colorp?4:0);

   }

   Wait(150);
   TextOut(x, y, cs, color? 0:4);
   if ((K!=-1 )) TextOut(xp,yp,ps,colorp?0:4);
   Wait(100);

}


/******************************************************************************/
void PrintBoard(char K, char L, char turn, char CK, char CM, char RK, char board[]){
/******************************************************************************/
  int i;
  char x, y, rank, color=0;
  string sp;

  for (i=0;i<121;++i) { // a8=119: highest field number, 120=dummy for auto mode
     rank=7-(i>>4);
     y=loc[rank];

     if (i&8) {
       NumOut(0, y, 8-(i>>4)); // (i&8: new rank=> print rank number, skip the next 7 indices
       i+=7;
     }
     else {             // !(i&8): only the first 8 fields of each rank are valid
       x=11+(i&15)*fontWi;
       sp=SubStr(pieces, board[i]&15,1);  // board[i]&15 : piece on field
       color=!(board[i]&16);               // color=?   <<<<<<<<<<<<<<<<
       TextOut(x, y, sp, color?0:4 );
     }
  }

  Score (CK, RK, board);
  printf1(68,48,"B%4d", board[104]+board[105]+board[106]);      // black score
  printf1(68,40,"W%4d", board[108]+board[109]+board[110]);      // white score

  if ((K>=0)&&(L>=0)) {
    TextOut(68,32, SubStr(pieces, board[L]&15,1)+num2anot(K)+num2anot(L));
    printf1(68,16, "K %3d", K);
    printf1(68, 8, "L %3d", L);

  }
  if (CK&turn) TextOut(68,24, "+");
  if (CM&turn) TextOut(68,24, "++");

  if (tWHITE) { TextOut(68, 56, "white");  }
  else         { TextOut(68, 56, "black");  }
}

/******************************************************************************/
void MovePiece(int &K, int &L, char turn, char &EP, char &RK, char &board[]) {
/******************************************************************************/
  char PP=0;                                                // move from K to L

   if ((K<0)||(L<0)) {                  // debug
     PlayTones(sndError);
     TextOut(68,0, "mov-1");
     //getchar();
     return;
   }

   if (board[K]&32) board[K]-=32;       // remove virgin flag
   board[L]=board[K];                   // move K -> L
   board[K]=0;                          // start K=empty

   if ( ((board[L]&7)<3)&& ((L<8)||(L>111))) {
        board[L]=7+turn;                // pawn promotion -> Queen
        PP=true;
   }

   if (EP) {                            // E.P. move done
     board[board[127]]=0;               // delete opponent pawn at E.P. sqr
     EP=0;                              // delete E.P.
   }
   else
   if (board[126]!=turn) {
     board[126]=0;                      // delete markers for possible E.P.
     board[127]=0;
     board[128]=0;
   }

   if (RK) {
     board[board[124]]=board[board[125]]&15;
     board[board[125]]=0;
     board[125]=0;                      // delete markers for castling=Rochade
     board[124]=0;
     RK=0;
   }
}

/*
#define RookNew  124                  // Rook pos after Castling
#define RookEdge 125                  // Rook pos original before castling

#define EPturn   126                  // turn which makes E.P. move possible
#define EPpawn   127                  // pos of E.P. pawn to be beaten
#define EPdest   128                  // pos of beating pawn after E.P. beat
*/

/******************************************************************************/
// AI tools
/******************************************************************************/

/******************************************************************************/
char FindKing(char turn, char board[]) {
/******************************************************************************/
  char n, tPiece;

  tPiece=4; // 4=King
  for (n=0; n<120; ++n){
     if ( ((board[n]&7)==tPiece) && (board[n]&turn) && !(n&0x88)) return n;
  }
}



/******************************************************************************/
char ValidityTest(char K, char L, char turn, char &board[]) {
/******************************************************************************/
  char tPiece, Piece, j, d,
       delta, adelta,
       leap, aleap, fa, dest,
       curr,
       go;
  char SqrKingThrone, SqrRookEdge;                   // sqr for casteling



  if  (board[L]&turn)    return 0;                   // same color
  if  (K & 0x88)    return 0;                        // off-board
  if  (L & 0x88)    return 0;

  tPiece = board[K] & 7;
  Piece  = board[K] & 15;
  delta=K-L;
  d=o[tPiece];

//..............................................................................
  if ((tPiece==1) || (tPiece==2)) {                  // P+, P- / Bauer

     if ((!board[L])&&(delta==dirlst[d])) return 1;  // empty sq.
     else
     if ((board[K]&32) &&                            // if virgin Pawn
        (!board[L])  &&  (!board[K-dirlst[d]]) &&    // 2 empty sqrs,
        ( delta==2*dirlst[d]))  {
            board[128]=K-dirlst[d];                  // mark E.P. sqr.
            board[127]=K-2*dirlst[d];                // mark E.P. Pawn
            board[126]=turn;                         // mark turn color
                                        return 1;    // target ok
        }
     else
     if  (board[L]) {                                // opponent sq.
       if ( ((delta==dirlst[d+1])
         || ( delta==dirlst[d+2]))
         && ((board[K]&turn)!=(board[L]&turn)))   return 1;
     }
     else
     if  ((L==board[128])   ) {                      // E.P. opponent sq.
                                        return 2;
     }

     return 0;
  }


//..............................................................................
  else
  if (tPiece==3)  {                                         // Knight/Springer
     while(dirlst[d]) {
        if (delta==dirlst[d])           return 1;
        else { ++d;  }
     }
     return 0;
  }


//..............................................................................
  else
  if (tPiece==4)  {                                        // King

     if  (tWHITE)  SqrKingThrone=116;
     else  SqrKingThrone=4;

     if ((L==SqrKingThrone-3)&&(board[K]&32)) {
       SqrRookEdge=SqrKingThrone-4;

       if ((!board[K-1])&&(!board[K-2])&&(!board[K-3])     // empty squares
          &&(board[K]&32)&&(board[SqrRookEdge]&32))        // & virgin R+K
       {                                                   // for left castling
            board[125]=SqrRookEdge;                        // left Castlng rook
            board[124]=SqrRookEdge+2;                      // new rook sqr.
                                        return 3;
       }
     }
     else
     if ((L==SqrKingThrone+2)&&(board[K]&32)) {
       SqrRookEdge=SqrKingThrone+3;

       if ((!board[K+1])&&(!board[K+2])                    // empty squares
         &&(board[K]&32)&&(board[L+1]&32))                 // & virgin R+K
       {                                                   // for right castling
            board[125]=SqrRookEdge;                        // right Castlng rook
            board[124]=SqrRookEdge-2;                      // new rook sqr.
                                        return 3;
       }
     }
     else {
       while(dirlst[d]) {
         if (delta==dirlst[d]) {
           if (((dirlst[d]==3)||(dirlst[d]==-2))&& !(board[K]&32))  ++d;
           else                         return 1;
         }
         else { ++d;  }
       }
     }
  }

//..............................................................................
  else
  if (tPiece>=5)  {                  // Bishop, Rook, Queen (sliding pieces)

     d=o[tPiece];                    // array number for 1st direction for piece
     j=1;
     leap=dirlst[d];
     while(leap) {
       leap=dirlst[d];

       for (j=1; j<8; ++j) {                         // loop over sliding sqrs
         curr=K-j*leap;                              // current sqr number

         if  ((curr&0x88)||(curr<0)||(curr>119))
           { j=8; break; }                           // invalid sqr => break

         else
         if ( board[curr]&turn ) break;              // own piece/sqr => break

         else
         if ( (delta==j*leap) )            return 1; // L found=>ready
         if (board[curr]) { j=8; break; }            // opp.piece => stop inc

       } // for j

       ++d; // next direction in direction list

     } // while dirlst[d]

  }  // if tPiece>=5

}



/******************************************************************************/
// AI: HAL auto move unit
/******************************************************************************/

/******************************************************************************/
char FieldInCheck(char turn, char L, char board[]) {
/******************************************************************************/
  char n, tPiece, OtherTurn, test;

  OtherTurn=24-(turn);

  for(n=0; n<120; ++n) {
    if ((n&0x88)&&(n<104)) n+=8;               // skip off-board squares
    tPiece = board[n]&7;

    if ((board[n] & OtherTurn) && !(n&0x88) )  {
       test=ValidityTest(n, L, OtherTurn, board);
       if(test) return 1;
    }
  }
  return 0;
}

/******************************************************************************/
// deepest ply layer
/******************************************************************************/
/******************************************************************************/
int AutoMove9(int &K, int &L, char turn,     // from K to L, side on turn
              char &EP, char &RK,             // EnPassant, Castling,
              char &CK, char &CM,             // Check!
              char &board[]) {                // board[129], singleEvaluation
/******************************************************************************/
  char pc, pcmax,                             // piece counter
       n,                                     // from-square-number(loop counter)
       dest,                                  // dest-sqr-number n->dest
       tPiece,                                // piece type
       d,                                     // dirlst[d]=direction
       j,                                     // sliding move counter (max leaps)
       bestK, bestL,                          // best move bestL->bestL
       tK, tL,                                // test dummies for K, L
       uK, uL,                                // dummies for next ply uK->LK
       found, ok, go,                         // boolean flags
       tEP, tRK, tCK,                         // dummies for test EP, RK, CK
       uEP, uRK, uCK, uCM,                    // future values for EP, RK, CK, CM
       bEP, bRK, bCK,                         // best values for EP, RK, CK
       delta, leap,                           // delta=K-L, leap=dir in dirlist
       OtherTurn,                             // turn/OtherTurn = whi/blk=8/16
       tThrone, oThrone, buf;                 // king's pos., dummy

  int  tscore,  bscore, uscore,               // score=scoreWhite-scoreBlack
       tvalid, bvalid, uvalid,                // move validity  (test, best)
       scWi, scBl;                            // single WhiteScore, BlackScore

  char tboard[129], uboard[129];              // testboard, dummyboard


  OtherTurn=24-(turn);

  bCK=bestK=bestL=-1;
  dest=pc=found=0;
  Score(CK, RK, board);
  scBl=board[104]+board[105]+board[106];
  scWi=board[108]+board[109]+board[110];

  tscore=bscore=-INFINITY;
  bvalid=1;

//..............................................................................


  pcmax=16;

  for (n=0; ((n<120) && (pc<=pcmax)); ++n) {   // loop over square_number && (pc<=16)

    if ((n&0x88)&&(n<104)) n+=8;               // skip off-board squares

    tPiece = board[n] & 7;

    if ( (board[n]&turn))  {                   // own piece

       ++pc;
       d=o[tPiece];                            // rook=6, d=o[6]=8, dirlst[8]=1

       found=false;                            // no best move found yet

       while (dirlst[d]) {                     // loop over directions

         dest = n - dirlst[d];                           // L = K-leap

         if ((dest&0x88)||(n&0x88)||(n<0)||(n>119) ) {goto WHILE_INC_d9;}
                                                         // dest == off-board
         else {

//..............................................................................
           j=1;                                // search biggest leap sizes
//..............................................................................

           if (tPiece>=5) {   // Bishop,Rook,Queen (Läufer, Turm, Dame)
              ok=true;                                   // sliding peaces
              go=true;
              j=0;
              while ((j<7)&& ok && go)                   // inc j as possible
              {
                 if (go) ++j;
                 else break;

                 ok=false; go=false;                     // init OK-flag
                 leap=j*dirlst[d];                       // new virt. step size
                 dest= n-leap;                           // new virtual dest

                 if ( (dest&0x88)||(dest<0)||(dest>119)||(board[dest]&turn) ){
                     ok=false; go=false;                 // max. dest invalid:
                     if (j>1) --j;
                 }
                 else {                                    // dest on-board
                   if (!(board[dest])) {ok=true; go=true;} // dest sqr empty
                   else
                   if (!(board[dest])&turn ) {ok=true; go=false;} // dest=opponent
                   else {ok=false; go=false; break;}
                 }
              }                                      // if empty j++,
                                                     // if opponent: break (finished)

              leap=j*dirlst[d];                      // new virt. step size
              dest= n-leap;                          // new virtual dest

           }
//..............................................................................

           else
           if (tPiece<3) {    // (1,2)= pawns=Bauern P+, P-
             if (!(board[n]&32)) j=1;                    // normally 1 small step
             else
             if ((board[n]&32)) {            // >>but if virgin pawn
                                                         //  in case:
                if (((board[n]& 8)&& !(board[n-16])&& !(board[n-32]) ) // white P
                ||  ((board[n]&16)&& !(board[n+16])&& !(board[n+32]))) // black P
                  j=2;                                   // 2x straight at start
             }
           }
//..............................................................................
           else  j=1;         // 3=knight=Springer, 4=king=König
                                             // only 1 small step
//..............................................................................
//..............................................................................


//..............................................................................

           while (j>=1)  {                             // loop over sliding sqrs
                                                       // start with max j>=1
             oThrone=FindKing(OtherTurn, board);       // find opponent king

             ArrayBuild(tboard, board);                // copy  origin board
                                                       // for valid+score test
             leap=j*dirlst[d];                         // max possible leap
             dest= n-leap;                             // max distant sqr number

             tK=n;   tL=dest;                            // dummies for move K->L

//..............................................................................
//..............................................................................
             // Quiescence Search
             tvalid=true;
 /*
             if (((board[tK]&7)<5)&&(board[tK]!=3))     // Quick Validity Check
               tvalid=ValidityTest(tK, tL, turn, tboard); // test validity K->L
*/
//..............................................................................
//..............................................................................

             if (!tvalid) {       // test move not valid
               if (j==1)  goto WHILE_INC_d9;            // smallest step invalid
                                                       // => next dir in dirlist
               else goto WHILE_DEC_j9;                  // bigger step invalid
             }                                         // => decrease step size


//..............................................................................
             TextOut(68, 8, SubStr(pieces,board[tK]&15,1));    // piece symbol
             TextOut(74, 8, num2anot(tK)+num2anot(tL));

             if (dest==oThrone) {                      // dest=opponent King   // <<<<<<<<<<<<<<<<<<<<
                  CM=OtherTurn;
                  beep(TONE_C3,200);
                  bvalid=0;
                  goto CHECKMATE9;                        // KING CAPTURE!
             }

//..............................................................................
             if ((dest>=0)&&(dest<120) && (!(tboard[dest]&turn)) ) {
               tK=n;   tL=dest;

               MovePiece(tK, tL, turn, tEP, tRK, tboard);  // virtual test move
//..............................................................................
               // recognizes: forbidden discovered check of own king by own move

               tThrone=FindKing(turn, tboard);
               if (FieldInCheck(turn, tThrone, tboard)) { // forbidden move
                 beep(TONE_C6,10);
                 if (j==1)  goto WHILE_INC_d9;
                 else      goto WHILE_DEC_j9;
               }

//..............................................................................

               ArrayBuild(uboard, tboard);    // copy board for test search

//..............................................................................
            // recognizes: check/discovered check of opp. king by own piece
                                              // opponent king put in CHECK! ?
               buf=FieldInCheck(OtherTurn, oThrone, uboard);
               if (buf)  tCK=OtherTurn;
               else tCK=0;

//..............................................................................

               Score(tCK, tRK, tboard);                // of current ply
               scWi=tboard[108]+tboard[109]+tboard[110]; // white score
               scBl=tboard[104]+tboard[105]+tboard[106]; // black score

               if (tWHITE) tscore=scWi-scBl;              // board score
               else  tscore=scBl-scWi;

//..............................................................................
//..............................................................................
               // no further deepening //
//..............................................................................
//..............................................................................
               if (  (tscore>=bscore))    {

                 if (!(found) || (tscore>bscore)  )
                 {
                   bscore=tscore;                        // store best score
                   bestK=n;                              // store best K
                   bestL=dest;                           // store best L
                   bCK=tCK;                              // store CHECK flag
                 }                                       // 1 better move found
                 found=Random(2);                        // random move
               }

//..............................................................................
             } //
          WHILE_DEC_j9:
             if (j>0) --j;                               // decrease step size j

           }
        WHILE_INC_d9:
           if (dirlst[d]) ++d ;                          // next step direction

         }  // not off-board
       }  // while dirlst>0
     }  // own piece

   }  // for...loop over square_number

   if ((bestL<0)||(bCK)<0) {
     CM=OtherTurn;
     PlayTones(sndBeepBeep);
     bvalid=INFINITY;
     TextOut(68, 0, "CM  9");
     //getchar();
     goto CHECKMATE9;
   }

   K=bestK;  L=bestL;   CK=bCK;                            // reload best move

   if ((board[K]&7)<5) bvalid=ValidityTest(K,L,turn,board);// check for flags


CHECKMATE9:


   return bvalid;                                    // validity code
                                    // 0= invalid; 1=valid; 2=E.P.; 3= Castling
}

/******************************************************************************/
// 2nd ply layer
/******************************************************************************/
/******************************************************************************/
int AutoMove2(int &K, int &L, char turn,     // from K to L, side on turn
              char &EP, char &RK,             // EnPassant, Castling,
              char &CK, char &CM,             // Check!
              char &board[]) {                // board[129], singleEvaluation
/******************************************************************************/
  char pc, pcmax,                             // piece counter
       n,                                     // from-square-number(loop counter)
       dest,                                  // dest-sqr-number n->dest
       tPiece,                                // piece type
       d,                                     // dirlst[d]=direction
       j,                                     // sliding move counter (max leaps)
       bestK, bestL,                          // best move bestL->bestL
       tK, tL,                                // test dummies for K, L
       uK, uL,                                // dummies for next ply uK->LK
       found, ok, go,                         // boolean flags
       tEP, tRK, tCK,                         // dummies for test EP, RK, CK
       uEP, uRK, uCK, uCM,                    // future values for EP, RK, CK, CM
       bEP, bRK, bCK,                         // best values for EP, RK, CK
       delta, leap,                           // delta=K-L, leap=dir in dirlist
       OtherTurn,                             // turn/OtherTurn = whi/blk=8/16
       tThrone, oThrone, buf;                 // king's pos., dummy

  int  tscore,  bscore, uscore,               // score=scoreWhite-scoreBlack
       tvalid, bvalid, uvalid,                // move validity  (test, best)
       scWi, scBl;                            // single WhiteScore, BlackScore

  char tboard[129], uboard[129];              // testboard, dummyboard


  OtherTurn=24-(turn);

  bCK=bestK=bestL=-1;
  dest=pc=found=0;
  Score(CK, RK, board);
  scBl=board[104]+board[105]+board[106];
  scWi=board[108]+board[109]+board[110];

  tscore=bscore=-INFINITY;
  bvalid=1;

//..............................................................................


  pcmax=16;


  for (n=0; ((n<120) && (pc<=pcmax)); ++n) {   // loop over square_number && (pc<=16)

    if ((n&0x88)&&(n<104)) n+=8;               // skip off-board squares

    tPiece = board[n] & 7;

    if ( (board[n]&turn))  {                   // own piece

       ++pc;
       d=o[tPiece];                            // rook=6, d=o[6]=8, dirlst[8]=1

       found=false;                            // no best move found yet

       while (dirlst[d]) {                     // loop over directions

         dest = n - dirlst[d];                           // L = K-leap

         if ((dest&0x88)||(n&0x88)||(n<0)||(n>119) ) {goto WHILE_INC_d2;}
                                                         // dest == off-board
         else {

//..............................................................................
           j=1;                                // search biggest leap sizes
//..............................................................................

           if (tPiece>=5) {   // Bishop,Rook,Queen (Läufer, Turm, Dame)
              ok=true;                                   // sliding peaces
              go=true;
              j=0;
              while ((j<7)&& ok && go)                   // inc j as possible
              {
                 if (go) ++j;
                 else break;

                 ok=false; go=false;                     // init OK-flag
                 leap=j*dirlst[d];                       // new virt. step size
                 dest= n-leap;                           // new virtual dest

                 if ( (dest&0x88)||(dest<0)||(dest>119)||(board[dest]&turn) ){
                     ok=false; go=false;                 // max. dest invalid:
                     if (j>1) --j;
                 }
                 else {                                    // dest on-board
                   if (!(board[dest])) {ok=true; go=true;} // dest sqr empty
                   else
                   if (!(board[dest])&turn ) {ok=true; go=false;} // dest=opponent
                   else {ok=false; go=false; break;}
                 }
              }                                      // if empty j++,
                                                     // if opponent: break (finished)

              leap=j*dirlst[d];                      // new virt. step size
              dest= n-leap;                          // new virtual dest

           }
//..............................................................................

           else
           if (tPiece<3) {    // (1,2)= pawns=Bauern P+, P-
             if (!(board[n]&32)) j=1;                    // normally 1 small step
             else
             if ((board[n]&32)) {            // >>but if virgin pawn
                                                         //  in case:
                if (((board[n]& 8)&& !(board[n-16])&& !(board[n-32]) ) // white P
                ||  ((board[n]&16)&& !(board[n+16])&& !(board[n+32]))) // black P
                  j=2;                                   // 2x straight at start
             }
           }
//..............................................................................
           else  j=1;         // 3=knight=Springer, 4=king=König
                                             // only 1 small step
//..............................................................................
//..............................................................................

           while (j>=1)  {                             // loop over sliding sqrs
                                                       // start with max j>=1
             oThrone=FindKing(OtherTurn, board);       // find opponent king

             ArrayBuild(tboard, board);                // copy  origin board
                                                       // for valid+score test
             leap=j*dirlst[d];                         // max possible leap
             dest= n-leap;                             // max distant sqr number

             tK=n;   tL=dest;                            // dummies for move K->L

//..............................................................................
//..............................................................................
             tvalid=true;
             if (((board[tK]&7)<5)&&(board[tK]!=3))     // Quick Validity Check

               tvalid=ValidityTest(tK, tL, turn, tboard); // test validity K->L

//..............................................................................
//..............................................................................

             if (!tvalid) {       // test move not valid
               if (j==1)  goto WHILE_INC_d2;            // smallest step invalid
                                                       // => next dir in dirlist
               else goto WHILE_DEC_j2;                  // bigger step invalid
             }                                         // => decrease step size

//..............................................................................
             TextOut(68,16, SubStr(pieces,board[tK]&15,1));    // piece symbol
             TextOut(74,16, num2anot(tK)+num2anot(tL));

             if (dest==oThrone) {                      // dest=opponent King   // <<<<<<<<<<<<<<<<<<<<
                  CM=OtherTurn;
                  beep(TONE_C3,200);
                  bvalid=0;
                  goto CHECKMATE2;                        // KING CAPTURE!
             }

//..............................................................................
             if ((dest>=0)&&(dest<120) && (!(tboard[dest]&turn)) ) {
               tK=n;   tL=dest;

               MovePiece(tK, tL, turn, tEP, tRK, tboard);  // virtual test move
//..............................................................................
               // recognizes: discovered check of own king by own piece

               tThrone=FindKing(turn, tboard);
               if (FieldInCheck(turn, tThrone, tboard)) { // forbidden move
                 beep(TONE_C6,10);
                 if (j==1)  goto WHILE_INC_d2;
                 else      goto WHILE_DEC_j2;
               }

//..............................................................................

               ArrayBuild(uboard, tboard);    // copy board for test search

//..............................................................................
           // recognizes: check/discovered check of opp. king by own piece
                                              // opponent king put in CHECK! ??
               buf=FieldInCheck(OtherTurn, oThrone, uboard);
               if (buf)  tCK=OtherTurn;
               else tCK=0;

//..............................................................................
               Score(tCK, tRK, tboard);                // of current ply
               scWi=tboard[108]+tboard[109]+tboard[110]; // white score
               scBl=tboard[104]+tboard[105]+tboard[106]; // black score

               if (tWHITE) tscore=scWi-scBl;              // board score
               else  tscore=scBl-scWi;

//..............................................................................
//..............................................................................
                                                                // 3rd ply
               uK=uL=-1;  uEP=uRK=uCK=uCM=0;
               // ArrayBuild(uboard, tboard);
  /*             uvalid=AutoMove9(uK, uL, OtherTurn, uEP, uRK, uCK, uCM, uboard);

               if (uvalid) {
                 if (uvalid==INFINITY) {tscore=uvalid;}
                 else {
                   MovePiece(uK, uL, OtherTurn, uEP, uRK, uboard);   // calculate:
                   Score(uCK, uRK, uboard);              // score of future ply
                   scWi=uboard[108]+uboard[109]+uboard[110]; // white score
                   scBl=uboard[104]+uboard[105]+uboard[106]; // black score
                   if(tCK& 8) scWi-=3;                 // + current check! score
                   if(tCK&16) scBl-=3;                 // of current ply

                   if (turn==8) uscore=scWi-scBl;            // board score
                   else  uscore=scBl-scWi;
                   tscore=uscore;
                 }

               }
  */
//..............................................................................
//..............................................................................
               if (  (tscore>=bscore))    {

                 if (!(found) || (tscore>bscore)  )
                 {
                   bscore=tscore;                        // store best score
                   bestK=n;                              // store best K
                   bestL=dest;                           // store best L
                   bCK=tCK;                              // store CHECK flag
                 }                                       // 1 better move found
                 found=Random(2);                        // random move
               }

               printf1(68,40,">%4d", bscore);
               TextOut(68,08, " "+num2anot(bestK)+num2anot(bestL)); // best K, L
//..............................................................................
             } //
          WHILE_DEC_j2:
             if (j>0) --j;                               // decrease step size j

           }
        WHILE_INC_d2:
           if (dirlst[d]) ++d ;                          // next step direction

         }  // not off-board
       }  // while dirlst>0
     }  // own piece

   }  // for...loop over square_number

   if ((bestL<0)||(bCK)<0) {
     CM=OtherTurn;
     PlayTones(sndBeepBeep);
     bvalid=INFINITY;
     TextOut(68, 0, "CM 2 ");
     //getchar();
     goto CHECKMATE2;
   }

   K=bestK;  L=bestL;   CK=bCK;  bvalid=1;                 // reload best move

   if ((board[K]&7)<5) bvalid=ValidityTest(K,L,turn,board);// check for flags


CHECKMATE2:


   return bvalid;                                    // validity code
                                    // 0= invalid; 1=valid; 2=E.P.; 3= Castling
}


/******************************************************************************/
// ply layer 1
/******************************************************************************/
safecall int  AutoMove(int &K, int &L, char turn,  // from K to L, side on turn
              char &EP, char &RK,             // EnPassant, Castling,
              char &CK, char &CM,             // Check!
              char &board[], char pmod) {   // board[129], singleEvaluation
/******************************************************************************/
  char pc, pcmax,                             // piece counter
       n,                                     // from-square-number(loop counter)
       dest,                                  // dest-sqr-number n->dest
       tPiece,                                // piece type
       d,                                     // dirlst[d]=direction
       j,                                     // sliding move counter (max leaps)
       bestK, bestL,                          // best move bestL->bestL
       tK, tL,                                // test dummies for K, L
       uK, uL,                                // dummies for next ply uK->LK
       rK, rL,                                // remote move
       found, ok, go,                         // boolean flags
       tEP, tRK, tCK,                         // dummies for test EP, RK, CK
       uEP, uRK, uCK, uCM,                    // future values for EP, RK, CK, CM
       bEP, bRK, bCK,                         // best values for EP, RK, CK
       rEP, rRK, rCK,                         // remote values for EP, RK, CK
       delta, leap,                           // delta=K-L, leap=dir in dirlist
       OtherTurn,                             // turn/OtherTurn = whi/blk=8/16
       tThrone, oThrone, buf;                 // king's pos., dummy

  int  tscore,  bscore, uscore, rscore,       // score=scoreWhite-scoreBlack
       tvalid, bvalid, uvalid,                // move validity  (test, best)
       scWi, scBl;                            // single WhiteScore, BlackScore

  char tboard[129], uboard[129];              // testboard, dummyboard

  printf1(68,48, "%s", "$....");
  printf1(68,40, "%s", ">....");
  printf1(68,32, "%s", "     ");
  printf1(68,24, "%s", "     ");
  printf1(68,16, "%s", "     ");
  printf1(68, 8, "%s", "     ");
  printf1(68, 0, "%s", "     ");


  OtherTurn=24-(turn);

  bCK=bestK=bestL=-1;
  dest=pc=found=0;
  Score(CK, RK, board);
  scBl=board[104]+board[105]+board[106];
  scWi=board[108]+board[109]+board[110];

  tscore=bscore=-INFINITY;
  bvalid=1;

//..............................................................................


  pcmax=16;
  found=false;                            // no best move found yet
  AUTOMV_RDY=0;
 
  for (n=0; ((n<120) && (pc<=pcmax)); ++n) {   // loop over square_number && (pc<=16)
    if ((n&0x88)&&(n<104)) n+=8;               // skip off-board squares
    if(n%3!=pmod) continue;

    tPiece = board[n] & 7;


    if ( (board[n]&turn))  {                   // own piece

       ++pc;
       d=o[tPiece];                            // rook=6, d=o[6]=8, dirlst[8]=1

       while (dirlst[d]) {                     // loop over directions
         dest = n - dirlst[d];                           // L = K-leap

         if ((dest&0x88)||(n&0x88)||(n<0)||(n>119) )
             {goto WHILE_INC_d;}                         // dest == off-board

         else {

//..............................................................................
           j=1;                                // search biggest leap sizes
//..............................................................................

           if (tPiece>=5) {   // Bishop,Rook,Queen (Läufer, Turm, Dame)
              ok=true;                                   // sliding peaces
              go=true;
              j=0;
              while ((j<7)&& ok && go)                   // inc j as possible
              {
                 if (go) ++j;
                 else break;

                 ok=false; go=false;                     // init OK-flag
                 leap=j*dirlst[d];                       // new virt. step size
                 dest= n-leap;                           // new virtual dest

                 if ( (dest&0x88)||(dest<0)||(dest>119)||(board[dest]&turn) ){
                     ok=false; go=false;                 // max. dest invalid:
                     if (j>1) --j;
                 }
                 else {                                    // dest on-board
                   if (!(board[dest])) {ok=true; go=true;} // dest sqr empty
                   else
                   if (!(board[dest])&turn ) {ok=true; go=false;} // dest=opponent
                   else {ok=false; go=false; break;}
                 }
              }                                      // if empty j++,
                                                     // if opponent: break (finished)

              leap=j*dirlst[d];                      // new virt. step size
              dest= n-leap;                          // new virtual dest

           }
//..............................................................................

           else
           if (tPiece<3) {    // (1,2)= pawns=Bauern P+, P-
             if (!(board[n]&32)) j=1;                    // normally 1 small step
             else
             if ((board[n]&32)) {            // >>but if virgin pawn
                                                         //  in case:
                if (((board[n]& 8)&& !(board[n-16])&& !(board[n-32]) ) // white P
                ||  ((board[n]&16)&& !(board[n+16])&& !(board[n+32]))) // black P
                  j=2;                                   // 2x straight at start
             }
           }
//..............................................................................
           else  j=1;         // 3=knight=Springer, 4=king=König
                                             // only 1 small step
//..............................................................................
//..............................................................................

           while (j>=1)  {                             // loop over sliding sqrs
                                                       // start with max j>=1
             oThrone=FindKing(OtherTurn, board);       // find opponent king

             ArrayBuild(tboard, board);                // copy  origin board
                                                       // for valid+score test
             leap=j*dirlst[d];                         // max possible leap
             dest= n-leap;                             // max distant sqr number

             tK=n;   tL=dest;                          // dummies for move K->L

//..............................................................................
//..............................................................................
             tvalid=true;
             if (((board[tK]&7)<5)&&(board[tK]!=3))     // Quick Validity Check
                tvalid=ValidityTest(tK, tL, turn, tboard); // test validity K->L

             TextOut(68,32, SubStr(pieces,board[tK]&15,1));    // piece symbol
             TextOut(74,32, num2anot(tK)+num2anot(tL));

//..............................................................................
//..............................................................................

             if (!tvalid) {       // test move not valid
               if (j==1)  goto WHILE_INC_d;            // smallest step invalid
                                                       // => next dir in dirlist
               else goto WHILE_DEC_j;                  // bigger step invalid
             }                                         // => decrease step size

//..............................................................................

             if (dest==oThrone)                {       // dest=opponent King
                  CM=OtherTurn;
                  beep(TONE_A4,200);
                  bvalid=0;
                  goto CHECKMATE;                        // KING CAPTURE!
             }

//..............................................................................
             if ((dest>=0)&&(dest<120) && (!(tboard[dest]&turn)) ) {
               tK=n;   tL=dest;

               MovePiece(tK, tL, turn, tEP, tRK, tboard);  // virtual test move
//..............................................................................
            // recognizes: discovered check of own king by own piece

               tThrone=FindKing(turn, tboard);
               if (FieldInCheck(turn, tThrone, tboard)) { // forbidden move
                 beep(TONE_C6,10);
                 if (j==1)  goto WHILE_INC_d;
                 else      goto WHILE_DEC_j;
               }

//..............................................................................

               ArrayBuild(uboard, tboard);          // copy board for deepening
//..............................................................................
            // recognizes: check/discovered check of opp. king by own piece
                                                // opponent king put in CHECK! ?
               buf=FieldInCheck(OtherTurn, oThrone, uboard);
               if (buf)  tCK=OtherTurn;
               else tCK=0;

//..............................................................................
               Score(tCK, tRK, tboard);                // of current ply
               scWi=tboard[108]+tboard[109]+tboard[110]; // white score
               scBl=tboard[104]+tboard[105]+tboard[106]; // black score

               if (tWHITE) tscore=scWi-scBl;              // board score
               else  tscore=scBl-scWi;
//..............................................................................
//..............................................................................
                                                      // 2nd ply
               uK=uL=-1;  uEP=uRK=uCK=uCM=0;
               uvalid=AutoMove2(uK, uL, OtherTurn, uEP, uRK, uCK, uCM, uboard);

               if (uvalid) {
                   if (uvalid==INFINITY) {tscore=uvalid;}
                   else {
                     MovePiece(uK, uL, OtherTurn, uEP, uRK, uboard);   // calculate:
                     Score(uCK, uRK, uboard);              // score of future ply

                     scWi=uboard[108]+uboard[109]+uboard[110]; // white score
                     scBl=uboard[104]+uboard[105]+uboard[106]; // black score
                     if(tCK& 8) scWi-=1;                 // + current check! score
                     if(tCK&16) scBl-=1;                 // of current ply

                     if (tWHITE) uscore=scWi-scBl;            // board score
                     else  uscore=scBl-scWi;                    // Beta Search
                     tscore=uscore;
                   }
               }

//..............................................................................
//..............................................................................
                                                     // search for best move

               if (  (tscore>=bscore))    {             // eq/better best score
                 if ( !found || (tscore>bscore) )      // prefer if better move
                 {
                   bscore=tscore;                       // store best score
                   bestK=n;                             // store best K
                   bestL=dest;                          // store best L
                   bCK=tCK;                             // store CHECK flag
                 }
                 found=Random(2);                       // 1 better move found
               }

             printf1(68,48,"$%4d", bscore);
             TextOut(68,24, " "+num2anot(bestK)+num2anot(bestL)); // best K, L
             //PlayTones(sndBlip);
             printf1(68, 0,"?%4d", tscore);
             //getchar();

             if (bscore==INFINITY) {CM=OtherTurn; goto FINISHED;}
//..............................................................................
             } //
          WHILE_DEC_j:
             if (j>0) --j;                               // decrease step size j

           }
        WHILE_INC_d:
           if (dirlst[d]) ++d ;                          // next step direction

         }  // not off-board
       }  // while dirlst>0
     }  // own piece

   }  // for...loop over square_number

FINISHED:
   if ( (bestL<0) || (bCK<0) ) {
     CM=OtherTurn;
     PlayTones(sndTaDaa);
     TextOut(68,0, "SM ++");
     goto CHECKMATE;
   }

   K=bestK;  L=bestL;   CK=bCK;                            // reload best move

   if ((board[K]&7)<5) bvalid=ValidityTest(K,L,turn,board);// check for flags


CHECKMATE:
   TextOut(68,32, "     ");  //
   TextOut(68,24, "     ");  //
   TextOut(68,16, "     ");  //
   TextOut(68, 8, "     ");  //

   if ((K>=0)&&(L>=0)) {
     TextOut(68,40, SubStr(pieces,board[K]&15,1));  // piece symbol
     TextOut(74,40, num2anot(K)+num2anot(L));       //  best move
   }
   if (CK&OtherTurn) TextOut(68,24, "+");
   if (CM&OtherTurn) {
     TextOut(68,24, "++");
     TextOut(68,16, "CHECK");
     TextOut(68,08, " MATE ");
     PlayTones(sndChord);
   }
   if(board[L]) TextOut(80,24, "X");
   TextOut(68, 0, "press");
   beep(TONE_G5,200);
   //getchar();
   beep(TONE_C6,10);

   AUTOMV_RDY=1;
   return bscore;                                 //

}


/******************************************************************************/
// HID unit:    choose - |auto mode|  - or -  |take piece manually|
/******************************************************************************/

/******************************************************************************/
char GetHIDinput(int &K, int &L, char turn,
                 char &EP, char &RK, char &CK, char &CM, char &board[]){
/******************************************************************************/
    char valid, buf, chosen,
         uK, LK, OtherTurn, tboard[129], uboard[129];;

//..............................................................................
    key=-1;
    chosen=false;
    OtherTurn=24-(turn);

    if  (CursPos==120)  {SetAbortFlag(BTNSTATE_LONG_PRESSED_EV); }
    else                {SetAbortFlag(BTNSTATE_NONE); }

    MarkPos(K, CursPos, board);

    if (btnhit()) {
      beep(TONE_C6,10);
      key=btnin();
    }
//..............................................................................
//..............................................................................

    if (((key==BTNLEFT) || (key==BTNRIGHT))&&(L==-1)) {
      if (key==BTNLEFT) {
        if (CursPos==0)  CursPos=120;
        else
        if (CursPos>0) {
          CursPos--;
          if (CursPos&8)  CursPos-=8;
        }
      }
      else
      if (key==BTNRIGHT){
        if (CursPos>=120) CursPos=0;
        else
        if (CursPos==119) CursPos=120;  // border field for choice: auto move!
        else {
          CursPos++;
          if ((CursPos)&8) CursPos+=8;
        }
      }
      if (CursPos==120) {
        TextOut(68,32,"     ");
        TextOut(68,24,"     ");
        TextOut(68,16,"     ");
        TextOut(68, 8,"     ");
      }
      else if ((K==-1)&&(CursPos!=120)) {
        TextOut(68,32, SubStr(pieces, board[CursPos]&15,1)+num2anot(CursPos)+"  ");
        printf1(68,16, "K %3d", CursPos);
        printf1(68, 0, "p %3d",board[CursPos]);
      }
      else if (K>=0) {
        TextOut(68,32, SubStr(pieces, board[K]&15,1)+num2anot(K)+num2anot(CursPos));
        printf1(68,16, "K %3d", K);
        printf1(68, 8, "L %3d", CursPos);
        printf1(68, 0, "p %3d", board[CursPos]);
      }
    }

//..............................................................................
//..............................................................................

    else
    if (key==BTNCENTER) {

      if ((K==-1 ) && (L==-1 )) {                      // nothing chosen yet
                                                           // choice = start!
        if (CursPos==120) {                                // auto play
           beep(TONE_A3,200);
           chosen=true;
        }
        else                                               // try to take piece
        {
           if (!board[CursPos]) beep(TONE_G4,200);        // invalid- empty field
           else
           if (!(board[CursPos]&turn)) beep(TONE_G4,200); // invalid- not his turn

          else {                                          // K valid chosen
             K=CursPos;
             buf=board[K];
             beep(TONE_G6,10);
             TextOut(68,32, SubStr(pieces, board[K]&15,1)+num2anot(K));
             printf1(68,16, "K %3d", CursPos);
             printf1(68, 0, "p %3d", board[CursPos]);
           }
        }
      }

      else

      if ((K!=-1 ) && (L==-1 )) {                 // start ok, no dest yet

        if (K==CursPos)  beep(TONE_G4,200);     // choice: invalid (start=dest)


//..............................................................................
        else {                                    // choice: destination
          valid=true;
          ArrayBuild(tboard, board);

          MovePiece(K, CursPos, turn, EP, RK, tboard); // virtual test move
          LK=FindKing(turn,tboard);
//..............................................................................
          // recognizes: discovered check of own king by own piece
          if (FieldInCheck(turn, LK, tboard)) valid=false; // forbidden move

          if (valid) valid=ValidityTest(K,CursPos,turn,board);

          if (valid) {
            beep(TONE_A4,200);

//..............................................................................
            if(valid) L=CursPos;
            if(valid==2) {   EP=1;  }                     // flag: En Passant
            if(valid==3) {   RK=1;  }                     // flag: Castling

            printf1(68, 8, "%4d", L);

            if (((board[L]&7)==4)&& !(board[L]&turn)) {   // dest=opponent King
                    CM=24-(turn);
            }

//..............................................................................
            // recognizes:   KING CAPTURE / CHECK MATE!
            LK=FindKing(OtherTurn,board); // find opponent king at sqr(LK)

            if(L==LK) {                   // opp. king already put in CHECK! ?
              CM=OtherTurn;
              return chosen;              // KING CAPTURE! CHECK MATE!
            }
//..............................................................................
            // recognizes: discovered check of opp. king by own piece
             ArrayBuild(uboard, board);    // copy board for test search
             MovePiece(K, L, turn, buf, buf, uboard);
                                           // opponent king put in CHECK! ??
             buf=FieldInCheck(OtherTurn, LK, uboard);   // LK = opponent king
             if (buf) {
               CK=OtherTurn;
             }
             else CK=0;

          }

//..............................................................................
          else PlayTones(sndError);       // invalid validity test
        }
      }
//..............................................................................
      else
      if ((K!=-1)&&(L!=-1)&&(K!=L))  {    // choice: valid, ready to move
        beep(TONE_A3,600);
        chosen=true;
      }
    }

//..............................................................................
//..............................................................................

    else
    if (key==BTNEXIT) {

      if ((K==-1 ) && (L==-1 ) && (CursPos!=120)) {  // Cursor scroll up
        if (!((CursPos-16)&0x88)) CursPos-=16;
        else
        CursPos=CursPos+112;
        TextOut(68,32, SubStr(pieces, board[CursPos]&15,1)+" "+num2anot(CursPos));
        printf1(68,16, "K %3d", CursPos);
        Wait(100);
      }

      if ((K!=-1 ) && (L!=-1 )) {          // choice: undo destination
        beep(TONE_C3,100);
        L=-1;
        TextOut(68, 16, "      ");
      }
      else
      if ((K!=-1 ) && (L==-1 )) {          // choice: undo choose piece
        beep(TONE_C3,100);
        K=-1;
        TextOut(68, 24, "      ");
        TextOut(68,  8, "      ");
        board[K]=buf;                      // in case: reset virgin bit
      }
    }

//..............................................................................

    if(CursPos==120)
      TextOut(68, 0," auto");                     // AI auto mode
    else
      printf1(68, 0, "p %3d", board[CursPos]);    // sqr value = piece code
//..............................................................................


    return chosen;
}



// task main()  {}


#endif

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 11. Jan 2012 21:00

Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 17. Jan 2015 15:21

Update:

Ich habe den minimalistischen Micro-Max-Code von H.G. Muller auf den Arduino Due (und Mega) portiert.
Er läuft hunderte Male so schnell wie auf dem NXT mit dem NXC-Code und kann künftig anstelle des NXTs als Move Generator die Züge für den Schachroboter berechnen!

Wer jetzt mal ein bisschen Schach spielen (testen) möchte auf einem Arduino Due (oder, speichermäßig etwas abgespeckt, auf einem Arduino Mega) mit wirklich akzeptabler Spielstärke bei erträglicher Denkzeit mit bis zu 400000 durchgerechneten Zügen für max 80000 Knoten und bis zu 8 Halbzügen Denktiefe (willkürlich begrenzt zur Limitierung der "Denkzeit"), etwas "grafisch" aufgepimpt, hier ist der Code - einfach Sketch starten, Code reinkopieren, compilieren + auf Arduino per Tastatur und seriellem PC-Terminal spielen (natürlich ohne Roboterarm! ;) ):

Code: Alles auswählen

/***************************************************************************/
/*                               micro-Max,                                */
/* A chess program orig. <  2 KByte (of non-blank source), by H.G. Muller  */
/***************************************************************************/
/* version 4.8.n Sketch (1953 characters) features:                        */
/* - recursive negamax search                                              */
/* - all-capture MVV/LVA quiescence search                                 */
/* - (internal) iterative deepening                                        */
/* - best-move-first 'sorting'                                             */
/* - a hash table storing score and best move                              */
/* - futility pruning                                                      */
/* - king safety through magnetic, frozen king in middle-game              */
/* - R=2 null-move pruning                                                 */
/* - keep hash and repetition-draw detection                               */
/* - better defense against passers through gradual promotion              */
/* - extend check evasions in inner nodes                                  */
/* - reduction of all non-Pawn, non-capture moves except hash move (LMR)   */
/* - full FIDE rules (expt under-promotion) and move-legality checking     */

// Code für Arduino Due


#define K(A,B) *(int*)(T+A+(B&8)+S*(B&7))

#define HTsize (1<<12) //  wegen RAM, für PC: (1<<24) // <<<<<<  für Arduino Mega verkleinern auf 1<<8 ! 

struct HTab {
          int  K,
               V;
          int  X,
               Y,
               D;
        } HTarray[HTsize];           /* hash table, HTsize entries*/
       
       
#define MAXNODES 80000   //  wegen Zugdauer; für PC: x10 = 800000 = 8e5   // <<<<<<  für Mega verkleinern auf 10000! 

int  K,   
     Q,
     R,
     J,
     Z;
     
int32_t    N,
     I=80000;                         /* I=80000: "infinity score" */ ;                       

int
    M=136,                           /* M=0x88   board system    */
    S=128,                           /* dummy square 0x80, highest valid square =127    */
    turn=16;                         // 16=Weiss, 8=Schwarz; turn^=24 wechselt hin unnd her             

signed char  L,
     pval[]={0,2,2,7,-1,8,12,23},                      /* relative piece values    */
     vector[]={-16,-15,-17,0,1,16,0,1,16,15,17,0,14,18,31,33,0, /* step-vector lists */
          7,-1,11,6,8,3,6},                          /* 1st dir. in vector[] per piece*/
     
     bsetup[]={6,3,5,7,4,5,3,6},                         /* initial piece setup      */
     board[129],                                        /* board: half of 16x8+dummy*/
     T[1035];                                        /* hash translation table   */

signed char  psymbol[]= ".?+nkbrq?*?NKBRQ";

int  mfrom, mto;    // current ply from - to
int  EPSQ,           // e.p. square
     RemP;           // remove piece




/* recursive minimax search, turn=moving side, n=depth*/

int  Minimax(int32_t  q, int32_t  l, int32_t  score, int  EPC, int  prev, int32_t  hashkey)         
                       /* (q,l)=window, score, EnPass_sqr.*/
                       /* prev=prev.dest; J,Z=hashkeys; return score*/
{
   int  j,
        r,
        m,
        v,
        d,
        h,
        i,
        F,
        G,
        V,
        P,
        f=J,
        g=Z,
        C,
        s;
   signed char  t,
        p,
        upiece,
        x,
        y,
        X,
        Y,
        H,
        B;
   
   struct HTab *a = HTarray + (J + turn * EPC & HTsize-1);   /* lookup pos. in hash table*/
 
   char sbuf[50];
 
 
 
   q--;                                          /* adj. window: delay bonus */
   turn^=24;                                        /* change sides             */
   d=a->D;
   m=a->V;
   X=a->X;
   Y=a->Y;                  /* resume at stored depth   */
   
   if(a->K-Z|prev|                                  /* miss: other pos. or empty*/
      !(m<=q | X&8&&m>=l | X&S))                   /*   or window incompatible */
      { d=Y=0; }                                /* start iter. from scratch */
   
   X&=~M;                                        /* start at best-move hint  */
 
   while( d++ < hashkey || d<3                   /* iterative deepening loop */
     || prev&K == I
       && ( N<60000 & d<98                        /* root: deepen upto time   */
          || (K=X, L=Y&~M, d=3)
       )
     )                                          /* time's up: go do best    */
   {
      x=B=X;                                       /* start scan at prev. best */
      h=Y&S;                                       /* request try noncastl. 1st*/
      P=d<3 ? I : Minimax(-l,1-l,-score,S,0,d-3);               /* Search null move         */
      m = (-P<l | R>35) ? ( d>2 ? -I : score ) : -P;            /* Prune or stand-pat       */
      N++;                                         /* node count (for timing)  */
      do
      {
         upiece=board[x];                                   /* scan board looking for   */
         if(upiece & turn)                                  /*  own piece (inefficient!)*/
         {
            r = p = upiece&7;                               /* p = piece type (set r>0) */
            j = vector[p+16];                                 /* first step vector f.piece*/
            while(r = p>2 & r<0 ? -r : -vector[++j] )       /* loop over directions vector[] */
            {
labelA:                                        /* resume normal after best */
               y=x;                            /* (x,y)=move         */
               F=G=S;                          /* (F,G)=castl.R      */
               
               do
               {                                       /* y traverses ray, or:     */
                  H=y=h?Y^h:y+r;                           /* sneak in prev. best move */
                 
                  if(y&M)break;                            /* board edge hit           */
                 
                  m= EPC-S&board[EPC]&&y-EPC<2&EPC-y<2?I:m;      /* bad castling             */
                 
                  if(p<3&y==EPC)H^=16;                           /* shift capt.sqr. H if e.p.*/
                 
                  t=board[H];
                 
                  if(t&turn|p<3&!(y-x&7)-!t)break;            /* capt. own, bad pawn mode */
                  i=37*pval[t&7]+(t&192);                     /* value of capt. piece t   */
                  m=i<0?I:m;                                  /* K capture                */
                 
                  if(m>=l&d>1) goto labelC;                     /* abort on fail high       */
           
                  v=d-1?score:i-p;                             /* MVV/LVA scoring          */
                 
                  if(d-!t>1)                               /* remaining depth          */
                  {
                     v=p<6?board[x+8]-board[y+8]:0;                  /* center positional pts.   */
                     board[G]=board[H]=board[x]=0;board[y]=upiece|32;             /* do move, set non-virgin  */
                     if(!(G&M))board[F]=turn+6,v+=50;               /* castling: put R & score  */
                     v-=p-4|R>29?0:20;                              /* penalize mid-game K move */
                     
                     if(p<3)                                        /* pawns:                   */
                     {
                        v-=9*((x-2&M||board[x-2]-upiece)+              /* structure, undefended    */
                               (x+2&M||board[x+2]-upiece)-1            /*        squares plus bias */
                              +(board[x^16]==turn+36))                 /* kling to non-virgin King */
                              -(R>>2);                                 /* end-game Pawn-push bonus */
                         V=y+r+1&S?647-p:2*(upiece&y+16&32);           /* promotion or 6/7th bonus */
                         board[y]+=V;
                         i+=V;                                         /* change piece, add score  */
                     }
                     
                     v+= score+i;
                     V=m>q ? m : q;                           /* new eval and alpha       */
                     J+=K(y+0,board[y])-K(x+0,upiece)-K(H+0,t);
                     Z+=K(y+8,board[y])-K(x+8,upiece)-K(H+8,t)+G -S;  /* update hash key          */
                     C=d-1-(d>5&p>2&!t&!h);
                     C=R>29|d<3|P-I?C:d;                     /* extend 1 ply if in check */
                     do {
                        s=C>2|v>V?-Minimax(-l,-V,-v,         /* recursive eval. of reply */
                                            F,0,C):v;        /* or fail low if futile    */
                     } while( s>q & ++C<d );
                   
                     v=s;
                     if(prev&&K-I&&v+I&&x==K&y==L)              /* move pending & in root:  */
                     {
                        Q=-score-i; EPSQ=F;                            /*   exit if legal & found  */
                        a->D=99;a->V=0;                        /* lock game in hash as draw*/
                        R+=i>>7;
                        return l;                            /* captured non-P material  */
                     }
                     J=f;
                     Z=g;                                    /* restore hash key         */
                     board[G]=turn+6;
                     board[F]=board[y]=0;
                     board[x]=upiece;
                     board[H]=t;                             /* undo move,G can be dummy */
                  }
                  if(v>m)                                  /* new best, update max,best*/
                  {
                     m=v,X=x,Y=y|S&F;                      /* mark double move with S  */
                  }                       
                  if(h)
                  {
                     h=0;
                     goto labelA;                           /* redo after doing old best*/
                  }                 
                  if (
                    x+r-y|upiece&32|                             /* not 1st step,moved before*/
                    p>2 & (
                      p-4|j-7||                             /* no P & no lateral K move,*/
                      board[G=x+3^r>>1&7]-turn-6            /* no virgin R in corner G, */
                      || board[G^1] | board[G^2] )          /* no 2 empty sq. next to R */
                    )
                  {
                     t+=p<5;
                  }                                        /* fake capt. for nonsliding*/
                  else F=y;                                /* enable e.p.              */
                 
               } while(!t);                               /* if not capt. continue ray*/
         
            }
         }  // (upiece & turn)
     
      } while((x=x+9&~M)-B);                       /* next sqr. of board, wrap */
   
labelC:
      if (m>I-M|m<M-I) d=98;                       /* mate holds to any depth  */
      m= m+I|P==I ? m : 0;                         /* best loses K: (stale)mate*/
     
      if(a->D<99) {                                /* protect game history     */
         a->K=Z;
         a->V=m;
         a->D=d;                       /* always store in hash tab */
         a->X=X|8*(m>q)|S*(m<l);
         a->Y=Y;                       /* move, type (bound/exact),*/
      }
      /* uncomment for Kibitz */
      //if(prev) sprintf(sbuf, "%2d ply, %9d searched, score=%6d by %c%c%c%c\n",
      //     d-1, N-S, m, 'a'+(X&7),'8'-(X>>4),'a'+(Y&7),'8'-(Y>>4&7));   
       
       if(prev  && X!=Y) {   
         sprintf(sbuf, "\n%2d ply, searched: %9d ", d-1, N-S );
         Serial.print(sbuf);
       }
       else
       if( ((N-S)%10000)<1) Serial.print(".");
       
     
   }  // while (iterative deepening loop)                                           
 
   turn^=24;                                        /* change sides back        */
   mfrom=K; mto=L;
   return m+= m<score;                                  /* delayed-loss bonus       */
}





void chess()
{
   int32_t       score, i;
   int16_t       oldto, oldEPSQ;
   char          sbuf[50], sbuf2[50];
   char          cstring[20];
   signed char   oboard[129], spiece;
 
   
   K=8;
   while(K--)
   {
      board[K]=(board[K+112]=bsetup[K]+8)+8;
      board[K+16]=18;
      board[K+96]=9;                               /* initial board setup*/
      L=8;
      while(L--)board[16*L+K+8]=(K-4)*(K-4)+(L-3.5)*(L-3.5);     /* center-pts table   */
   }                                                             /*(in unused half board[])*/
   N=1035;
   while(N-->M)T[N]=rand()>>9;
   
                                                                /* play loop          */
   while(1)                                               
   {
     N=-1;
     
     Serial.print("\n");

     sprintf(sbuf,"     A B C D E F G H \n     --------------- \n"); Serial.print(sbuf);
     while(++N<121) {                                            /* print board */
         if(N&8 && (N+7!=0) ) {sprintf(sbuf,"%3d \n", 1+((120-N)>>4)); Serial.print(sbuf); N+=7; }
         else {
           if(N%8==0) {sprintf(sbuf, "%3d ", 1+((120-N)>>4)); Serial.print(sbuf); }
         sprintf(sbuf," %c", psymbol[board[N]&15]);         Serial.print(sbuf);
         }
     }
     sprintf(sbuf,"     --------------- \n     A B C D E F G H "); Serial.print(sbuf);
     
     if(turn==16) sprintf(sbuf,"\n>  WHITE: ");  else sprintf(sbuf,"\n>   BLACK:  ");
     Serial.print(sbuf);
     
     i = 0;       
     strcpy(cstring,"");
     do   {
       while (Serial.available()==0);       
       cstring[i] = Serial.read();     
       if(cstring[i]==13) {
         cstring[i]=0;
         break;
       }
       else i++;
     } while(i < 10);
     
     K=I;
     
     if(cstring[0]!=0) {                                   /* parse entered move */
       K= cstring[0]-16*cstring[1]+799;
       L= cstring[2]-16*cstring[3]+799;
     }   
     /*
     Serial.print("\n DEBUG cstring : "); Serial.print(cstring);
     sprintf(sbuf,"\n DEBUG K: %d  \n DEBUG L: %d \n",  K, L);
     Serial.print(sbuf);
     */
     memcpy(oboard, board, sizeof(board));
     oldto=mto;
     oldEPSQ=EPSQ;
     
     score=Minimax(-I, I, Q, EPSQ, 1, 3);                              /* think or check & do*/     

     if(score!=15) {                     
        RemP=S;   
        if(oboard[mto])   RemP=mto;
        if(mto==oldEPSQ)  RemP=oldto;
       
        spiece=psymbol[board[mto]&15];
        if(spiece=='*' || spiece=='+') spiece=' ';       
        sprintf(sbuf,"\n\nmoved: >> %c %c%c", spiece,'a'+(mfrom&7),'8'-(mfrom>>4) );
       
        if(oboard[mto]) strcat(sbuf," X ");
        else strcat(sbuf,"-");
       
        sprintf(sbuf2,"%c%c ", 'a'+(mto&7),'8'-(mto>>4&7));
        strcat(sbuf, sbuf2);
        Serial.print(sbuf);
     
        sprintf(sbuf, " \nDEBUG: %d to %d  \n", mfrom, mto);
        Serial.print(sbuf);
          sprintf(sbuf,"  EPsq: %c%c (%3d)\n",
                        'a'+(EPSQ&7), '8'-(EPSQ>>4&7), EPSQ); Serial.print(sbuf);
          sprintf(sbuf,"  RemP: %c%c (%3d)\n\n",
                        'a'+(RemP&7), '8'-(RemP>>4&7), RemP); Serial.print(sbuf);
      }
      else printf("\n\nILLEGAL!\n");

   }
}




void setup() {
   Serial.begin(9600);   
}



void loop() {   
   chess();
   
   while(1);
}



keywords:
NXC NXT autonom autonomer Schach Roboter Schachroboter Arm Roboterarm Zuggenerator Micro-Max Micromax Muller
autonomous autonomously chess robot arm engine move generator Arduino Mega Due 22422.5722
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5314
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess Robot: autonomes NXT Schach-Programm / Schach-Roboter

Beitragvon HaWe » 22. Okt 2015 23:07

update:
Sourcecode portiert auf den Raspberry Pi - so spielstark wie auf einem PC, wäre eine ideale Chess Engine auch für den Roboterarm
(Raspi zu NXT-Verbindung per i2c):

Code: Alles auswählen

/***************************************************************************/
/*                               micro-Max,                                */
/* A chess program orig. <  2 KByte (of non-blank source), by H.G. Muller  */
/***************************************************************************/
/* version 4.8.d  RasPi   features:                               */
/* - recursive negamax search                                              */
/* - all-capture MVV/LVA quiescence search                                 */
/* - (internal) iterative deepening                                        */
/* - best-move-first 'sorting'                                             */
/* - a hash table storing score and best move                              */
/* - futility pruning                                                      */
/* - king safety through magnetic, frozen king in middle-game              */
/* - R=2 null-move pruning                                                 */
/* - keep hash and repetition-draw detection                               */
/* - better defense against passers through gradual promotion              */
/* - extend check evasions in inner nodes                                  */
/* - reduction of all non-Pawn, non-capture moves except hash move (LMR)   */
/* - full FIDE rules (expt under-promotion) and move-legality checking     */

// Code für Raspberry Pi

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



#define K(A,B) *(int*)(T+A+(B&8)+S*(B&7))

#define HTsize (1<<16) //  wegen RAM, für PC: (1<<24) 
struct HTab {
          int  K,
               V;
          int  X,
               Y,
               D;
        } HTarray[HTsize];           /* hash table, HTsize entries*/


#define MAXNODES 200000 //  wegen Zugdauer; für PC:  800000 = 8e5   
int  K,
     Q,
     R,
     J,
     Z;

int32_t    N,
     I=80000;                         /* I=80000: "infinity score" */ ;

int
    M=136,                           /* M=0x88   board system    */
    S=128,                           /* dummy square 0x80, highest valid square =127    */
    turn=16;                         // 16=Weiss, 8=Schwarz; turn^=24 wechselt hin unnd her

signed char  L,
     pval[]={0,2,2,7,-1,8,12,23},                      /* relative piece values    */
     vector[]={-16,-15,-17,0,1,16,0,1,16,15,17,0,14,18,31,33,0, /* step-vector lists */
          7,-1,11,6,8,3,6},                          /* 1st dir. in vector[] per piece*/

     bsetup[]={6,3,5,7,4,5,3,6},                         /* initial piece setup      */
     board[129],                                        /* board: half of 16x8+dummy*/
     T[1035];                                        /* hash translation table   */

signed char  psymbol[]= ".?+nkbrq?*?NKBRQ";

int  mfrom, mto;    // current ply from - to
int  EPSQ,           // e.p. square
     RemP;           // remove piece




/* recursive minimax search, turn=moving side, n=depth*/

int  Minimax(int32_t  q, int32_t  l, int32_t  score, int  EPC, int  prev, int32_t  hashkey)
                       /* (q,l)=window, score, EnPass_sqr.*/
                       /* prev=prev.dest; J,Z=hashkeys; return score*/
{
   int  j,
        r,
        m,
        v,
        d,
        h,
        i,
        F,
        G,
        V,
        P,
        f=J,
        g=Z,
        C,
        s;
   signed char  t,
        p,
        upiece,
        x,
        y,
        X,
        Y,
        H,
        B;

   struct HTab *a = HTarray + (J + turn * EPC & HTsize-1);   /* lookup pos. in hash table*/

   char sbuf[50];



   q--;                                          /* adj. window: delay bonus */
   turn^=24;                                        /* change sides             */
   d=a->D;
   m=a->V;
   X=a->X;
   Y=a->Y;                  /* resume at stored depth   */

   if(a->K-Z|prev|                                  /* miss: other pos. or empty*/
      !(m<=q | X&8&&m>=l | X&S))                   /*   or window incompatible */
      { d=Y=0; }                                /* start iter. from scratch */

   X&=~M;                                        /* start at best-move hint  */

   while( d++ < hashkey || d<3                   /* iterative deepening loop */
     || prev&K == I
       && ( N<60000 & d<98                        /* root: deepen upto time   */
          || (K=X, L=Y&~M, d=3)
       )
     )                                          /* time's up: go do best    */
   {
      x=B=X;                                       /* start scan at prev. best */
      h=Y&S;                                       /* request try noncastl. 1st*/
      P=d<3 ? I : Minimax(-l,1-l,-score,S,0,d-3);               /* Search null move         */
      m = (-P<l | R>35) ? ( d>2 ? -I : score ) : -P;            /* Prune or stand-pat       */
      N++;                                         /* node count (for timing)  */
      do
      {
         upiece=board[x];                                   /* scan board looking for   */
         if(upiece & turn)                                  /*  own piece (inefficient!)*/
         {
            r = p = upiece&7;                               /* p = piece type (set r>0) */
            j = vector[p+16];                                 /* first step vector f.piece*/
            while(r = p>2 & r<0 ? -r : -vector[++j] )       /* loop over directions vector[] */
            {
labelA:                                        /* resume normal after best */
               y=x;                            /* (x,y)=move         */
               F=G=S;                          /* (F,G)=castl.R      */

               do
               {                                       /* y traverses ray, or:     */
                  H=y=h?Y^h:y+r;                           /* sneak in prev. best move */

                  if(y&M)break;                            /* board edge hit           */

                  m= EPC-S&board[EPC]&&y-EPC<2&EPC-y<2?I:m;      /* bad castling             */

                  if(p<3&y==EPC)H^=16;                           /* shift capt.sqr. H if e.p.*/

                  t=board[H];

                  if(t&turn|p<3&!(y-x&7)-!t)break;            /* capt. own, bad pawn mode */
                  i=37*pval[t&7]+(t&192);                     /* value of capt. piece t   */
                  m=i<0?I:m;                                  /* K capture                */

                  if(m>=l&d>1) goto labelC;                     /* abort on fail high       */

                  v=d-1?score:i-p;                             /* MVV/LVA scoring          */

                  if(d-!t>1)                               /* remaining depth          */
                  {
                     v=p<6?board[x+8]-board[y+8]:0;                  /* center positional pts.   */
                     board[G]=board[H]=board[x]=0;board[y]=upiece|32;             /* do move, set non-virgin  */
                     if(!(G&M))board[F]=turn+6,v+=50;               /* castling: put R & score  */
                     v-=p-4|R>29?0:20;                              /* penalize mid-game K move */

                     if(p<3)                                        /* pawns:                   */
                     {
                        v-=9*((x-2&M||board[x-2]-upiece)+              /* structure, undefended    */
                               (x+2&M||board[x+2]-upiece)-1            /*        squares plus bias */
                              +(board[x^16]==turn+36))                 /* kling to non-virgin King */
                              -(R>>2);                                 /* end-game Pawn-push bonus */
                         V=y+r+1&S?647-p:2*(upiece&y+16&32);           /* promotion or 6/7th bonus */
                         board[y]+=V;
                         i+=V;                                         /* change piece, add score  */
                     }

                     v+= score+i;
                     V=m>q ? m : q;                           /* new eval and alpha       */
                     J+=K(y+0,board[y])-K(x+0,upiece)-K(H+0,t);
                     Z+=K(y+8,board[y])-K(x+8,upiece)-K(H+8,t)+G -S;  /* update hash key          */
                     C=d-1-(d>5&p>2&!t&!h);
                     C=R>29|d<3|P-I?C:d;                     /* extend 1 ply if in check */
                     do {
                        s=C>2|v>V?-Minimax(-l,-V,-v,         /* recursive eval. of reply */
                                            F,0,C):v;        /* or fail low if futile    */
                     } while( s>q & ++C<d );

                     v=s;
                     if(prev&&K-I&&v+I&&x==K&y==L)              /* move pending & in root:  */
                     {
                        Q=-score-i; EPSQ=F;                            /*   exit if legal & found  */
                        a->D=99;a->V=0;                        /* lock game in hash as draw*/
                        R+=i>>7;
                        return l;                            /* captured non-P material  */
                     }
                     J=f;
                     Z=g;                                    /* restore hash key         */
                     board[G]=turn+6;
                     board[F]=board[y]=0;
                     board[x]=upiece;
                     board[H]=t;                             /* undo move,G can be dummy */
                  }
                  if(v>m)                                  /* new best, update max,best*/
                  {
                     m=v,X=x,Y=y|S&F;                      /* mark double move with S  */
                  }
                  if(h)
                  {
                     h=0;
                     goto labelA;                           /* redo after doing old best*/
                  }
                  if (
                    x+r-y|upiece&32|                             /* not 1st step,moved before*/
                    p>2 & (
                      p-4|j-7||                             /* no P & no lateral K move,*/
                      board[G=x+3^r>>1&7]-turn-6            /* no virgin R in corner G, */
                      || board[G^1] | board[G^2] )          /* no 2 empty sq. next to R */
                    )
                  {
                     t+=p<5;
                  }                                        /* fake capt. for nonsliding*/
                  else F=y;                                /* enable e.p.              */

               } while(!t);                               /* if not capt. continue ray*/

            }
         }  // (upiece & turn)

      } while((x=x+9&~M)-B);                       /* next sqr. of board, wrap */

labelC:
      if (m>I-M|m<M-I) d=98;                       /* mate holds to any depth  */
      m= m+I|P==I ? m : 0;                         /* best loses K: (stale)mate*/

      if(a->D<99) {                                /* protect game history     */
         a->K=Z;
         a->V=m;
         a->D=d;                       /* always store in hash tab */
         a->X=X|8*(m>q)|S*(m<l);
         a->Y=Y;                       /* move, type (bound/exact),*/
      }
      /* uncomment for Kibitz */
      //if(prev) sprintf(sbuf, "%2d ply, %9d searched, score=%6d by %c%c%c%c\n",
      //     d-1, N-S, m, 'a'+(X&7),'8'-(X>>4),'a'+(Y&7),'8'-(Y>>4&7));

       if(prev  && X!=Y) {
         sprintf(sbuf, "\n%2d ply, searched: %9d ", d-1, N-S );
         printf(sbuf);
       }
       else
       if( ((N-S)%10000)<1) printf(".");


   }  // while (iterative deepening loop)

   turn^=24;                                        /* change sides back        */
   mfrom=K; mto=L;
   return m+= m<score;                                  /* delayed-loss bonus       */
}





void chess()
{
   int32_t       score, i;
   int16_t       oldto, oldEPSQ;
   char          sbuf[50], sbuf2[50];
   int16_t       cstring[20], *p;
   signed char   oboard[129], spiece;


   K=8;
   while(K--)
   {
      board[K]=(board[K+112]=bsetup[K]+8)+8;
      board[K+16]=18;
      board[K+96]=9;                               /* initial board setup*/
      L=8;
      while(L--)board[16*L+K+8]=(K-4)*(K-4)+(L-3.5)*(L-3.5);     /* center-pts table   */
   }                                                             /*(in unused half board[])*/
   N=1035;
   while(N-->M)T[N]=rand()>>9;

                                                                /* play loop          */
   while(1)
   {
     N=-1;

     printf("\n");

     sprintf(sbuf,"     A B C D E F G H \n     --------------- \n"); printf(sbuf);
     while(++N<121) {                                            /* print board */
         if(N&8 && (N+7!=0) ) {sprintf(sbuf,"%3d \n", 1+((120-N)>>4)); printf(sbuf); N+=7; }
         else {
           if(N%8==0) {sprintf(sbuf, "%3d ", 1+((120-N)>>4)); printf(sbuf); }
         sprintf(sbuf," %c", psymbol[board[N]&15]);         printf(sbuf);
         }
     }
     sprintf(sbuf,"     --------------- \n     A B C D E F G H "); printf(sbuf);

     if(turn==16) sprintf(sbuf,"\n>  WHITE: ");  else sprintf(sbuf,"\n>   BLACK:  ");
     printf(sbuf);

     i = 0;
     
     p=cstring;
     while( ( *p++ = getchar() ) >10 );
     if(cstring[0]==10)cstring[0]=0;

     K=I;

     if(cstring[0]!=0) {                                   /* parse entered move */
       K= cstring[0]-16*cstring[1]+799;
       L= cstring[2]-16*cstring[3]+799;
     }
     /*
     printf("\n DEBUG cstring : "); printf(cstring);
     sprintf(sbuf,"\n DEBUG K: %d  \n DEBUG L: %d \n",  K, L);
     printf(sbuf);
     */
     memcpy(oboard, board, sizeof(board));
     oldto=mto;
     oldEPSQ=EPSQ;

     score=Minimax(-I, I, Q, EPSQ, 1, 3);                              /* think or check & do*/

     if(score!=15) {
        RemP=S;
        if(oboard[mto])   RemP=mto;
        if(mto==oldEPSQ)  RemP=oldto;

        spiece=psymbol[board[mto]&15];
        if(spiece=='*' || spiece=='+') spiece=' ';
        sprintf(sbuf,"\n\nmoved: >> %c %c%c", spiece,'a'+(mfrom&7),'8'-(mfrom>>4) );

        if(oboard[mto]) strcat(sbuf," X ");
        else strcat(sbuf,"-");

        sprintf(sbuf2,"%c%c ", 'a'+(mto&7),'8'-(mto>>4&7));
        strcat(sbuf, sbuf2);
        printf(sbuf);

        sprintf(sbuf, " \nDEBUG: %d to %d  \n", mfrom, mto);
        printf(sbuf);
          sprintf(sbuf,"  EPsq: %c%c (%3d)\n",
                        'a'+(EPSQ&7), '8'-(EPSQ>>4&7), EPSQ); printf(sbuf);
          sprintf(sbuf,"  RemP: %c%c (%3d)\n\n",
                        'a'+(RemP&7), '8'-(RemP>>4&7), RemP); printf(sbuf);
      }
      else printf("\n\nILLEGAL!\n");

   }
}



int main(int argc, char **argv)
{
   chess();
   return 0;


}
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E


Zurück zu „Projekte, Showcase, Bauanleitungen“

Wer ist online?

Mitglieder in diesem Forum: Google [Bot] und 9 Gäste

Lego Mindstorms EV3, NXT und RCX Forum : Haftungsauschluss