TicTacToeDe

This commit is contained in:
kraus 2018-10-07 17:13:35 +02:00
parent 1c8ddc40d0
commit c858774383
2 changed files with 540 additions and 0 deletions

View File

@ -0,0 +1,148 @@
#
# Makefile.184 for Arduino/AVR
#
# Note:
# Display list make database: make -p -f/dev/null | less
# Install path of the arduino software. Requires a '/' at the end.
ARDUINO_PATH:=/home/kraus/prg/arduino-1.8.4/
# Board (and prozessor) information: see $(ARDUINO_PATH)hardware/arduino/avr/boards.txt
# Some examples:
# BOARD DESCRIPTION
# uno Arduino Uno
# atmega328 Arduino Duemilanove or Nano w/ ATmega328
# diecimila Arduino Diecimila, Duemilanove, or Nano w/ ATmega168
# mega Arduino Mega
# mega2560 Arduino Mega2560
# mini Arduino Mini
# lilypad328 LilyPad Arduino w/ ATmega328
# leonardo Leonardo, Arduboy, Feather AVR
BOARD:=leonardo
# The unix device where we can reach the arduino board
# Uno: /dev/ttyACM0
# Duemilanove: /dev/ttyUSB0
AVRDUDE_PORT:=/dev/ttyACM0
SRC_DIRS=$(ARDUINO_PATH)hardware/arduino/avr/cores/arduino/
SRC_DIRS+=$(ARDUINO_PATH)hardware/arduino/avr/libraries/SPI/src/
SRC_DIRS+=$(ARDUINO_PATH)hardware/arduino/avr/libraries/SPI/src/utility/
SRC_DIRS+=$(ARDUINO_PATH)hardware/arduino/avr/libraries/Wire/src/
SRC_DIRS+=$(ARDUINO_PATH)hardware/arduino/avr/libraries/Wire/src/utility/
SRC_DIRS+=../../../../csrc/
SRC_DIRS+=../../../../cppsrc/
#=== suffixes ===
.SUFFIXES: .elf .hex .ino
#=== identify user files ===
INOSRC:=$(shell ls *.ino)
TARGETNAME=$(basename $(INOSRC))
#=== internal names ===
LIBNAME:=$(TARGETNAME).a
ELFNAME:=$(TARGETNAME).elf
HEXNAME:=$(TARGETNAME).hex
BINNAME:=$(TARGETNAME).bin
DISNAME:=$(TARGETNAME).dis
MAPNAME:=$(TARGETNAME).map
#=== replace standard tools ===
CC:=$(ARDUINO_PATH)hardware/tools/avr/bin/avr-gcc
CXX:=$(ARDUINO_PATH)hardware/tools/avr/bin/avr-g++
AR:=$(ARDUINO_PATH)hardware/tools/avr/bin/avr-gcc-ar
OBJCOPY:=$(ARDUINO_PATH)hardware/tools/avr/bin/avr-objcopy
OBJDUMP:=$(ARDUINO_PATH)hardware/tools/avr/bin/avr-objdump
SIZE:=$(ARDUINO_PATH)hardware/tools/avr/bin/avr-size
AVRDUDE = $(ARDUINO_PATH)hardware/tools/avr/bin/avrdude
#=== get values from boards.txt ===
BOARDS_TXT:=$(ARDUINO_PATH)hardware/arduino/avr/boards.txt
# get the MCU value from the $(BOARD).build.mcu variable. For the atmega328 board this is atmega328p
MCU:=$(shell sed -n -e "s/$(BOARD).build.mcu=\(.*\)/\1/p" $(BOARDS_TXT))
# get the F_CPU value from the $(BOARD).build.f_cpu variable. For the atmega328 board this is 16000000
F_CPU:=$(shell sed -n -e "s/$(BOARD).build.f_cpu=\(.*\)/\1/p" $(BOARDS_TXT))
# get variant subfolder
VARIANT:=$(shell sed -n -e "s/$(BOARD).build.variant=\(.*\)/\1/p" $(BOARDS_TXT))
UPLOAD_SPEED:=$(shell sed -n -e "s/$(BOARD).upload.speed=\(.*\)/\1/p" $(BOARDS_TXT))
# get the AVRDUDE_PROGRAMMER value from the $(BOARD).upload.protocol variable. For the atmega328 board this is stk500
UPLOAD_PROTOCOL:=$(shell sed -n -e "s/$(BOARD).upload.protocol=\(.*\)/\1/p" $(BOARDS_TXT))
# use stk500v1, because stk500 will default to stk500v2
#UPLOAD_PROTOCOL:=stk500v1
AVRDUDE_FLAGS = -V -F
AVRDUDE_FLAGS += -C $(ARDUINO_PATH)/hardware/tools/avr/etc/avrdude.conf
AVRDUDE_FLAGS += -p $(MCU)
AVRDUDE_FLAGS += -P $(AVRDUDE_PORT)
AVRDUDE_FLAGS += -c $(UPLOAD_PROTOCOL)
AVRDUDE_FLAGS += -b $(UPLOAD_SPEED)
AVRDUDE_FLAGS += -U flash:w:$(HEXNAME)
#=== get all include dirs ===
INC_DIRS:=. $(SRC_DIRS) $(ARDUINO_PATH)hardware/arduino/avr/variants/$(VARIANT)
INC_OPTS:=$(addprefix -I,$(INC_DIRS))
#=== get all source files ===
CSRC:=$(shell ls $(addsuffix *.c,$(SRC_DIRS)) 2>/dev/null)
CPPSRC:=$(shell ls $(addsuffix *.cpp,$(SRC_DIRS)) 2>/dev/null)
#=== get all obj files ===
COBJ:=$(CSRC:.c=.o)
CPPOBJ:=$(CPPSRC:.cpp=.o)
OBJ:=$(COBJ) $(CPPOBJ) $(TARGETNAME).o
#=== options ===
COMMON_FLAGS = -g -Os -DF_CPU=$(F_CPU) -mmcu=$(MCU)
COMMON_FLAGS +=-DARDUINO=10800 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR
COMMON_FLAGS +=-DUSB_VID=0x2341 -DUSB_PID=0x8036
COMMON_FLAGS +=-ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects
COMMON_FLAGS +=$(INC_OPTS)
CFLAGS:=$(COMMON_FLAGS) -std=gnu99 -Wstrict-prototypes -Wall -Wextra
CXXFLAGS:=$(COMMON_FLAGS) -std=gnu++11 -fpermissive -fno-exceptions -fno-threadsafe-statics
LDFLAGS:=-g -Os -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=$(MCU)
LDLIBS:=-lm
all: $(HEXNAME) $(DISNAME)
$(SIZE) $(ELFNAME)
.PHONY: debug
debug:
@echo $(MCU) $(F_CPU) $(VARIANT) $(UPLOAD_SPEED) $(UPLOAD_PROTOCOL)
@echo $(SRC_DIRS)
@echo $(CSRC)
@echo $(CPPSRC)
@echo $(INC_OPTS)
.PHONY: clean
clean:
$(RM) $(OBJ) $(HEXNAME) $(ELFNAME) $(LIBNAME) $(DISNAME) $(MAPNAME) $(BINNAME)
.PHONY: upload
upload: $(HEXNAME)
stty -F $(AVRDUDE_PORT) 1200 raw ignbrk hup && sleep 3
$(AVRDUDE) $(AVRDUDE_FLAGS)
# implicit rules
.ino.cpp:
@cp $< $@
.elf.hex:
@$(OBJCOPY) -O ihex -R .eeprom $< $@
# explicit rules
$(ELFNAME): $(LIBNAME)($(OBJ))
$(LINK.o) $(LFLAGS) $(LIBNAME) $(LDLIBS) -o $@
$(DISNAME): $(ELFNAME)
$(OBJDUMP) -D -S $< > $@

View File

@ -0,0 +1,392 @@
/*
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();
}