mqtt-to-flipdot/hangman.py

337 lines
10 KiB
Python

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="/root/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="/root/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/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)
if (len(s1)>0):
draw.text(self._fo_word, s1.upper(), font=font, fill=C_TEXT)
if (len(s2)>0):
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)