You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
392 lines
8.7 KiB
392 lines
8.7 KiB
/* |
|
|
|
TicTacToeDe.ino |
|
|
|
*/ |
|
|
|
#include <Arduino.h> |
|
#include <U8g2lib.h> |
|
|
|
|
|
/*==============================================*/ |
|
/* Konstante Werte */ |
|
|
|
#define GITTER_X_OFFSET 35 |
|
#define GITTER_Y_OFFSET 2 |
|
#define ZELLE_BREITE 17 |
|
#define ZELLE_HOEHE 17 |
|
#define ZELLE_RAHMENBREITE 3 |
|
|
|
#define FELD_NICHT_BELEGT 0 |
|
#define FELD_MARKIERT_DURCH_SPIELER 1 |
|
#define FELD_MARKIERT_DURCH_COMPUTER 2 |
|
|
|
/*==============================================*/ |
|
/* Variablen */ |
|
|
|
/* U8g2 Graphics API, setup for ARDUBOY Production, Kickstarter Edition */ |
|
U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 12, /* dc=*/ 4, /* reset=*/ 6); |
|
|
|
uint8_t cursor_position; /* Aktuelle Cursorposition die vom User ausgewählt wurde */ |
|
u8g2_uint_t zelle_x, zelle_y; /* Berechnete Position einer Zelle (berechne_zell_position) */ |
|
|
|
int spielfeld[3][3]; /* Enthält die aktuelle Belegung mit x und o */ |
|
int gewinner; /* Zeigt den gewinner an (wenn es einen gibt) */ |
|
|
|
/*==============================================*/ |
|
/* vorbelegung und spiel initalisierenalisierung */ |
|
void spiel_initalisieren(void) |
|
{ |
|
int x, y; |
|
|
|
gewinner = FELD_NICHT_BELEGT; |
|
for( y = 0; y < 3; y = y + 1 ) |
|
{ |
|
for( x = 0; x < 3; x = x + 1 ) |
|
{ |
|
spielfeld[y][x] = FELD_NICHT_BELEGT; |
|
} |
|
} |
|
} |
|
|
|
|
|
/*==============================================*/ |
|
/* Hilfsroutine */ |
|
|
|
/* berechne die Zell-Position, Ergebnis in zelle_x und zelle_y */ |
|
void berechne_zell_position(uint8_t x, uint8_t y ) |
|
{ |
|
zelle_x = x; |
|
zelle_x*=ZELLE_BREITE+ZELLE_RAHMENBREITE; |
|
zelle_x+= GITTER_X_OFFSET; |
|
zelle_y = y; |
|
zelle_y *=ZELLE_HOEHE+ZELLE_RAHMENBREITE; |
|
zelle_y +=GITTER_Y_OFFSET; |
|
} |
|
|
|
/*==============================================*/ |
|
/* "game engine" */ |
|
|
|
void zeichne_gitter(void) |
|
{ |
|
u8g2_uint_t x, y; |
|
x = GITTER_X_OFFSET+ZELLE_BREITE; |
|
u8g2.drawVLine(x+1, GITTER_Y_OFFSET, ZELLE_HOEHE*3+ZELLE_RAHMENBREITE*2); |
|
x += ZELLE_BREITE+ZELLE_RAHMENBREITE; |
|
u8g2.drawVLine(x+1, GITTER_Y_OFFSET, ZELLE_HOEHE*3+ZELLE_RAHMENBREITE*2); |
|
|
|
y = GITTER_Y_OFFSET+ZELLE_HOEHE; |
|
u8g2.drawHLine(GITTER_X_OFFSET, y+1, ZELLE_BREITE*3+ZELLE_RAHMENBREITE*2); |
|
y += ZELLE_HOEHE+ZELLE_RAHMENBREITE; |
|
u8g2.drawHLine(GITTER_X_OFFSET, y+1, ZELLE_BREITE*3+ZELLE_RAHMENBREITE*2); |
|
} |
|
|
|
void zeichne_spielfeld(void) |
|
{ |
|
int x, y; |
|
for( y = 0; y < 3; y = y + 1 ) |
|
{ |
|
for( x = 0; x < 3; x = x + 1 ) |
|
{ |
|
if ( spielfeld[y][x] == FELD_NICHT_BELEGT ) |
|
{ |
|
/* nichts anzeigen */ |
|
} |
|
if ( spielfeld[y][x] == FELD_MARKIERT_DURCH_SPIELER ) |
|
{ |
|
berechne_zell_position(x, y); |
|
u8g2.drawLine(zelle_x, zelle_y, zelle_x+ZELLE_BREITE-1, zelle_y+ZELLE_HOEHE-1); |
|
u8g2.drawLine(zelle_x+ZELLE_BREITE-1, zelle_y, zelle_x, zelle_y+ZELLE_HOEHE-1); |
|
} |
|
if ( spielfeld[y][x] == FELD_MARKIERT_DURCH_COMPUTER ) |
|
{ |
|
berechne_zell_position(x, y); |
|
u8g2.drawCircle(zelle_x+ZELLE_BREITE/2, zelle_y+ZELLE_HOEHE/2, ZELLE_HOEHE/2); |
|
} |
|
} /* for x */ |
|
} /* for y */ |
|
} |
|
|
|
void zeichne_gitter_und_spielfeld(void) |
|
{ |
|
zeichne_gitter(); |
|
zeichne_spielfeld(); |
|
} |
|
|
|
void zeige_spielfeld_an(void) |
|
{ |
|
u8g2.firstPage(); |
|
do |
|
{ |
|
yield(); // Arduino |
|
zeichne_gitter_und_spielfeld(); |
|
} while ( u8g2.nextPage() ); |
|
} |
|
|
|
/*==============================================*/ |
|
/* Benitzerschnittstelle (User Interface) */ |
|
|
|
/* Zeichne den Cursor für die Benutzereingabe */ |
|
void zeichne_cursor(void) |
|
{ |
|
u8g2_uint_t x, y; |
|
x = cursor_position % 3; |
|
y = cursor_position / 3; |
|
berechne_zell_position(x, y ); |
|
u8g2.drawFrame(zelle_x, zelle_y, ZELLE_BREITE, ZELLE_HOEHE); |
|
u8g2.drawFrame(zelle_x+1, zelle_y+1, ZELLE_BREITE-2, ZELLE_HOEHE-2); |
|
} |
|
|
|
void zug_spieler(void) |
|
{ |
|
static uint8_t keycode = 0; |
|
int x; |
|
int y; |
|
int zaehler = 0; |
|
|
|
for(;;) /* check valid entry */ |
|
{ |
|
for(;;) /* cursor movement loop */ |
|
{ |
|
keycode = 0; |
|
u8g2.firstPage(); |
|
do |
|
{ |
|
zeichne_gitter_und_spielfeld(); |
|
zeichne_cursor(); |
|
if ( keycode == 0 ) |
|
keycode = u8g2.getMenuEvent(); |
|
} while ( u8g2.nextPage() ); |
|
|
|
while ( keycode == 0 ) |
|
{ |
|
yield(); // Arduino |
|
keycode = u8g2.getMenuEvent(); |
|
} |
|
|
|
if ( keycode == U8X8_MSG_GPIO_MENU_DOWN ) |
|
{ |
|
cursor_position += 3; |
|
if ( cursor_position > 9 ) |
|
cursor_position -= 9; |
|
} |
|
|
|
if ( keycode == U8X8_MSG_GPIO_MENU_NEXT ) |
|
{ |
|
if ( cursor_position % 3 == 2 ) |
|
cursor_position-=2; |
|
else |
|
cursor_position += 1; |
|
} |
|
|
|
if ( keycode == U8X8_MSG_GPIO_MENU_UP ) |
|
{ |
|
cursor_position -= 3; |
|
if ( cursor_position > 9 ) |
|
cursor_position += 9; |
|
} |
|
|
|
if ( keycode == U8X8_MSG_GPIO_MENU_PREV ) |
|
{ |
|
if ( cursor_position % 3 == 0 ) |
|
cursor_position+=2; |
|
else |
|
cursor_position -= 1; |
|
} |
|
cursor_position = cursor_position % 9; |
|
|
|
if ( keycode == U8X8_MSG_GPIO_MENU_SELECT ) |
|
break; |
|
if ( keycode == U8X8_MSG_GPIO_MENU_HOME ) |
|
break; |
|
} |
|
|
|
y = cursor_position / 3; |
|
x = cursor_position % 3; |
|
|
|
if ( spielfeld[y][x] == FELD_NICHT_BELEGT ) |
|
{ |
|
spielfeld[y][x] = FELD_MARKIERT_DURCH_SPIELER ; |
|
return; |
|
} |
|
|
|
/* |
|
if ( zaehler > 3 ) |
|
{ |
|
printf("Du doedl, jetzt langts aber...\n"); |
|
exit(1); |
|
} |
|
printf("Ahh, das feld ist schon belegt, nochmal...\n"); |
|
zaehler = zaehler + 1; |
|
*/ |
|
} |
|
} |
|
|
|
/*==============================================*/ |
|
/* Künstliche Computer Intelligenz */ |
|
|
|
void zug_computer(void) |
|
{ |
|
int x, y; |
|
|
|
/* Sehr dumme AI: Nimm den nächsten freien Platz */ |
|
|
|
for( y = 0; y < 3; y = y + 1 ) |
|
{ |
|
for( x = 0; x < 3; x = x + 1 ) |
|
{ |
|
if ( spielfeld[y][x] == FELD_NICHT_BELEGT ) |
|
{ |
|
spielfeld[y][x] = FELD_MARKIERT_DURCH_COMPUTER; |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/*==============================================*/ |
|
/* Spiel Zuende Prüfung */ |
|
|
|
/* gibt 1 zurück, wenn in der zeile überall markierung gesetzt ist */ |
|
int zeile_gewonnen(int y, int markierung) |
|
{ |
|
int x; |
|
for( x = 0; x < 3; x++ ) |
|
{ |
|
if ( spielfeld[y][x] != markierung ) |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
/* gibt 1 zurück, wenn in der zeile überall markierung gesetzt ist */ |
|
int spalte_gewonnen(int x, int markierung) |
|
{ |
|
int y; |
|
for( y = 0; y < 3; y++ ) |
|
{ |
|
if ( spielfeld[y][x] != markierung ) |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
int diagonale_gewonnen(int markierung) |
|
{ |
|
int i; |
|
|
|
for( i = 0; i < 3; i ++ ) |
|
{ |
|
if ( spielfeld[i][i] != markierung ) |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
int inverse_diagonale_gewonnen(int markierung) |
|
{ |
|
int i; |
|
|
|
for( i = 0; i < 3; i ++ ) |
|
{ |
|
if ( spielfeld[2-i][i] != markierung ) |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
int ist_das_spiel_zuende(void) |
|
{ |
|
int i, x, y; |
|
int ist_alles_voll; |
|
|
|
zeige_spielfeld_an(); |
|
|
|
for( i = 0; i < 3; i ++ ) |
|
{ |
|
if ( zeile_gewonnen(i, FELD_MARKIERT_DURCH_SPIELER) ) |
|
gewinner = FELD_MARKIERT_DURCH_SPIELER; |
|
if ( zeile_gewonnen(i, FELD_MARKIERT_DURCH_COMPUTER) ) |
|
gewinner = FELD_MARKIERT_DURCH_COMPUTER; |
|
if ( spalte_gewonnen(i, FELD_MARKIERT_DURCH_SPIELER) ) |
|
gewinner = FELD_MARKIERT_DURCH_SPIELER; |
|
if ( spalte_gewonnen(i, FELD_MARKIERT_DURCH_COMPUTER) ) |
|
gewinner = FELD_MARKIERT_DURCH_COMPUTER; |
|
} |
|
if ( diagonale_gewonnen(FELD_MARKIERT_DURCH_SPIELER) ) |
|
gewinner = FELD_MARKIERT_DURCH_SPIELER; |
|
if ( diagonale_gewonnen(FELD_MARKIERT_DURCH_COMPUTER) ) |
|
gewinner = FELD_MARKIERT_DURCH_COMPUTER; |
|
|
|
if ( inverse_diagonale_gewonnen(FELD_MARKIERT_DURCH_SPIELER) ) |
|
gewinner = FELD_MARKIERT_DURCH_SPIELER; |
|
if ( inverse_diagonale_gewonnen(FELD_MARKIERT_DURCH_COMPUTER) ) |
|
gewinner = FELD_MARKIERT_DURCH_COMPUTER; |
|
|
|
if ( gewinner != FELD_NICHT_BELEGT ) |
|
return 1; |
|
|
|
ist_alles_voll = 1; |
|
for( y = 0; y < 3; y = y + 1 ) |
|
{ |
|
for( x = 0; x < 3; x = x + 1 ) |
|
{ |
|
if ( spielfeld[y][x] == FELD_NICHT_BELEGT ) |
|
{ |
|
ist_alles_voll = 0; |
|
} |
|
} |
|
} |
|
|
|
|
|
if ( ist_alles_voll ) |
|
return 1; |
|
|
|
return 0; |
|
} |
|
|
|
/*==============================================*/ |
|
|
|
void zeige_ergebnis_an(void) |
|
{ |
|
u8g2.setFont(u8g2_font_helvB12_tr); |
|
if ( gewinner == FELD_MARKIERT_DURCH_SPIELER ) |
|
u8g2.userInterfaceMessage("Spieler", "gewinnt", "", " ok "); |
|
else if ( gewinner == FELD_MARKIERT_DURCH_COMPUTER ) |
|
u8g2.userInterfaceMessage("Computer", "gewinnt", "", " ok "); |
|
else |
|
u8g2.userInterfaceMessage("", "Unentschieden", "", " ok "); |
|
} |
|
|
|
/*==============================================*/ |
|
|
|
void setup(void) // Arduino setup |
|
{ |
|
// Intialisierung für Arduboy (Production) |
|
u8g2.begin(/*Select=*/ 7, /*Right/Next=*/ A1, /*Left/Prev=*/ A2, /*Up=*/ A0, /*Down=*/ A3, /*Home/Cancel=*/ 8); |
|
} |
|
|
|
void loop(void) // Arduino loop |
|
{ |
|
spiel_initalisieren(); |
|
zeige_spielfeld_an(); |
|
for(;;) |
|
{ |
|
zug_spieler(); |
|
zeige_spielfeld_an(); |
|
if ( ist_das_spiel_zuende() ) |
|
{ |
|
break; |
|
} /* if */ |
|
delay(300); |
|
zug_computer(); |
|
zeige_spielfeld_an(); |
|
if ( ist_das_spiel_zuende() ) |
|
{ |
|
break; |
|
} /* if */ |
|
|
|
} /* for */ |
|
zeige_ergebnis_an(); |
|
} |
|
|
|
|