NXC Chess: 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: 4754
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

NXC Chess: 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: 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: 4754
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess: 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: 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: 4754
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess: 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) 729-mal heruntergeladen

3 volle Ebenen Suchtiefe (+ Schach-Test-Ebenen):
chess 406.zip
3 volle Ebenen Suchtiefe
(11.76 KiB) 520-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) 550-mal heruntergeladen

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

Re: NXC Chess: 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) 24029 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) 23313 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: 42
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: 4754
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess: 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: 4754
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess: 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: 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: 4754
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: NXC Chess: 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 ;)

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

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

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: 4754
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

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

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


Zurück zu „Projekte, Showcase, Bauanleitungen“

Wer ist online?

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

Lego Mindstorms EV3, NXT und RCX Forum : Haftungsauschluss