diff --git a/hangman.py b/hangman.py new file mode 100644 index 0000000..341045b --- /dev/null +++ b/hangman.py @@ -0,0 +1,313 @@ +import socket, time +from PIL import Image, ImageFont, ImageDraw +import sys, os +import fileinput +from random import randint + + +class Hangman(object): + ''' + classdocs + ''' + + global C_BLACK + global C_WHITE + global C_BG + global C_TEXT + global C_HM + global FPS + global FONT_SIZE_word + + C_BLACK = 0 + C_WHITE = 255 + C_BG=C_WHITE + C_TEXT=C_BLACK + C_HM=C_TEXT + FPS=2 + FONT_SIZE_word=9 #was 9 + + #hangman/alterebro-pixel-font.ttf size=14, -2 and 6 + + + + def __init__(self, udphost, udpport, img_size=(80,16)): + ''' + Constructor + ''' + + self._udphost = udphost + if not type(udpport) is int or udpport > 65536: + raise TypeError('port has to be int and > 65536 !!') + self._udpport = udpport + self._img_size = img_size + self._fo_word= (15, -1) #(15, -1) + self._fo_word2= (15, 7) #(15,7) + #self._wordlist="/home/pi/mqtt-to-flipdot/hangman/nomenliste_de.txt" + self._wordlist="/home/pi/mqtt-to-flipdot/hangman/crodict_nomen.txt" + self._gamestate=0# 0=start 1=ingame 2=lose 3=win + self._g_word="test" #word + self._g_displword="" #display word + self._g_chars="" #used characters + + self._hmdir="/home/pi/mqtt-to-flipdot/hangman/stdhm/" + + self._hmimg=[] + self._maxfails=len( os.listdir(self._hmdir))-1 -1 #maxfails defined by files in directory, -1 -1 because win image + print("Maxfails="+str(self._maxfails)) + + for i in range(self._maxfails+1): + self._hmimg.append(Image.open(open(self._hmdir+"f"+str(i)+".png", 'rb')) ) #load hangmans + + self._winimg=Image.open(open(self._hmdir+"win.png", 'rb')) + + self._minwlen=4 + self._maxwlen=26 + + self._words=[] + fobj = open(self._wordlist) + for line in fobj: + string=line.rstrip() + if (self._validateWord(string)==1): + if (len(string)>=self._minwlen and len(string)<=self._maxwlen): + self._words.append(string) + fobj.close() + print("loaded "+str(len(self._words))+" words") + + self._sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + + + def setup(self): + print("Hangman setup") + rand=randint(0,len(self._words)-1) + self._g_word=self._words[rand] + self._g_chars="" + self._generateDisplword() + self._g_gamestate=1 + self._sock.sendto(bytes(self._array2packet(self._draw())), (self._udphost, self._udpport)) + + + def _list2byte(self, l): + byte = 0 + i = 0 + for i in range(8): + byte += 2**(7-i) if l[i] else 0 + return byte + + def _array2packet(self, a): + return [self._list2byte(a[i*8:i*8+8]) for i in range(int(len(a)/8))] + + + def _str2array(self,s): + image = Image.new("RGBA", self._img_size, C_BLACK) + draw = ImageDraw.Draw(image) + draw.fontmode = "1" # No AA + #font = ImageFont.load_default() + font = ImageFont.truetype("/usr/share/fonts/Retro Computer_DEMO.ttf", FONT_SIZE) + #/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf + + draw.text(FONT_OFFSET, s, font=font, fill=C_WHITE) + + + def _validateWord(self,s): #returns 1 if chars are only abc...xyz or ABC...XYZ, else 0 + for c in range(0,len(s)): + oc=ord(s[c]) + #print s+":ord="+str(oc) + if (oc>=65 and oc<=90) : #A-Z + a=s#nonesense + elif (oc>=97 and oc<=122):#a-z + a=s + elif (oc>=48 and oc<=57 and G_ALLOWNUMERIC==1):#0-9 + a=s + else: + return 0 + return 1 + + def _generateDisplword(self): + + self._g_displword="" + + for i in range(0,len(self._g_word)): + cha=self._g_word[i] #current character + show=0 + for c in range(0,len(self._g_chars)): + if cha.lower()==self._g_chars[c]: #if current char is opened + show=1 + + if show==1: #if character cha is opened + self._g_displword+=cha #show + else: + self._g_displword+="-" #do not show + + def _countFails(self): + fails=0 + for c in range(0,len(self._g_chars)): + used=0 + for i in range(0,len(self._g_word)): + if self._g_chars[c]==self._g_word[i].lower(): + used=1 + if used==0: #if current char was never used in g_word + fails+=1 + return fails + + def _computeInput(self,strinput): + if ((len(strinput)==1) and (self._validateWord(strinput[:len(strinput)-1])==1) ): #only one character and only alphabet + newchar=strinput[0].lower() + used=0 + for c in range(0,len(self._g_chars)): + if self._g_chars[c]==newchar: + used=1 + + if used==0: + self._g_chars+=newchar #add new character + else: #if character already entered + print("Character already entered!") + else: + print("Wrong input!!11!") + + + def _checkWord(self): + #print "fails="+str(countFails())+" max="+str(maxfails) + if self._countFails()>=self._maxfails: + self._g_gamestate=2 + if self._g_displword==self._g_word: + self._g_gamestate=3 + + + def _draw(self): + image = Image.new("RGBA", self._img_size, C_BG) + draw = ImageDraw.Draw(image) + draw.fontmode = "1" # No AA + + if self._g_gamestate==1: + self._drawGameScreen(draw) + elif self._g_gamestate==2: + self._drawLoseScreen(draw) + elif self._g_gamestate==3: + self._drawWinScreen(draw) + + imgmap = [] + + for pixel in image.getdata(): + r, g, b, a = pixel + if r == 255: + imgmap.append(1) + else: + imgmap.append(0) + return imgmap + + def _drawHangman(self,draw): + dimg=self._hmimg[self._countFails()] + #self._draw.ImageDraw(hmimg[countFails()]) + self._drawImage(dimg,0,0,draw) + + def _drawWinImage(self,draw): + dimg=self._winimg + #self._draw.ImageDraw(hmimg[countFails()]) + self._drawImage(dimg,0,0,draw) + + + def _drawImage(self,img,xv,yv,draw): + w=img.size[0] + h=img.size[1] + i=0 + for pixel in img.getdata(): + #r, g, b, a = pixel + if pixel[0]==255: + draw.point( (xv+i%w,yv+i/w), fill=C_HM) + i+=1 + + + + def _drawGameScreen(self,draw): + + #font = ImageFont.truetype("/usr/share/fonts/truetype/fonts-japanese-gothic.ttf", FONT_SIZE_word) + #font = ImageFont.truetype("hangman/alterebro-pixel-font.ttf", FONT_SIZE_word) + font = ImageFont.truetype("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", FONT_SIZE_word) + + + if (self._g_gamestate!=3): + self._drawHangman(draw) + else: + self._drawWinImage(draw) + + x=len(self._g_displword) + l=draw.textsize(self._g_displword[:x]+"E", font=font)[0] #concat one char because textsize is one char short (somehow) + while (l>(80-14-4)) and (x>0): #80-14-18 + + x-=1 + l=draw.textsize(self._g_displword[:x]+"E", font=font)[0] + + + s1=self._g_displword[:x] + s2=self._g_displword[x:] + + #for i in range(0,len(s1)): + # draw.text((fo_word[0]+i*5, fo_word[1]), s1[i], font=font, fill=C_TEXT) + + #for i in range(0,len(s2)): + # draw.text((fo_word2[0]+i*5, fo_word2[1]), s2[i], font=font, fill=C_TEXT) + + draw.text(self._fo_word, s1.upper(), font=font, fill=C_TEXT) + draw.text(self._fo_word2, s2.upper(), font=font, fill=C_TEXT) + + def _drawLoseScreen(self,draw): + self._drawGameScreen(draw) + + + def _drawWinScreen(self,draw): + self._drawGameScreen(draw) + + + def step(self,strinput): #returns 0 if game ended + + if self._g_gamestate==0: #game ended + return 0 + + elif self._g_gamestate==1: + #strinput = sys.stdin.readline() + self._computeInput(strinput) + + + self._generateDisplword() + + + #draw() #test + self._sock.sendto(bytes(self._array2packet(self._draw())), (self._udphost, self._udpport)) + print("Display:"+self._g_displword) + print("Used:"+self._g_chars) + print("fails:"+str(self._countFails())) + + self._checkWord() + + if self._g_gamestate==2: + #c_t=C_TEXT #backup + #C_TEXT=C_BG #invert text + #C_BG=c_t #invert text + self._g_displword=self._g_word + self._sock.sendto(bytes(self._array2packet(self._draw())), (self._udphost, self._udpport)) + print("verloren, das Wort war:"+self._g_word) + self._g_gamestate=0 + return 2 + + + elif self._g_gamestate==3: + self._sock.sendto(bytes(self._array2packet(self._draw())), (self._udphost, self._udpport)) + print("gewonnen") + self._g_gamestate=0 + return 3 + + + return 1 + + + + +if __name__ == '__main__': + hangman= Hangman("2001:67c:275c:a9::c", 2323) + hangman.setup() + running=1 + while running==1: + running=hangman.step(sys.stdin.readline()) + time.sleep(1.0/FPS) + + diff --git a/mqtt-to-flipdot.py b/mqtt-to-flipdot.py index aa0604a..8055b4d 100644 --- a/mqtt-to-flipdot.py +++ b/mqtt-to-flipdot.py @@ -3,39 +3,78 @@ import time import paho.mqtt.client as mqtt from FlipdotSender import FlipdotSender import time +from hangman import Hangman + +global mode +mode="standby" def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) - client.subscribe("raum2/flipdot/text") - client.subscribe("raum2/flipdot/scroll") - client.subscribe("raum2/flipdot/image") + client.subscribe("raum2/flipdot/#") + #client.subscribe("raum2/flipdot/text") + #client.subscribe("raum2/flipdot/scroll") + #client.subscribe("raum2/flipdot/image") def on_message(client, userdata, msg): print(msg.topic + " " + str(msg.payload.decode("utf-8"))) + global mode - if msg.topic == "raum2/flipdot/scroll": - payload = msg.payload.decode("utf-8") + if mode=="standby": + + if msg.topic == "raum2/flipdot/scroll/set": + payload = msg.payload.decode("utf-8") - if (payload[0]).isdigit(): - speed = int(payload[0]) - text = payload[1:] - else: - speed = 3 - text = payload - - flipdot.send_marquee(text, speed) - if msg.topic == "raum2/flipdot/text": - payload = msg.payload.decode("utf-8") - flipdot.send_text(payload) - - if msg.topic == "raum2/flipdot/image": - payload = msg.payload.decode("utf-8") - print(payload) - flipdot.send_bytes(payload) + if (payload[0]).isdigit(): + speed = int(payload[0]) + text = payload[1:] + else: + speed = 3 + text = payload + + flipdot.send_marquee(text, speed) + if msg.topic == "raum2/flipdot/text/set": + payload = msg.payload.decode("utf-8") + flipdot.send_text(payload) + + if msg.topic == "raum2/flipdot/image/set": + payload = msg.payload.decode("utf-8") + print(payload) + flipdot.send_bytes(payload) + + if msg.topic == "raum2/flipdot/hangman/set": + payload = msg.payload.decode("utf-8") + + if payload=="#start": + hangman.setup() + client.publish("raum2/flipdot/hangman","started") + mode="hangman" + + elif (mode=="hangman") and (len(payload)>0): #try entered character + trychar=payload[-1] + gamestatus=hangman.step(trychar) + if gamestatus!=1: #game has ended + mode="standby" + if gamestatus==2: #gameover + client.publish("raum2/flipdot/hangman","gameover") + elif gamestatus==3: #won + client.publish("raum2/flipdot/hangman","won") + elif gamestatus==0: #ended in another way + client.publish("raum2/flipdot/hangman","ended") + + + if payload=="#stop": + mode="standby" + client.publish("raum2/flipdot/hangman","ended") + + + flipdot = FlipdotSender("2001:67c:275c:a9::c", 2323) +hangman= Hangman("2001:67c:275c:a9::c", 2323) + + client = mqtt.Client() client.on_connect = on_connect