from machine import Pin, SPI, SoftI2C
import ili9342c
import random
import focaltouch
import time
from xglcd_font import XglcdFont
def tftinit():
spi = SPI(2, baudrate=40000000, sck=Pin(18), mosi=Pin(23)) # SPI init
tft = ili9342c.ILI9342C(spi, cs=Pin(5, Pin.OUT), dc=Pin(15, Pin.OUT), rst=Pin(33, Pin.OUT), width=320, height=240, rotation=270)
return tft
i2c = SoftI2C(scl=Pin(22), sda=Pin(21))
touch = focaltouch.FocalTouch(i2c)
tft = tftinit()
tft.clear(ili9342c.WHITE)
#==========================================================================================================================#
# --- Klassen --- #
#==========================================================================================================================#
class Button():
def __init__(self, x, y, w, h, tft, color):
self.x = x
self.y = y
self.w = w
self.h = h
self.tft = tft
self.color = color
def draw(self):
self.tft.fill_rect(self.x, self.y, self.w, self.h, self.color)
self.tft.rect(self.x, self.y, self.w, self.h, ili9342c.BLACK)
def set_color(self, color):
self.color = color
def get_color(self):
return self.color
def test(self, px, py):
if (self.x <= px <= self.x + self.w) and (self.y <= py <= self.y + self.h):
return True
else:
return False
#==========================================================================================================================#
# --- Hilfsfunktionen für das Spiel --- #
#==========================================================================================================================#
def check_winner(liste):
"""Prüft, ob ein Spieler gewonnen hat. Gibt 'blue', 'RED' oder None zurück."""
win_patterns = [
(0, 1, 2), (3, 4, 5), (6, 7, 8), # Zeilen
(0, 3, 6), (1, 4, 7), (2, 5, 8), # Spalten
(0, 4, 8), (2, 4, 6) # Diagonalen
]
for pattern in win_patterns:
colors = [liste[i].get_color() for i in pattern]
if (colors[0] != ili9342c.WHITE) and (colors[0] == colors[1] == colors[2]):
if colors[0] == ili9342c.BLUE:
return 'BLUE'
elif colors[0] == ili9342c.RED:
return 'RED'
elif colors[0] == ili9342c.PURPLE:
return 'PURPLE'
return None
def is_draw(liste):
"""Prüft, ob alle Felder belegt sind (kein Weiß mehr)."""
return all(btn.get_color() != ili9342c.WHITE for btn in liste)
def show_message(msg):
half = tft.height() // 2
font3 = XglcdFont(scale=2) # 16x16
font4 = XglcdFont(scale=4)
if msg == 'Player 1 WIN':
tft.text(55, half, msg, font3, ili9342c.BLACK, ili9342c.WHITE)
elif msg == 'Player 2 WIN':
tft.text(55, half, msg, font3, ili9342c.BLACK, ili9342c.WHITE)
elif msg == 'BOT WIN':
tft.text(100, half, msg, font3, ili9342c.BLACK, ili9342c.WHITE)
else:
tft.text(90, half, msg, font4, ili9342c.BLACK, ili9342c.WHITE)
#==========================================================================================================================#
# --- Modusauswahl (Tippen oben = PvP, unten = PvE) --- #
#==========================================================================================================================#
def touch_warten():
"""Wartet, bis genau eine Berührung erkannt wird und gibt (x, y) im Display-System zurück."""
while True:
if touch.touched == 1:
tx = touch.touches[0]['x']
ty = touch.touches[0]['y']
x = ty
y = (tft.height() - 1) - tx
#x = touch.touches[0]['x'] -> beide Zeilen sind im Praktikum gültig
#y = touch.touches[0]['y'] -> statt die Zeile da oben
return x, y
def select_mode():
"""Zeigt oben blau (PvP) und unten rot (PvE). Gibt 'pvp' oder 'pve' zurück."""
half = tft.height() // 2
quad = tft.height() // 4
font2 = XglcdFont(scale=2) # 16x16
tft.fill_rect(0, 0, tft.width(), half, ili9342c.BLUE) # obere Hälfte: PvP
tft.fill_rect(0, half, tft.width(), tft.height() - half, ili9342c.PURPLE) # untere Hälfte: PvE
tft.text(15, quad, "Player vs. Player", font2, ili9342c.MAGENTA, ili9342c.BLUE)
tft.text(35, tft.height()-quad, "Player vs. Bot", font2, ili9342c.BLUE, ili9342c.PURPLE)
while True:
x, y = touch_warten()
if y < half:
mode = 'pvp'
else:
mode = 'pve'
while touch.touched == 1:
time.sleep_ms(10)
return mode
def bot_zug(liste, current_color):
"""Bot wählt ein zufälliges freies Feld und färbt es."""
frei = [btn for btn in liste if btn.get_color() == ili9342c.WHITE]
if frei:
btn = random.choice(frei)
btn.set_color(current_color)
btn.draw()
#==========================================================================================================================#
# --- Spielfeld-Erstellung --- #
#==========================================================================================================================#
def main():
mode = select_mode() # Spielmodus auswählen
tft.clear(ili9342c.WHITE)
liste = []
m = 3
n = 3
gap = 10
w = ((tft.width() - (m + 1) * gap) // m)
h = ((tft.height() - (n + 1) * gap) // n)
for i in range(m):
for j in range(n):
x = j * (w + gap) + gap
y = i * (h + gap) + gap
btn = Button(x, y, w, h, tft, ili9342c.WHITE)
liste.append(btn)
btn.draw()
current_color = ili9342c.BLUE
if mode == 'pve':
gegner_farbe = ili9342c.PURPLE # Bot
else:
gegner_farbe = ili9342c.RED # Spieler 2
while True:
num_touches = touch.touched
if num_touches == 1:
tx = touch.touches[0]['x']
ty = touch.touches[0]['y']
# Touch-Rohkoordinaten an Display-Rotation (270°) anpassen:
x = ty
y = (tft.height() - 1) - tx
#x = touch.touches[0]['x'] -> beide Zeilen sind im Praktikum gültig
#y = touch.touches[0]['y'] -> statt die Zeile da oben
for btn in liste:
if btn.test(x, y):
if btn.get_color() == ili9342c.WHITE: # Überprüfe den Zustand des Buttons
btn.set_color(current_color)
if current_color == ili9342c.BLUE:
current_color = gegner_farbe
else:
current_color = ili9342c.BLUE
btn.draw()
# Im PvE-Modus zieht nach dem Spieler der Bot
if mode == 'pve' and check_winner(liste) is None and not is_draw(liste):
bot_zug(liste, current_color)
if current_color == ili9342c.BLUE:
current_color = gegner_farbe
else:
current_color = ili9342c.BLUE
break
winner = check_winner(liste)
if winner == 'BLUE':
print("Player 1 win")
show_message('Player 1 WIN')
return
elif winner == 'RED':
print("Player 2 win")
show_message('Player 2 WIN')
return
elif winner == 'PURPLE':
print("Bot win")
show_message('BOT WIN')
return
elif is_draw(liste):
print("DRAW")
show_message('DRAW')
return
while touch.touched == 1:
time.sleep_ms(10)
if __name__ == "__main__":
while True:
main()
tft.clear(ili9342c.WHITE)