mqtt-to-flipdot/hangman.py

336 lines
10 KiB
Python
Executable File

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/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)