PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6: Sammlung von Spielen und anderen Mini-Programmen



Dirk
24.05.2011, 21:37
Hallo Leute,

bei mir gibt es immer mal wieder kleinere Spiele oder Mini-Programme, die ich mit der RP6Base, der RP6Control M32, der CCPro M128 oder der RP6 Control M256 WiFi umsetze - "just for fun".

Diese Progrämmchen haben nichts mit dem Roboter an sich zu tun, sondern sollen nur zeigen, was sonst noch mit der Hardware machbar ist.

Deshalb mache ich hier mal einen "Spiele-Miniprogramme-Thread" auf. Die Spiele sollten keine zusätzliche Hardware brauchen,- und wenn doch, kann man die natürlich hier auch vorstellen.

In diesem Thread gibt es schon 2 kleine Spiele bzw. Simulationen:
https://www.roboternetz.de/community/showthread.php?53015-RP6Control-M32-Conway-s-Game-Of-Life

Wenn ihr auch eigene kleine Progrämmchen einstellen wollt, aktualisiere ich für jedes neue Programm diese Liste:

1. Conway's Game Of Life --- Das Spiel des Lebens auf Zellebene
2. Doc Z --- Ein Mini-Psychiater
3. Kalaha --- Ein altes "Bohnenspiel"
4. Oware --- Eines der ältesten Spiele der Welt
5. Merry Christmas --- Alle Jahre wieder ...
6. Chess --- Schach, das königliche Spiel

Dirk
24.05.2011, 21:40
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ß!

Dirk
18.06.2011, 20:34
Hier das Spiel Oware. Es ist eines der ältesten Spiele der Welt und deutlich komplexer als Kalaha.
Versucht 'mal, gegen euren ATMega32 zu gewinnen ... nicht ganz einfach.
Aber: Die "KI" läßt sich noch deutlich verbessern!

Infos dazu: http://de.wikipedia.org/wiki/Oware

Viel Spaß!

Dirk
14.12.2013, 12:36
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;
}

Dirk
03.01.2014, 21:28
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ß!