Hier das Spiel Kalaha.
Infos dazu: http://de.wikipedia.org/wiki/Kalaha
/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 TESTS
* ************************************************** **************************
* Example: Kalaha
* Author(s): Dirk
* ************************************************** **************************
* Description:
* This program for RP6 Control plays the old game Kalaha, invented by William
* Julius Champion Jr in 1940.
*
* Rules:
* Kalaha is usually played on a board with two rows of 6 flat deepenings
* (called field or house) and two more bigger deepenings (called kalah, home
* or store) on the left and right end of the two rows.
* Both players are normally sitting opposite. The 12 fields in two rows are
* filled with 3 seeds or other small things (like beans, stones ...). Each
* player controls the six fields next to him and the home field to his right.
*
* Alternately each player decides to take all seeds out of ONE of the 6
* fields of his row. Moving counter-clockwise, he drops one seed in each
* field in turn, including the player's own home but not his opponent's.
* If the last seed is sawn into the player's own home, he gets to go again.
* There is no limit on the number of moves a player can make in his turn.
* If the last seed is dropped into an empty field owned by the player, he
* gains the last seed and all of the seeds in the field directly opposite
* the one he ended in, and all of those seeds are moved into his home. When
* one side runs out of seeds, the other player moves all seeds from his
* fields into his home and whoever has the most in his home wins.
*
* Variations:
* - Starting the game with four, five or six seeds in each field.
* - The "Empty Capture" variant modifies the rules to prohibit a player from
* capturing seeds from his opponent when landing in an empty field - i.e.,
* only the last dropped seed is placed into the home.
* - Not counting the remaining seeds as part of the opponent's score at the
* end of the game.
*
* You will find further information here:
* http://en.wikipedia.org/wiki/Kalah
*
* ################################################## ##########################
* The Robot does NOT move in this example! You can simply put it on a table
* next to your PC and you should connect it to the PC via the USB Interface!
* ################################################## ##########################
* ************************************************** **************************
*/
/************************************************** ***************************/
// Includes:
#include "RP6ControlLib.h" // The RP6 Control Library (1.3beta or higher).
// Always needs to be included!
/************************************************** ***************************/
// Defines:
// Number of fields (Default: 6, Range: 2..11):
#define MAXFIELDS 6
// Seeds in each field (Default: 3, Range: 2..11):
#define MAXSEEDS 3
// 4 seeds in each field:
//#define MAXSEEDS 4
// 5 seeds in each field:
//#define MAXSEEDS 5
// 6 seeds in each field:
//#define MAXSEEDS 6
// Show rules:
#define SHOW_RULES
// -------------------------------------------------------
// Highest index of field[]:
#define MAXINDEX (MAXFIELDS * 2 + 1)
// Index of home field 1:
#define KALAH1 MAXFIELDS
// Index of home field 2:
#define KALAH2 MAXINDEX
// Number of seeds / 2 (Tie):
#define TIE (MAXSEEDS * MAXFIELDS)
// Constants for gamemode:
#define PLAYER_PLAYER 0
#define COMPUTER_PLAYER 1
#define COMPUTER_COMPUTER 2
// Output delay (ms):
#define WAIT_MS 1000
#define WAITDEMO_MS 2000
// -------------------------------------------------------
// Variations:
// "Empty Capture" variation:
//#define EMPTY_CAPTURE
// Don't count the opponent's seeds at the end of the game:
//#define REMAINING_SEEDS
/************************************************** ***************************/
// Variables:
// Reception buffer for the function getInputLine():
char receiveBuffer[UART_RECEIVE_BUFFER_SIZE + 1];
uint8_t field[MAXINDEX + 1];
uint8_t firstmove;
uint16_t pause_ms;
uint8_t gamemode;
uint8_t turn;
uint8_t move;
uint8_t winner;
uint8_t winner1;
uint8_t winner2;
/************************************************** ***************************/
// Functions:
// UART receive functions:
/**
* Get chars of an input line from the UART.
*
* Returns 0 (false), if the UART receive buffer is empty
* OR a character of the input line has been received.
* Returns 1, if the whole input line has been received
* (with a "new line" character at the end).
* Returns 2, if the UART receive buffer overflows.
* The input line is stored in the receiveBuffer array.
*
*/
uint8_t getInputLine(void)
{static uint8_t buffer_pos = 0;
if(getBufferLength()) {
receiveBuffer[buffer_pos] = readChar();
if(receiveBuffer[buffer_pos] == '\n') {
receiveBuffer[buffer_pos] = '\0';
buffer_pos = 0;
return 1;
}
else if(buffer_pos >= UART_RECEIVE_BUFFER_SIZE) {
receiveBuffer[UART_RECEIVE_BUFFER_SIZE] = '\0';
buffer_pos = 0;
return 2;
}
buffer_pos++;
}
return 0;
}
/**
* Get a complete input line from the UART.
*
* This function waits for a whole input line from the UART.
* The input line is stored in the receiveBuffer array.
* The function is blocking until one of the two following
* conditions occurs:
* - A "new line" character has been received at the end of
* the input line.
* - The UART receive buffer overflows.
*
*/
void enterString(void)
{
while(!getInputLine());
}
/**
* GET SEED
*
* Gets a starting value for srand().
*
*/
uint16_t get_seed(void)
{
uint16_t seed = 0;
uint16_t *p = (uint16_t*) (RAMEND + 1);
extern uint16_t __heap_start;
while (p >= &__heap_start + 1)
seed ^= * (--p);
return seed;
}
/**
* WRITE 6 SPACES
*
* Sends 6 spaces for each field via UART (used by showBoard).
*
*/
void write6Spaces(void)
{
uint8_t i;
for (i = 0; i < KALAH1; i++) {
writeString_P(" ");
}
}
/**
* SHOW BOARD
*
* Shows the Kalaha board in field[] on the terminal.
*
*/
void showBoard(void)
{
uint8_t i;
writeString_P("\n -2- ");
for (i = KALAH1; i > 0; i--) {
writeString_P("[F");
writeIntegerLength(i, DEC, 2); // Player 2 fields
writeString_P("] ");
}
writeString_P(" -2-\n");
writeString_P(" < ");
for (i = (KALAH2 - 1); i > KALAH1; i--) {
writeIntegerLength(field[i], DEC, 3); // Player 2 side
writeString_P(" < ");
}
writeChar('\n');
writeString_P(" v ");
write6Spaces();
writeString_P("^\n");
writeString_P(" v ");
write6Spaces();
writeString_P(" ^\n");
writeString_P(" ");
writeIntegerLength(field[KALAH2], DEC, 3); // Player 2 result
writeString_P(" ");
write6Spaces();
writeIntegerLength(field[KALAH1], DEC, 3); // Player 1 result
writeString_P("\n v ");
write6Spaces();
writeString_P(" ^\n");
writeString_P(" v ");
write6Spaces();
writeString_P("^\n");
writeString_P(" > ");
for (i = 0; i < KALAH1; i++) {
writeIntegerLength(field[i], DEC, 3); // Player 1 side
writeString_P(" > ");
}
writeChar('\n');
writeString_P(" -1- ");
for (i = 1; i <= KALAH1; i++) {
writeString_P("[F");
writeIntegerLength(i, DEC, 2); // Player 1 fields
writeString_P("] ");
}
writeString_P(" -1-\n");
}
/**
* INIT FIELD ARRAY
*
* Initialises the field array.
*
*/
void initFieldArray(void)
{
uint8_t i;
for (i = 0; i <= MAXINDEX; i++) {
field[i] = MAXSEEDS;
}
field[KALAH1] = 0; // Result field 1
field[KALAH2] = 0; // Result field 2
}
/**
* CALCULATE MOVE
*
* Calculates each move. The variable move contains the actual
* field index to be processed in field[]. After the calculation
* field[] contains the new field (board). The variable turn
* determines the next player (1/2) or the victory condition (0).
*
*/
void calculateMove(void)
{
uint8_t actualmove;
uint8_t resultfield;
uint8_t I;
uint8_t fieldindex;
#ifndef REMAINING_SEEDS
uint8_t seeds;
#endif
// Calculate a move:
actualmove = move;
if ((turn == 0) || (field[actualmove] == 0)) return;
if (turn == 1) resultfield = KALAH1;
if (turn == 2) resultfield = KALAH2;
fieldindex = actualmove;
do {
actualmove += 1;
if (actualmove > MAXINDEX) actualmove = 0;
// Jump over the opponent's result field:
if ((actualmove == KALAH1) && (resultfield != KALAH1)) {
actualmove += 1;
}
if ((actualmove == KALAH2) && (resultfield != KALAH2)) {
actualmove = 0;
}
field[actualmove] += 1;
field[fieldindex] -= 1;
} while (field[fieldindex] > 0);
// Calculate the "special case":
// Special case: Last seed drops into an empty field of the actual
// player and the opposite field is not empty
if (((resultfield == KALAH1) && (actualmove < KALAH1))
|| ((resultfield == KALAH2) && (actualmove > KALAH1))) {
if ((field[actualmove] == 1) && (actualmove != KALAH2)
&& (field[MAXINDEX - 1 - actualmove] > 0)) {
field[actualmove] = 0;
field[resultfield] += 1;
#ifndef EMPTY_CAPTURE
field[resultfield] += field[MAXINDEX - 1 - actualmove];
field[MAXINDEX - 1 - actualmove] = 0;
#endif
}
}
// Test the victory conditions:
// Continue playing, if own fields are not empty:
fieldindex = 0;
#ifndef REMAINING_SEEDS
seeds = 0;
#endif
for (I = 0; I < MAXFIELDS; I++) {
if (field[resultfield - KALAH1 + I] > 0) fieldindex = 1;
#ifndef REMAINING_SEEDS
seeds += field[KALAH2 - resultfield + I];
#endif
}
if (fieldindex == 1) {
if (actualmove == resultfield) return; // Once more (extra move)
}
else {
turn = 0; // No more seeds: End of game
#ifndef REMAINING_SEEDS
field[KALAH1 + KALAH2 - resultfield] += seeds;
for (I = 0; I < MAXFIELDS; I++) {
field[KALAH2 - resultfield + I] = 0;
}
#endif
return;
}
// Change player, if his fields are not empty:
fieldindex = 0;
#ifndef REMAINING_SEEDS
seeds = 0;
#endif
for (I = 0; I < MAXFIELDS; I++) {
if (field[KALAH2 - resultfield + I] > 0) fieldindex = 1;
#ifndef REMAINING_SEEDS
seeds += field[resultfield - KALAH1 + I];
#endif
}
if (fieldindex == 1) {
turn = 3 - turn; // Change player
}
else {
turn = 0; // No more seeds: End of game
#ifndef REMAINING_SEEDS
field[KALAH1 + KALAH2 - resultfield] += seeds;
for (I = 0; I < MAXFIELDS; I++) {
field[resultfield - KALAH1 + I] = 0;
}
#endif
}
}
/**
* SHOW MOVE
*
* Shows the actual move (board) on the terminal and displays
* the victory message at the end of a game.
*
*/
void showMove(void)
{
mSleep(1000);
showBoard(); // Show fields
if (turn != 0) {
mSleep(pause_ms); // Pause the output for (pause_ms) ms
return;
}
if (field[KALAH1] > field[KALAH2]) {
writeString_P("\nSpieler/Computer 1 hat gewonnen!");
winner = 1;
winner1++;
}
if (field[KALAH1] < field[KALAH2]) {
writeString_P("\nSpieler/Computer 2 hat gewonnen!");
winner = 2;
winner2++;
}
if (field[KALAH1] == field[KALAH2]) {
writeString_P("\nUnentschieden!");
winner = 0;
}
writeString_P(" Spielende.\n");
writeString_P("\nSpielstand: ");
writeInteger(winner1, DEC);
writeString_P(" : ");
writeInteger(winner2, DEC);
writeString_P(" !\n");
}
/**
* COMPUTER 1 MOVE
*
* Calculates the computer 1 move in the actual field[].
* After processing the variable move contains the field
* index of the new computer 1 move. This function calls
* calculateMove() and displays a text informing about
* the move.
*
*/
void computer1Move(void)
{
uint8_t I, J;uint8_t movefield;uint8_t fieldindex;do {I = rand() % KALAH1;
} while (field[I] == 0);movefield = I;for (I = (MAXINDEX - 2); I > KALAH1;
I--) {if (field[I] > 0) {fieldindex = I + field[I];if (fieldindex >= KALAH2)
continue;if (field[fieldindex] == 0) {if (field[MAXINDEX - 1 - fieldindex] > 0)
{movefield = MAXINDEX - 1 - fieldindex; break;}}}}for (I = KALAH1; I > 0; I--)
{J = I - 1; if (field[J] > 0) {fieldindex = J + field[J];if (fieldindex >
KALAH1) {movefield = J;break;}}}for (I = (KALAH1 - 1); I > 0; I--) {J = I - 1;
if (field[J] > 0) {fieldindex = J + field[J];if (fieldindex >= KALAH1)
continue;if (field[fieldindex] == 0) {if (field[MAXINDEX - 1 - fieldindex] > 0)
{movefield = J;break;}}}}for (I = KALAH1; I > 0; I--) {J = I - 1;if (field[J]
> 0) {fieldindex = J + field[J];if (fieldindex == KALAH1) {movefield = J;
break;}}}move = movefield;calculateMove();writeString_P("\nComputer 1: Zieht Feld ");
writeInteger((move + 1), DEC);writeString_P(".\n");}
/**
* COMPUTER 2 MOVE
*
* Calculates the computer 2 move in the actual field[].
* After processing the variable move contains the field
* index of the new computer 2 move. This function calls
* calculateMove() and displays a text informing about
* the move.
*
*/
void computer2Move(void)
{
uint8_t I, J;uint8_t movefield;uint8_t fieldindex;do {I = rand() % KALAH1 +
KALAH1 + 1;} while (field[I] == 0);movefield = I;for (I = (KALAH1 - 1); I > 0;
I--) {J = I - 1;if (field[J] > 0) {fieldindex = J + field[J];if (fieldindex
>= KALAH1) continue;if (field[fieldindex] == 0) {if (field[MAXINDEX - 1 -
fieldindex] > 0) {movefield = MAXINDEX - 1 - fieldindex;break;}}}} for (I =
(MAXINDEX - 1); I > KALAH1; I--) {if (field[I] > 0) {fieldindex = I +
field[I];if (fieldindex > MAXINDEX) {movefield = I;break;}}}for (I =
(MAXINDEX - 2); I > KALAH1; I--) {if (field[I] > 0) {fieldindex = I +
field[I];if (fieldindex >= MAXINDEX) continue;if (field[fieldindex] == 0) {
if (field[MAXINDEX - 1 - fieldindex] > 0) {movefield = I;break;}}}}for (I =
(MAXINDEX - 1); I > KALAH1; I--) {if (field[I] > 0) {fieldindex = I +
field[I];if (fieldindex == MAXINDEX) {movefield = I;break;}}}move = movefield;
calculateMove();writeString_P("\nComputer 2: Zieht Feld ");writeInteger((move
- KALAH1), DEC);writeString_P(".\n");}
/**
* PLAYER 1 MOVE
*
* Player 1 move. The function asks for the move of player 1.
* The player enters a number from 1 to KALAH1 to select one
* of his fields. This function calls calculateMove().
*
*/
void player1Move(void)
{
uint8_t movefield = KALAH1;
writeString_P("\nSpieler 1: Dein Zug (Feld 1..");
writeInteger(movefield, DEC);
writeString_P(")?\n");
do {
enterString();
if (receiveBuffer[1] == '\0') {
movefield = receiveBuffer[0] - 49;
}
else {
if (receiveBuffer[2] == '\0') {
movefield = (receiveBuffer[0] - 48) * 10 + receiveBuffer[1] - 49;
}
}
}
while ((movefield >= KALAH1) || (field[movefield] == 0));
firstmove = 0;
move = movefield; // 0..(KALAH1 - 1)
calculateMove();
}
/**
* PLAYER 2 MOVE
*
* Player 2 move. The function asks for the move of player 2.
* The player enters a number from 1 to KALAH1 to select one
* of his fields. This function calls calculateMove().
*
*/
void player2Move(void)
{
uint8_t movefield = KALAH1;
writeString_P("\nSpieler 2: Dein Zug (Feld 1..");
writeInteger(movefield, DEC);
writeString_P(")?\n");
do {
enterString();
if (receiveBuffer[1] == '\0') {
movefield = receiveBuffer[0] - 48 + KALAH1;
}
else {
if (receiveBuffer[2] == '\0') {
movefield = (receiveBuffer[0] - 48) * 10 + receiveBuffer[1] - 48 + KALAH1;
}
}
}
while ((movefield <= KALAH1) || (movefield >= KALAH2)
|| (field[movefield] == 0));
firstmove = 0;
move = movefield; // (KALAH1 + 1)..(KALAH2 - 1)
calculateMove();
}
/**
* PLAYER V PLAYER
*
* Player 2 against player 1. Function only ends, if turn == 0.
*
*/
void playerVplayer(void)
{
do {
while (turn == 1) {
player1Move();
showMove();
};
while (turn == 2) {
player2Move();
showMove();
};
} while (turn != 0);
}
/**
* COMPUTER V PLAYER
*
* Computer 2 against player 1. Function only ends, if turn == 0.
*
*/
void computerVplayer(void)
{
do {
while (turn == 1) {
player1Move();
showMove();
};
while (turn == 2) {
computer2Move();
showMove();
};
} while (turn != 0);
}
/**
* COMPUTER DEMO
*
* Computer 2 against computer 1. Function only ends, if turn == 0.
*
*/
void computerDemo(void)
{
pause_ms = WAITDEMO_MS;
do {
while (turn == 1) {
computer1Move();
showMove();
};
while (turn == 2) {
computer2Move();
showMove();
};
} while (turn != 0);
pause_ms = WAIT_MS;
}
/**
* NEW GAME
*
* Performs a new Kalaha game. Function only ends, if turn == 0.
*
*/
void newGame(void)
{
// Initialisation:
pause_ms = WAIT_MS;
if (!gamemode) {
gamemode = COMPUTER_PLAYER; // Default mode -> Player : Computer
}
turn = rand() % 2 + 1; // Default: Random player or computer begins or
if (winner) turn = winner; // the last winning player or computer begins
firstmove = 1; // First move of a game
// Menu:
writeString_P("\n\n****** Kalaha Version 1.0 ******\n");
#ifdef SHOW_RULES
writeString_P("Spielregeln:\n");
writeString_P("Das Kalaha-Spielbrett besteht aus zwei Muldenreihen mit\n");
writeString_P("jeweils sechs Spielmulden. Außerdem befindet sich an\n");
writeString_P("jedem Ende eine große Gewinnmulde, auch Kalah genannt,\n");
writeString_P("welche im Spiel die gefangenen Samen aufnimmt.\n");
writeString_P("Jedem Spieler gehören die sechs Spielmulden auf seiner\n");
writeString_P("Seite des Brettes und die rechts von ihm gelegene Ge-\n");
writeString_P("winnmulde.\n");
writeString_P("Vorbereitung: Zu Beginn des Spiels werden alle Spiel-\n");
writeString_P("mulden mit jeweils drei Samen gefüllt. Gewöhnlich fängt\n");
writeString_P("der letzte Sieger das neue Spiel an.\n");
writeString_P("Das Ziel des Spiels ist es, mehr Samen zu sammeln als\n");
writeString_P("der Gegner. Da es nur 36 Samen gibt, reichen 19, um das\n");
writeString_P("zu erreichen. Da es eine gerade Anzahl an Samen gibt,\n");
writeString_P("ist ein Unentschieden möglich, wenn beide Spieler am\n");
writeString_P("Ende 18 Samen ihr Eigen nennen.\n");
writeString_P("Spielrunde: Die beiden Spieler sind abwechselnd am Zug.\n");
writeString_P("Der Spieler entscheidet sich für eine seiner sechs\n");
writeString_P("Spielmulden, nimmt alle Samen heraus und veteilt sie\n");
writeString_P("einzeln gegen den Uhrzeigersinn (links herum) auf die\n");
writeString_P("folgenden Spielmulden einschließlich der eigenen Ge-\n");
writeString_P("winnmulde, aber mit Ausnahme der gegnerischen Gewinn-\n");
writeString_P("mulde.\n");
writeString_P("Fällt der letzte Samen in die eigene Gewinnmulde, be-\n");
writeString_P("kommt der Spieler eine Extra-Runde, d.h. er darf erneut\n");
writeString_P("ziehen. Dies kann auch mehrfach vorkommen.\n");
writeString_P("Fangen: Wenn der letzte Samen in einer leeren Spiel-\n");
writeString_P("mulde des aktiven Spielers landet und direkt gegenüber\n");
writeString_P("in der gegnerischen Mulde Samen liegen, sind sowohl der\n");
writeString_P("letzte Samen als auch die gegenüberliegenden Samen ge-\n");
writeString_P("fangen und werden zu den eigenen Samen in die Gewinn-\n");
writeString_P("mulde gelegt.\n");
writeString_P("Spielende: Wenn ein Spieler an der Reihe ist, jedoch\n");
writeString_P("alle seine Spielmulden leer sind, ist das Spiel be-\n");
writeString_P("endet.\n");
writeString_P("Der Gegner leert seine Spielmulden ebenfalls und legt\n");
writeString_P("die Samen in seine Gewinnmulde. Gewinner ist, wer die\n");
writeString_P("meisten Samen in seiner Gewinnmulde hat.\n\n");
writeString_P("Weitere Informationen kann man hier finden:\n");
writeString_P(" http://de.wikipedia.org/wiki/Kalaha\n");
#endif
writeString_P("\nWelches Spiel willst du spielen?\n");
writeString_P(" -1- Spieler : Spieler\n");
writeString_P(" -2- Spieler : Computer\n");
writeString_P(" -3- Computer : Computer (Demo)\n");
enterString();
if (receiveBuffer[0] == '1') gamemode = PLAYER_PLAYER;
if (receiveBuffer[0] == '2') gamemode = COMPUTER_PLAYER;
if (receiveBuffer[0] == '3') gamemode = COMPUTER_COMPUTER;
writeString_P("\nWer soll anfangen?\n");
writeString_P(" -1- Spieler/Computer 1 (unten)\n");
writeString_P(" -2- Spieler/Computer 2 (oben)\n");
writeString_P(" -3- Zufällige Spieler-Auswahl\n");
enterString();
if (receiveBuffer[0] == '1') turn = 1;
if (receiveBuffer[0] == '2') turn = 2;
if (receiveBuffer[0] == '3') {
turn = rand() % 2 + 1;
writeString_P("Es beginnt der Spieler/Computer ");
writeInteger(turn, DEC);
writeString_P("!\n");
}
initFieldArray();
showBoard();
switch (gamemode) {
// Player 2 plays against player 1:
case PLAYER_PLAYER :
playerVplayer();
break;
// Computer 2 plays against player 1:
case COMPUTER_PLAYER :
computerVplayer();
break;
// Shows the computer demo:
case COMPUTER_COMPUTER :
computerDemo();
break;
}
}
/************************************************** ***************************/
// Main function - The program starts here:
int main(void)
{
initRP6Control(); // Always call this first! The Processor will not work
// correctly otherwise.
initLCD(); // Initialize the LC-Display (LCD)
// Always call this before using the LCD!
// Write some text messages to the UART - just like on RP6Base:
writeString_P("\n\n _______________________\n");
writeString_P(" \\| RP6 ROBOT SYSTEM |/\n");
writeString_P(" \\_-_-_-_-_-_-_-_-_-_/\n\n (file://\\_-_-_-_-_-_-_-_-_-_/\n\n)");
writeString_P("Kalaha for RP6 CONTROL!\n");
// Set the four Status LEDs:
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
showScreenLCD("################", "################");
mSleep(1500);
showScreenLCD("<<RP6 Control>>", "<<LC - DISPLAY>>");
mSleep(2500);
showScreenLCD(" Kalaha 1.0 ", " ************ ");
mSleep(2500);
clearLCD(); // Clear the whole LCD Screen
srand(get_seed());
while(true) {
newGame();
}
return 0;
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 24.05.2011 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
Viel Spaß!
Hallo RP6v2 Fans!
Einen schönen 3. Advent! :)
/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 Examples
* ************************************************** **************************
* Example: Christmas
* Author(s): Dirk
* ************************************************** **************************
* Description:
* This program for RP6 Control plays the song Jingle Bells
* and shows a Christmas tree on the terminal.
*
* ################################################## ##########################
* The Robot does NOT move in this example! You can simply put it on a table
* next to your PC and you should connect it to the PC via the USB Interface!
* ################################################## ##########################
* ************************************************** **************************
*/
/************************************************** ***************************/
// Includes:
#include "RP6ControlLib.h" // The RP6 Control Library.
// Always needs to be included!
/************************************************** ***************************/
// Defines:
// Define tone frequencies (well temperament):
// Great Octave
#define Tone_H 2 //123Hz
// Small Octave
#define Tone_c 16 //131Hz
#define Tone_cis 30 //139Hz
#define Tone_d 42 //147Hz
#define Tone_dis 54 //156Hz
#define Tone_e 65 //165Hz
#define Tone_f 76 //175Hz
#define Tone_fis 86 //185Hz
#define Tone_g 96 //196Hz
#define Tone_gis 105 //208Hz
#define Tone_a 113 //220Hz
#define Tone_ais 121 //233Hz
#define Tone_h 128 //247Hz
// ' Octave
#define Tone_C1 136 //262Hz
#define Tone_Cis1 142 //277Hz
#define Tone_D1 149 //294Hz
#define Tone_Dis1 155 //311Hz
#define Tone_E1 160 //330Hz
#define Tone_F1 166 //349Hz
#define Tone_Fis1 171 //370Hz
#define Tone_G1 175 //392Hz
#define Tone_Gis1 180 //415Hz
#define Tone_A1 184 //440Hz
#define Tone_Ais1 188 //466Hz
#define Tone_H1 192 //494Hz
// '' Octave
#define Tone_C2 195 //523Hz
#define Tone_Cis2 199 //554Hz
#define Tone_D2 202 //587Hz
#define Tone_Dis2 205 //622Hz
#define Tone_E2 208 //659Hz
#define Tone_F2 210 //698Hz
#define Tone_Fis2 213 //740Hz
#define Tone_G2 215 //784Hz
#define Tone_Gis2 217 //831Hz
#define Tone_A2 219 //880Hz
#define Tone_Ais2 221 //932Hz
#define Tone_H2 223 //988Hz
// ''' Octave
#define Tone_C3 225 //1047Hz
#define Tone_Cis3 227 //1109Hz
#define Tone_D3 228 //1175Hz
#define Tone_Dis3 230 //1245Hz
#define Tone_E3 231 //1319Hz
#define Tone_F3 233 //1397Hz
#define Tone_Fis3 234 //1480Hz
#define Tone_G3 235 //1568Hz
#define Tone_Gis3 236 //1661Hz
#define Tone_A3 237 //1760Hz
#define Tone_Ais3 238 //1865Hz
#define Tone_H3 239 //1976Hz
// '''' Octave
#define Tone_C4 240 //2093Hz
#define Tone_Cis4 241 //2217Hz
#define Tone_D4 242 //2349Hz
#define Tone_Dis4 242 //2489Hz
#define Tone_E4 243 //2637Hz
#define Tone_F4 244 //2794Hz
#define Tone_Fis4 244 //2960Hz
#define Tone_G4 245 //3136Hz
#define Tone_Gis4 246 //3322Hz
#define Tone_A4 246 //3520Hz
#define Tone_Ais4 247 //3729Hz
#define Tone_H4 247 //3951Hz
// ''''' Octave
#define Tone_C5 248 //4186Hz
// Beats per minute (BPM):
#define Largo 50
#define Larghetto 63
#define Adagio 71
#define Andante 92
#define Moderato 114
#define Allegro 144
#define Presto 188
/************************************************** ***************************/
// Variables:
uint16_t T_1; // Whole tone
uint16_t T_2; // Semitone (halftone)
uint16_t T_4; // Quarter tone
uint16_t T_8; // Quaver (eigth note)
uint16_t T_16; // Semiquaver
uint16_t T_32; // Demisemiquaver (thirty-second note)
/************************************************** ***************************/
// Functions:
/**
* SET SPEED
*
* Input: Speed [BPM]
* OR Speed [Adagio] (= 71 BPM)
*
*/
void setSpeed(uint16_t bpm)
{
T_4 = 60000 / bpm;
T_1 = 4 * T_4;
T_2 = 2 * T_4;
T_8 = T_4 / 2;
T_16 = T_4 / 4;
T_32 = T_4 / 8;
}
/**
* PLAY JINGLE BELLS
*
*/
void jingle_bells(void)
{
setSpeed(Allegro); // Set 144 BPM
setLEDs(0b0010);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_2, 0);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_2, 0);
sound(Tone_E1,T_4, 0);
setLEDs(0b1000);
sound(Tone_G1,T_4, 0);
setLEDs(0b0001);
sound(Tone_C1,T_4, 0);
setLEDs(0b0010);
sound(Tone_D1,T_4, 0);
setLEDs(0b0100);
sound(Tone_E1,T_1, 0);
setLEDs(0b1000);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
setLEDs(0b0100);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,(T_4 + T_8), 0);
sound(Tone_E1,T_8, 0);
sound(Tone_E1,T_4, 0);
setLEDs(0b0010);
sound(Tone_D1,T_4, 0);
sound(Tone_D1,T_4, 0);
setLEDs(0b0100);
sound(Tone_E1,T_4, 0);
setLEDs(0b0010);
sound(Tone_D1,T_2, 0);
setLEDs(0b1000);
sound(Tone_G1,T_2, 0);
setLEDs(0b0010);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_2, 0);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_2, 0);
sound(Tone_E1,T_4, 0);
setLEDs(0b1000);
sound(Tone_G1,T_4, 0);
setLEDs(0b0001);
sound(Tone_C1,T_4, 0);
setLEDs(0b0010);
sound(Tone_D1,T_4, 0);
setLEDs(0b0100);
sound(Tone_E1,T_1, 0);
setLEDs(0b1000);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
sound(Tone_F1,T_4, 0);
setLEDs(0b0100);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_4, 0);
sound(Tone_E1,T_4, 0);
setLEDs(0b1000);
sound(Tone_G1,T_4, 0);
sound(Tone_G1,T_4, 0);
setLEDs(0b0100);
sound(Tone_F1,T_4, 0);
setLEDs(0b0010);
sound(Tone_D1,T_4, 0);
setLEDs(0b0001);
sound(Tone_C1,(T_4 * 3), T_4);
setLEDs(0b0000);
}
/************************************************** ***************************/
// Main function - The program starts here:
int main(void)
{
initRP6Control(); // Always call this first! The Processor will not work
// correctly otherwise.
initLCD(); // Initialize the LC-Display (LCD)
// Always call this before using the LCD!
// Write some text messages to the UART - just like on RP6Base:
writeString_P("\n\n _______________________\n");
writeString_P(" \\| RP6 ROBOT SYSTEM |/\n");
writeString_P(" \\_-_-_-_-_-_-_-_-_-_/\n\n");
// Set the four Status LEDs:
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
showScreenLCD("################", "################");
mSleep(1500);
showScreenLCD("<<RP6 Control>>", "<<LC - DISPLAY>>");
mSleep(2500);
showScreenLCD(" Merry Christmas", "* Jingle Bells *");
writeString_P(" X\n");
writeString_P(" *\n");
writeString_P(" **i\n");
writeString_P(" *****\n");
writeString_P(" *i*****\n");
writeString_P(" *******O*\n");
writeString_P(" ***********\n");
writeString_P(" **O****i*****\n");
writeString_P(" *************i*\n");
writeString_P(" **O*i************\n");
writeString_P(" ***********O****i**\n");
writeString_P(" **i****************O*\n");
writeString_P(" *******O*****i*********\n");
writeString_P(" *****************O*****i*\n");
writeString_P(" ****O**i*******************\n");
writeString_P("**i*******************i******\n");
writeString_P(" & |I|\n");
writeString_P(" [M32] |I|\n");
while(true)
{
mSleep(5000); // Pause 5 seconds
jingle_bells(); // Play melody
}
return 0;
}
Hallo M256 WiFi Besitzer,
wie wäre es mit einer kleinen Schach-Partie?
Das geht ganz gut auch mit dem ATmega2560.
Datei: RP6M256_Chess.c:
/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
* ************************************************** **************************
* Example: Chess
* Author(s): Dirk
* ************************************************** **************************
* Description:
* This program for RP6 Control M256 WiFi plays the game chess.
*
* You will find further information here:
* http://de.wikipedia.org/wiki/Chess
* http://en.wikipedia.org/wiki/Chess
*
* ################################################## ##########################
* The Robot does NOT move in this example! You can simply put it on a table
* next to your PC and you should connect it to the PC via the USB Interface!
* You should also connect to it via WIFI.
* ################################################## ##########################
* ************************************************** **************************
*/
/************************************************** ***************************/
// Includes:
#include "RP6M256Lib.h" // The RP6 M256 Library.
// Always needs to be included!
/************************************************** ***************************/
// Defines:
#define HELP // Display help
/************************************************** ***************************/
// Functions:
/**
* GET SEED
*
* Gets a starting value for mysrand().
*
*/
uint16_t get_seed(void)
{
uint16_t seed = 0;
uint16_t *p = (uint16_t*) (RAMEND + 1);
extern uint16_t __heap_start;
while (p >= &__heap_start + 1)
seed ^= * (--p);
return seed;
}
/************************************************** ***************************/
//################################################## #########################
/************************************************** ***************************/
// micro-Max chess engine V4.8 by H. G. Muller:
// (http://home.hccnet.nl/h.g.muller/max-src2.html)
/************************************************** *************************/
/* micro-Max, */
/* A chess program smaller than 2KB (of non-blank source), by H.G. Muller */
/* Port to Atmel ATMega644 and AVR GCC, by Andre Adrian */
/* (http://www.andreadrian.de/schach/index.html) */
/************************************************** *************************/
/* version 4.8 (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 */
/* 26nov2008 no hash table */
/* 29nov2008 all IO via myputchar(), mygetchar(), pseudo random generator */
#define W while
#define M 0x88
#define S 128
#define I 8000
long N, T; /* N=evaluated positions+S, T=recursion limit */
short Q,O,K,R,k=16; /* k=moving side */
char *p,c[5],Z; /* p=pointer to c, c=user input,*/
/* computer output, Z=recursion counter */
char L,
w[]={0,2,2,7,-1,8,12,23}, /* relative piece values */
o[]={-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 o[] per piece*/
6,3,5,7,4,5,3,6}, /* initial piece setup */
b[]={ /* board is left part, center-pts table is right part, and dummy*/
22, 19, 21, 23, 20, 21, 19, 22, 28, 21, 16, 13, 12, 13, 16, 21,
18, 18, 18, 18, 18, 18, 18, 18, 22, 15, 10, 7, 6, 7, 10, 15,
0, 0, 0, 0, 0, 0, 0, 0, 18, 11, 6, 3, 2, 3, 6, 11,
0, 0, 0, 0, 0, 0, 0, 0, 16, 9, 4, 1, 0, 1, 4, 9,
0, 0, 0, 0, 0, 0, 0, 0, 16, 9, 4, 1, 0, 1, 4, 9,
0, 0, 0, 0, 0, 0, 0, 0, 18, 11, 6, 3, 2, 3, 6, 11,
9, 9, 9, 9, 9, 9, 9, 9, 22, 15, 10, 7, 6, 7, 10, 15,
14, 11, 13, 15, 12, 13, 11, 14, 28, 21, 16, 13, 12, 13, 16, 21, 0
};
volatile char breakpoint; /* for debugger */
/* User interface routines */
void myputchar(char c) {
writeChar_WIFI(c);
}
void myputs(const char *s) {
while(*s) myputchar(*s++);
myputchar('\n');
}
char mygetchar(void) {
char tmp;
do {tmp = readChar_WIFI();}
while (tmp == 0);
if(c[0] == 13) c[0] = 10;
return tmp;
// return 10; /* self play computer with computer */
}
/* 16bit pseudo random generator */
#define MYRAND_MAX 65535
unsigned short r = 1; /* pseudo random generator seed */
void mysrand(unsigned short r_) {
r = r_;
}
unsigned short myrand(void) {
return r=((r<<11)+(r<<7)+r)>>1;
}
short D(q,l,e,E,z,n) /* recursive minimax search */
short q,l,e; /* (q,l)=window, e=current eval. score, */
unsigned char E,z,n; /* E=e.p. sqr.z=prev.dest, n=depth; return score*/
{
short m,v,i,P,V,s;
unsigned char t,p,u,x,y,X,Y,H,B,j,d,h,F,G,C;
signed char r;
if (++Z>30) { /* stack underrun check */
breakpoint=1; /* AVR Studio 4 Breakpoint for stack underrun */
myputchar('u');
--Z;return e;
}
q--; /* adj. window: delay bonus */
k^=24; /* change sides */
d=Y=0; /* start iter. from scratch */
X=myrand()&~M; /* start at random field */
W(d++<n||d<3|| /* iterative deepening loop */
z&K==I&&(N<T&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:D(-l,1-l,-e,S,0,d-3); /* Search null move */
m=-P<l|R>35?d>2?-I:e:-P; /* Prune or stand-pat */
++N; /* node count (for timing) */
do{u=b[x]; /* scan board looking for */
if(u&k) /* own piece (inefficient!)*/
{r=p=u&7; /* p = piece type (set r>0) */
j=o[p+16]; /* first step vector f.piece*/
W(r=p>2&r<0?-r:-o[++j]) /* loop over directions o[] */
{A: /* resume normal after best */
y=x;F=G=S; /* (x,y)=move, (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=E-S&b[E]&&y-E<2&E-y<2?I:m; /* bad castling */
if(p<3&y==E)H^=16; /* shift capt.sqr. H if e.p.*/
t=b[H];if(t&k|p<3&!(y-x&7)-!t)break; /* capt. own, bad pawn mode */
i=37*w[t&7]+(t&192); /* value of capt. piece t */
m=i<0?I:m; /* K capture */
if(m>=l&d>1)goto C; /* abort on fail high */
v=d-1?e:i-p; /* MVV/LVA scoring */
if(d-!t>1) /* remaining depth */
{v=p<6?b[x+8]-b[y+8]:0; /* center positional pts. */
b[G]=b[H]=b[x]=0;b[y]=u|32; /* do move, set non-virgin */
if(!(G&M))b[F]=k+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||b[x-2]-u)+ /* structure, undefended */
(x+2&M||b[x+2]-u)-1 /* squares plus bias */
+(b[x^16]==k+36)) /* kling to non-virgin King */
-(R>>2); /* end-game Pawn-push bonus */
V=y+r+1&S?647-p:2*(u&y+16&32); /* promotion or 6/7th bonus */
b[y]+=V;i+=V; /* change piece, add score */
}
v+=e+i;V=m>q?m:q; /* new eval and alpha */
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?-D(-l,-V,-v, /* recursive eval. of reply */
F,0,C):v; /* or fail low if futile */
W(s>q&++C<d);v=s;
if(z&&K-I&&v+I&&x==K&y==L) /* move pending & in root: */
{Q=-e-i;O=F; /* exit if legal & found */
R+=i>>7;--Z;return l; /* captured non-P material */
}
b[G]=k+6;b[F]=b[y]=0;b[x]=u;b[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 A;} /* redo after doing old best*/
if(x+r-y|u&32| /* not 1st step,moved before*/
p>2&(p-4|j-7|| /* no P & no lateral K move,*/
b[G=x+3^r>>1&7]-k-6 /* no virgin R in corner G, */
||b[G^1]|b[G^2]) /* no 2 empty sq. next to R */
)t+=p<5; /* fake capt. for nonsliding*/
else F=y; /* enable e.p. */
}W(!t); /* if not capt. continue ray*/
}}}W((x=x+9&~M)-B); /* next sqr. of board, wrap */
C: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(z&&d>2)
{*c='a'+(X&7);c[1]='8'-(X>>4);c[2]='a'+(Y&7);c[3]='8'-(Y>>4&7);c[4]=0;
breakpoint=2; /* AVR Studio 4 Breakpoint for moves, watch c[] */
// printf("%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));/* uncomment for Kibitz */
}
} /* encoded in X S,8 bits */
k^=24; /* change sides back */
--Z;return m+=m<e; /* delayed-loss bonus */
}
//void print_board(void)
//{
// short N=-1;
// W(++N<121)
// myputchar(N&8&&(N+=7)?10:".?inkbrq?I?NKBRQ"[b[N]&15]); /* Pawn is i*/
//}
// micro-Max chess engine V4.8 end.
/************************************************** ***************************/
//################################################## #########################
/************************************************** ***************************/
void print_new_board(void)
{
myputs(" A B C D E F G H");
short N=-1;
W(++N<121)
{
if (N&8&&(N+=7)) {
myputchar(' ');
writeInteger_WIFI(8-(N>>4), DEC);
#ifdef HELP
myputchar(' ');
myputchar(' ');
switch(N)
{
case 15: myputs("kK = King");
break;
case 31: myputs("qQ = Queen");
break;
case 47: myputs("rR = Rook");
break;
case 63: myputs("nN = Knight");
break;
case 79: myputs("bB = Bishop");
break;
case 95: myputs("iI = Pawn");
break;
case 111: myputs("i = BLACK, I = WHITE Pawn");
break;
case 127: myputs("Move: c2c4<ENTER><ENTER>");
break;
default: myputchar(10);
}
#else
myputchar(10);
#endif
if (N < 127) writeInteger_WIFI(7-(N>>4), DEC);
}
else {
if (!N) myputchar('8');
myputchar(' ');
myputchar(".?inkbrq?I?NKBRQ"[b[N]&15]); /* Pawn is i*/
}
}
myputs(" A B C D E F G H");
}
/************************************************** ***************************/
// Main function - The program starts here:
int main(void)
{
initRP6M256(); // Always call this first! The Processor will not work
// correctly otherwise.
initLCD(); // Initialize the LC-Display (LCD)
// Always call this before using the LCD!
// Now write Text via the WIFI Interface:
writeString_P_WIFI("\n\n _______________________\n");
writeString_P_WIFI(" \\| RP6 ROBOT SYSTEM |/\n");
writeString_P_WIFI(" \\_-_-_-_-_-_-_-_-_-_/\n\n");
writeString_P_WIFI("Chess for RP6 CONTROL M256 WIFI!\n");
// Set the four Status LEDs:
setLEDs(0b1111);
mSleep(500);
setLEDs(0b0000);
showScreenLCD("################", "################");
mSleep(1500);
showScreenLCD("RP6v2-M256-WIFI ", "<<LC - DISPLAY>>");
mSleep(1500);
showScreenLCD(" Chess 1.1 ", " ************ ");
mSleep(1500);
clearLCD(); // Clear the whole LCD Screen
/************************************************** ***************************/
// micro-Max chess engine V4.8 (initialisation):
mysrand(get_seed()); /* make myrand() calls random */
// micro-Max chess engine V4.8 (play loop):
do{ /* play loop */
print_new_board();
myputs(c);
p=c;W((*p++=mygetchar())>10); /* read input line */
K=I; /* invalid move */
if(*c-10)K=*c-16*c[1]+799,L=c[2]-16*c[3]+799; /* parse entered move */
N=0;T=0x3F; /* T=Computer Play strength */
}W(D(-I,I,Q,O,1,3)>-I+1); /* think or check & do */
print_new_board();
/************************************************** ***************************/
return 0;
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.1 New board & help text added 03.01.2014 by Dirk
* - v. 1.0 (initial release) 03.01.2014 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
Hinweise:
1. Im makefile die Zeile:
OPT = s
... ersetzen durch:
OPT = 2
2. Die Warnungen beim Kompilieren ignorieren!
3. Die Ausgaben des Programms erfolgen auf dem WiFi Terminal.
Viel Spaß!
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.