//verwendete Bibliotheken:
//https://github.com/ThingPulse/esp8266-oled-ssd1306
//https://github.com/adafruit/Adafruit_NeoPixel
#define DEBUG 1
#if DEBUG == 1
#define debug(x) Serial.print(x)
#define debugln(x) Serial.println(x)
#else
#define debug(x)
#define debugln(x)
#endif
#include <Wire.h>
#include "SSD1306Wire.h"
#include <Adafruit_NeoPixel.h>
#define PIN 26
#define NUMPIXELS 1
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
SSD1306Wire display(0x3c, SDA, SCL);
//Portpins für Ein-/Ausgänge
const int Enc_A = 34, Enc_B = 35, Enc_Taster = 0;
const int LED_rot = 32, LED_gruen = 33, Taster_L = 2, Taster_R = 4;
//Globale Variablen
int Encoder, Status, auswahl, Spieler, game, aktiv, iX, iY, iComputer; // zur Kommunikation zw. ISR und loop
int felder [9];
const int16_t setx = display.getWidth() / 3;
const int16_t sety = display.getHeight() / 3;
//functions
void spielfeld(void);
void spiel(void);
void box(int16_t setx, int16_t sety);
void start(void);
void sieg(void);
void spieler1(int16_t setx, int16_t sety);
void spieler2(int16_t setx, int16_t sety);
void Pos(void);
void Auswertung();
void AuswertungL();
void AuswertungR();
void computer();
void gegenComputer(void);
void taktik(int x);
void fehler();
void spielfeld(void) {
int16_t drittelx = display.getWidth() / 3;
int16_t drittely = display.getHeight() / 3;
display.drawLine(drittelx, display.getHeight() , drittelx, 0);
display.drawLine(drittelx * 2, display.getHeight() , drittelx * 2, 0);
display.drawLine(display.getWidth(), drittely, 0 , drittely);
display.drawLine(display.getWidth(), drittely * 2, 0 , drittely * 2);
display.display();
}
void spiel(void) {
Pos();
box(setx * iX, sety * iY);
if (Spieler == 1 and auswahl == 1 and felder[Encoder] == 0) {
spieler1(setx * iX , sety * iY);
auswahl = 0;
felder[Encoder] = 1;
sieg();
do {
Encoder ++;
fehler();
} while (felder[Encoder] != 0);
Pos();
box(setx * iX, sety * iY);
digitalWrite(LED_rot, HIGH);
digitalWrite(LED_gruen, LOW);
}
else if (Spieler == 2 and auswahl == 1 and felder[Encoder] == 0) {
spieler2(setx * iX , sety * iY);
auswahl = 0;
felder[Encoder] = 2;
sieg();
do {
Encoder ++;
fehler();
} while (felder[Encoder] != 0);
Pos();
box(setx * iX, sety * iY);
digitalWrite(LED_gruen, HIGH);
digitalWrite(LED_rot, LOW);
}
else if (iComputer == 1 and Spieler == 2) {
computer();
}
}
void box(int16_t setx, int16_t sety) {
setx = setx - (display.getWidth() / 3) / 2;
sety = sety - (display.getHeight() / 3) / 2;
display.setColor(WHITE); // alternate colors
char* text[1];
if (Spieler == 1) text[0] = "X";
else text[0] = "O";
display.drawString(setx - 3, sety - 6, text[0]);
display.display();
display.setColor(BLACK); // alternate colors
display.drawString(setx - 3, sety - 6, text[0]);
display.setColor(WHITE);
delay(100);
aktiv = 0;
}
void start(void) {
display.setLogBuffer(5, 30);
display.println("Tic Tac Toe");
display.drawLogBuffer(0, 0);
for (uint8_t i = 0; i < 101; i++) {
display.drawProgressBar(0, display.getHeight() / 2 - 10, display.getWidth() - 1, 20, i);
display.display();
delay(15);
}
display.clear();
debug("Start zu ende");
}
void sieg(void) {
display.display();
display.setLogBuffer(5, 30);
aktiv = 0;
if (felder[0] == 1 and felder [1] == 1 and felder [2] == 1 or
felder[3] == 1 and felder [4] == 1 and felder [5] == 1 or
felder[6] == 1 and felder [7] == 1 and felder [8] == 1 or
felder[0] == 1 and felder [4] == 1 and felder [8] == 1 or
felder[2] == 1 and felder [4] == 1 and felder [6] == 1 or
felder[1] == 1 and felder [4] == 1 and felder [7] == 1 or
felder[2] == 1 and felder [5] == 1 and felder [8] == 1 or
felder[0] == 1 and felder [3] == 1 and felder [6] == 1) {
delay(2000);
display.clear();
game = 0;
const char* test[1] = {
"Spieler X hat gewonnen!"
};
display.println(test[0]);
display.drawLogBuffer(0, 0);
display.display();
pixels.setPixelColor(0, pixels.Color(100, 0, 0)); // Moderately bright green color.
pixels.show(); // This sends the updated pixel color to the hardware.
delay(4000);
pixels.setPixelColor(0, pixels.Color(0, 0, 0)); // Moderately bright green color.
pixels.show(); // This sends the updated pixel color to the hardware.
display.clear();
}
else if (felder[0] == 2 and felder [1] == 2 and felder [2] == 2 or
felder[3] == 2 and felder [4] == 2 and felder [5] == 2 or
felder[6] == 2 and felder [7] == 2 and felder [8] == 2 or
felder[0] == 2 and felder [4] == 2 and felder [8] == 2 or
felder[2] == 2 and felder [4] == 2 and felder [6] == 2 or
felder[1] == 2 and felder [4] == 2 and felder [7] == 2 or
felder[2] == 2 and felder [5] == 2 and felder [8] == 2 or
felder[0] == 2 and felder [3] == 2 and felder [6] == 2) {
delay(2000);
display.clear();
game = 0;
char* test[1];
if (iComputer == 0) test[0] = { "Spieler O hat gewonnen!" };
else test[0] = { "Computer hat gewonnen!" };
display.println(test[0]);
display.drawLogBuffer(0, 0);
display.display();
pixels.setPixelColor(0, pixels.Color(0, 100, 0)); // Moderately bright green color.
pixels.show(); // This sends the updated pixel color to the hardware.
delay(4000);
pixels.setPixelColor(0, pixels.Color(0, 0, 0)); // Moderately bright green color.
pixels.show(); // This sends the updated pixel color to the hardware.
display.clear();
}
else if (felder[0] != 0 and felder[1] != 0 and felder[2] != 0 and
felder[3] != 0 and felder[4] != 0 and felder[5] != 0 and
felder[6] != 0 and felder[7] != 0 and felder[8] != 0) {
felder[8] = 0;
delay(2000);
display.clear();
game = 0;
const char* test[1] = {
"Unentschieden ..."
};
display.println(test[0]);
display.drawLogBuffer(0, 0);
display.display();
delay(4000);
display.clear();
}
}
void spieler1(int16_t setx, int16_t sety) {
setx = setx - (display.getWidth() / 3) / 2;
sety = sety - (display.getHeight() / 3) / 2;
int16_t x = (display.getWidth() / 3) / 4;
int16_t y = (display.getHeight() / 3) / 4;
display.drawLine(setx - x, sety - y, setx + x, sety + y);
display.drawLine(setx + x, sety - y, setx - x, sety + y);
Spieler = 2;
display.display();
}
void spieler2(int16_t setx, int16_t sety) {
setx = setx - (display.getWidth() / 3) / 2;
sety = sety - (display.getHeight() / 3) / 2;
display.drawCircleQuads(setx, sety, 8, 0b00001111);
Spieler = 1;
display.display();
}
void Pos(void) {
switch ( Encoder )
{
case 0:
iY = 1;
iX = 1;
break;
case 1:
iY = 1;
iX = 2;
break;
case 2:
iY = 1;
iX = 3;
break;
case 3:
iY = 2;
iX = 1;
break;
case 4:
iY = 2;
iX = 2;
break;
case 5:
iY = 2;
iX = 3;
break;
case 6:
iY = 3;
iX = 1;
break;
case 7:
iY = 3;
iX = 2;
break;
case 8:
iY = 3;
iX = 3;
break;
default:
iY = 0;
iX = 0;
}
}
void setup() {
Serial.begin(115200); // Serielle Schnittstelle mit 115200Bit/s
pinMode(LED_rot, OUTPUT); // die LEDs beginnen danach
pinMode(LED_gruen, OUTPUT); // zu leuchten!
Serial.print("LED Test");
digitalWrite(LED_rot, LOW);
digitalWrite(LED_gruen, LOW);
delay(2000);
digitalWrite(LED_rot, HIGH);
digitalWrite(LED_gruen, HIGH);
pinMode(Taster_L, INPUT_PULLUP); // Taster brauchen hier den
pinMode(Taster_R, INPUT_PULLUP); // Pullup-Widerstand
display.init();
display.flipScreenVertically();
display.setContrast(255);
pinMode(Enc_A, INPUT); // externe Pullups auf der Platine
pinMode(Enc_B, INPUT); // Spur B des Encoders
pinMode(Enc_Taster, INPUT_PULLUP); // Taster des Encoders = Flash-Taster!
attachInterrupt(digitalPinToInterrupt(Enc_A), Auswertung, RISING); // ISR void Auswertung(void)
// use the input in polling-mode first. Attach interrupt after start of the game
//attachInterrupt(digitalPinToInterrupt(Taster_L), AuswertungL, FALLING); // ISR void Auswertung(void)
attachInterrupt(digitalPinToInterrupt(Taster_R), AuswertungR, FALLING); // ISR void Auswertung(void)
Encoder = 1;
Status = 0;
Spieler = 1;
game = 0;
aktiv = 0;
iComputer = 2;
iX = 2;
iY = 1;
digitalWrite(LED_gruen, HIGH);
digitalWrite(LED_rot, LOW);
}
void loop() {
delay(10);
if (game == 0) {
for (int i = 0; i < 9; ++i) {
felder[i] = 0;
}
start();
if (iComputer == 2) {
gegenComputer();
}
spielfeld();
game = 1;
box(display.getWidth() / 3 * iX, display.getHeight() / 3 * iY);
}
if (digitalRead(Enc_Taster) == false) {
auswahl = 1;
while (digitalRead(Enc_Taster) == false); // warte auf loslassen
}
if (Status == 1 or auswahl == 1 or iComputer == 1 and Spieler == 2) {
spiel();
Status = 0; // Signal wieder löschen
}
for (int i = 0; i < 9; ++i) {
Serial.printf("%4d", felder[i]);
}
Serial.printf("\n");
}
//Einzelspieler (gegen Computer)
void gegenComputer(void) {
//noInterrupts();
const char* test[2] = {
"Halte Taster 2 gedrückt,", "für Einzelspieler."
};
display.println(test[0]);
display.println(test[1]);
display.drawLogBuffer(0, 0);
display.display();
delay(3000);
if ( digitalRead(Taster_L) == false ) { // low-aktiv, daher false
iComputer = 1;
}
else iComputer = 0;
display.clear();
//interrupts();
attachInterrupt(digitalPinToInterrupt(Taster_L), AuswertungL, FALLING); // ISR void Auswertung(void)
}
void taktik(int x) {
if (felder[0] == x and felder [1] == x and felder [2] == 0) {
spieler2(setx * 3 , sety * 1);
Encoder = 2;
return;
}
if (felder[0] == x and felder [1] == 0 and felder [2] == x) {
spieler2(setx * 2 , sety * 1);
Encoder = 1;
return;
}
if (felder[0] == 0 and felder [1] == x and felder [2] == x) {
spieler2(setx * 1 , sety * 1);
Encoder = 0;
return;
}
if (felder[3] == x and felder [4] == x and felder [5] == 0) {
spieler2(setx * 3 , sety * 2);
Encoder = 5;
return;
}
if (felder[3] == x and felder [4] == 0 and felder [5] == x) {
spieler2(setx * 2 , sety * 2);
Encoder = 4;
return;
}
if (felder[3] == 0 and felder [4] == x and felder [5] == x) {
spieler2(setx * 1 , sety * 2);
Encoder = 3;
return;
}
if (felder[6] == x and felder [7] == x and felder [8] == 0) {
spieler2(setx * 3 , sety * 3);
Encoder = 8;
return;
}
if (felder[6] == x and felder [7] == 0 and felder [8] == x) {
spieler2(setx * 2 , sety * 3);
Encoder = 7;
return;
}
if (felder[6] == 0 and felder [7] == x and felder [8] == x) {
spieler2(setx * 1 , sety * 3);
Encoder = 6;
return;
}
if (felder[0] == x and felder [4] == x and felder [8] == 0) {
spieler2(setx * 3 , sety * 3);
Encoder = 8;
return;
}
if (felder[0] == x and felder [4] == 0 and felder [8] == x) {
spieler2(setx * 2 , sety * 2);
Encoder = 4;
return;
}
if (felder[0] == 0 and felder [4] == x and felder [8] == x) {
spieler2(setx * 1 , sety * 1);
Encoder = 0;
return;
}
if (felder[2] == x and felder [4] == x and felder [6] == 0) {
spieler2(setx * 1 , sety * 3);
Encoder = 6;
return;
}
if (felder[2] == x and felder [4] == 0 and felder [6] == x) {
spieler2(setx * 2 , sety * 2);
Encoder = 4;
return;
}
if (felder[2] == 0 and felder [4] == x and felder [6] == x) {
spieler2(setx * 3 , sety * 1);
Encoder = 2;
return;
}
if (felder[1] == x and felder [4] == x and felder [7] == 0) {
spieler2(setx * 2 , sety * 3);
Encoder = 7;
return;
}
if (felder[1] == x and felder [4] == 0 and felder [7] == x) {
spieler2(setx * 2 , sety * 2);
Encoder = 4;
return;
}
if (felder[1] == 0 and felder [4] == x and felder [7] == x) {
spieler2(setx * 2 , sety * 1);
Encoder = 1;
return;
}
if (felder[2] == x and felder [5] == x and felder [8] == 0) {
spieler2(setx * 3 , sety * 3);
Encoder = 8;
return;
}
if (felder[2] == x and felder [5] == 0 and felder [8] == x) {
spieler2(setx * 3 , sety * 2);
Encoder = 5;
return;
}
if (felder[2] == 0 and felder [5] == x and felder [8] == x) {
spieler2(setx * 3 , sety * 1);
Encoder = 2;
return;
}
if (felder[0] == x and felder [3] == x and felder [6] == 0) {
spieler2(setx * 1 , sety * 3);
Encoder = 6;
return;
}
if (felder[0] == x and felder [3] == 0 and felder [6] == x) {
spieler2(setx * 1 , sety * 2);
Encoder = 3;
return;
}
if (felder[0] == 0 and felder [3] == x and felder [6] == x) {
spieler2(setx * 1 , sety * 1);
Encoder = 0;
return;
}
}
void computer() {
int i = 0;
if (Spieler == 2) taktik(2);
if (Spieler == 2) taktik(1);
if (Spieler == 2) {
srand(time(0));
do {
i = rand() % 9;
} while (felder[i] != 0);
Encoder = i;
Pos();
spieler2(setx * iX , sety * iY);
}
felder[Encoder] = 2;
sieg();
do {
Encoder ++;
fehler();
} while (felder[Encoder] != 0);
Pos();
box(setx * iX, sety * iY);
digitalWrite(LED_gruen, HIGH);
digitalWrite(LED_rot, LOW);
}
//Interrupts
void Auswertung() {
debug("Encoder-ISR");
aktiv = ++aktiv;
if (aktiv == 1) {
if (digitalRead(Enc_B) == false) {
do {
Encoder ++;
fehler();
} while (felder[Encoder] != 0);
}
else {
do {
Encoder --;
fehler();
} while (felder[Encoder] != 0);
}
Status = 1; // Signal an loop geben
}
debug(Encoder);
}
void AuswertungL( ) {
debug("Taster-ISR");
aktiv = ++aktiv;
if (aktiv == 1) {
do {
Encoder --;
fehler();
} while (felder[Encoder] != 0);
Status = 1; // Signal an loop geben
}
debug(Encoder);
}
void AuswertungR( ) {
debug("Taster2-ISR");
aktiv = ++aktiv;
if (aktiv == 1) {
do {
Encoder ++;
fehler();
} while (felder[Encoder] != 0);
Status = 1; // Signal an loop geben
}
debug(Encoder);
}
void fehler() {
if (Encoder < 0) {
Encoder = 8;
}
else if (Encoder > 8) {
Encoder = 0;
}
}
Taster2
Taster4
LED32
LED33
ESP32 Schulboard mit LEDs und Tastern, I2C-Bus mit Standard-Belegung
SSD1306 Display
WS2812 an Pin26