import socket, time from PIL import Image, ImageFont, ImageDraw import sys, os import fileinput from random import randint from FlipdotSender import FlipdotSender 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 global G_ALLOWNUMERIC 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 G_ALLOWNUMERIC=True #hangman/alterebro-pixel-font.ttf size=14, -2 and 6 def __init__(self, udphost, udpport, pflipdot=None,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._flipdot=pflipdot 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/wordlists/nomenliste_de.txt" self._wordlist="/home/pi/mqtt-to-flipdot/hangman/wordlists/wordsonly.txt" #self._wordlist="/home/pi/mqtt-to-flipdot/hangman/wordlists/nerdwords.txt" #self._wordlist="./hangman/wordlists/nerdwords.txt" #<- use for local testing 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._hmdir="./hangman/stdhm/" #<- use for local testing 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, encoding="utf-8") for line in fobj: string=line.rstrip().upper() #remove whitespaces and make uppercase string=string.replace(" ","+") #if using another replacement, also change in validateWord and generateDisplayWord 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._sendPacket(self._draw()) #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 elif (s[c]=="-" or s[c]==" " or s[c]=="+"):#or - or whitespace (will be given characters) 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 cha==" " or cha=="-" or cha=="+": #show spaces and - and _ 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 _sendPacket(self,imgmap): if self._flipdot is not None: self._flipdot.sendPacket(imgmap) else: self._sock.sendto(bytes(self._array2packet(imgmap)), (self._udphost, self._udpport)) 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._sendPacket(self._draw()) 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._sendPacket(self._draw()) print("verloren, das Wort war:"+self._g_word) self._g_gamestate=0 return 2 elif self._g_gamestate==3: self._sendPacket(self._draw()) 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)