From 0f1abf2d2cfe38fd22f7c657e9293362a4281cc7 Mon Sep 17 00:00:00 2001 From: kraus Date: Sun, 7 Oct 2018 17:13:35 +0200 Subject: [PATCH] TicTacToeDe --- .../TicTacToeDe/Makefile.184.leonardo | 148 +++++++ .../TicTacToeDe/TicTacToeDe.ino | 392 ++++++++++++++++++ 2 files changed, 540 insertions(+) create mode 100644 sys/arduino/u8g2_page_buffer/TicTacToeDe/Makefile.184.leonardo create mode 100644 sys/arduino/u8g2_page_buffer/TicTacToeDe/TicTacToeDe.ino diff --git a/sys/arduino/u8g2_page_buffer/TicTacToeDe/Makefile.184.leonardo b/sys/arduino/u8g2_page_buffer/TicTacToeDe/Makefile.184.leonardo new file mode 100644 index 00000000..69cbbb8f --- /dev/null +++ b/sys/arduino/u8g2_page_buffer/TicTacToeDe/Makefile.184.leonardo @@ -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 $< > $@ + + diff --git a/sys/arduino/u8g2_page_buffer/TicTacToeDe/TicTacToeDe.ino b/sys/arduino/u8g2_page_buffer/TicTacToeDe/TicTacToeDe.ino new file mode 100644 index 00000000..ee8be165 --- /dev/null +++ b/sys/arduino/u8g2_page_buffer/TicTacToeDe/TicTacToeDe.ino @@ -0,0 +1,392 @@ +/* + + TicTacToeDe.ino + +*/ + +#include +#include + + +/*==============================================*/ +/* 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(); +} +