Mindstormsforum Dateiupload | Links | Lexikon | NXT Shop | RobotC.de | Wettbewerbe |    Seitenreport - Die SEO und Website Analyse

bild
bild
Unbeantwortete Themen | Aktive Themen Aktuelle Zeit: 16. Sep 2014 01:52


Auf das Thema antworten  [ 12 Beiträge ] 
NXC Chess: autonomes NXT Schach-Programm / Schach-Roboter 
Autor Nachricht
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag NXC Chess: autonomes NXT Schach-Programm / Schach-Roboter
Hallo,
mein neues Projekt: ein Schach-Programm (NXC) für den NXT.
Ein richtiges schlaues Programm ist es jetzt 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:
Alpha-Version gelöscht, Beta-Versionen mit größerer Suchtiefe s.u. im Thread!

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


29. Sep 2011 09:12
Profil
Enorm-Viel-Schreiber
Enorm-Viel-Schreiber
Benutzeravatar

Registriert: 5. Mär 2009 18:48
Beiträge: 601
Wohnort: Mainz
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm Schach-Roboter
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.....

_________________
Mein YouTube Kanal: http://www.youtube.com/user/Golfi1812


29. Sep 2011 15:01
Profil Website besuchen
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
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.


29. Sep 2011 15:24
Profil
Super-Enorm-Viel-Schreiber
Super-Enorm-Viel-Schreiber
Benutzeravatar

Registriert: 27. Sep 2010 21:38
Beiträge: 946
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
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!


29. Sep 2011 20:48
Profil
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
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:
Dateianhang:
Dateikommentar: 2+1Q Ebenen Suchtiefe
chess 405.zip [11.75 KiB]
600-mal heruntergeladen

3 volle Ebenen Suchtiefe (+ Schach-Test-Ebenen):
Dateianhang:
Dateikommentar: 3 volle Ebenen Suchtiefe
chess 406.zip [11.76 KiB]
439-mal heruntergeladen


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


9. Okt 2011 14:21
Profil
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
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)

Dateianhang:
Dateikommentar: mit nur 1 NXT ohne Pneumatik-Druck-Regulierung (Fehler in jpg Datei)
chessBot.jpg
chessBot.jpg [ 52.37 KiB | 20821-mal betrachtet ]

Dateianhang:
Dateikommentar: mit nur 1 NXT ohne Pneumatik-Druck-Regulierung; neu hochgeladen
chessBot1.jpg
chessBot1.jpg [ 52.37 KiB | 473-mal betrachtet ]


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:
Dateianhang:
Dateikommentar: inkl. 2.NXT mit Blick auf pneumatische Pumpe,
Drucksensor + elekromagnetische Ventile

chessbot2.jpg
chessbot2.jpg [ 87.42 KiB | 20105-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:
/******************************************************************************/
//                             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:
/******************************************************************************/
// 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;
}



1. Nov 2011 22:39
Profil
Schreibt ab und zu
Schreibt ab und zu

Registriert: 13. Okt 2011 11:56
Beiträge: 22
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
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 :)


2. Nov 2011 11:10
Profil
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
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.


2. Nov 2011 13:23
Profil
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
@mindcraft: 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:
/******************************************************************************/
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


2. Nov 2011 14:53
Profil
Hilft fleißig mit!!!
Hilft fleißig mit!!!

Registriert: 5. Mai 2010 10:46
Beiträge: 66
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
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


28. Nov 2011 11:54
Profil
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm/Schach-Roboter
hallo,
danke für die Blumen! :)
Zitat:
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 ;)


28. Nov 2011 19:34
Profil
Administrator
Administrator
Benutzeravatar

Registriert: 11. Jan 2006 21:01
Beiträge: 4287
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze
Beitrag Re: NXC Chess: autonomes NXT Schach-Programm / Schach-Robote
Das Video ist da!

https://www.youtube.com/watch?v=Cv-yzuebC7E



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


11. Jan 2012 21:00
Profil
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Auf das Thema antworten   [ 12 Beiträge ] 

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 12 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
Impressum Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Deutsche Übersetzung durch phpBB.de