still was impressed by the Z80 assembly tutorial on Youtube by Darryl Sloan. He's demonstrating "Connect 4", using a single UDG in different colours:
I wondered, if I could do that in Pygame. It seems, I could. Here's my result.
Keys are: "q" (or "o") - left, "w" (or "p") right, "space" - drop, "u" - undo move, "r" - restart game:
Code: Select all
#!/usr/bin/python
# coding: utf-8
import pygame
from pygame.locals import *
import os
import zlib
import base64
""" winwithfour.py, 1.0:
A little game in Python/Pygame (inspired by a very good Z80 Assembly
tutorial on Youtube).
Copyright 2019, Forum-name: Major Percival FFoulkes, GNU GPL v.2,
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
SCALEFACTOR = 3
FPS = 50
GRIDWIDTH = 7
GRIDHEIGHT = 6
MATCHES = 4
class ZXEnvironment:
def __init__(self):
self.zx_paperwidth = 256
self.zx_paperheight = 176
self.zx_char_width = self.zx_paperwidth / 8 # 32
self.zx_char_height = self.zx_paperheight / 8 # 22
self.pc_paperwidth = self.zx_paperwidth * SCALEFACTOR
self.pc_paperheight = self.zx_paperheight * SCALEFACTOR
self.zx_border = 16 # 2
self.pc_border = self.zx_border * SCALEFACTOR
self.screenwidth = (self.zx_paperwidth + 2 * self.zx_border) * SCALEFACTOR
self.screenheight = (self.zx_paperheight + 2 * self.zx_border) * SCALEFACTOR
self.data = Data()
self.colours = self.data.colours
def initBorderAndPaper(self, screen):
self.screen = screen
self.paper = pygame.Surface((self.pc_paperwidth, self.pc_paperheight))
self.paperrect = self.paper.get_rect(topleft = (self.pc_border, self.pc_border))
self.borderbars = (pygame.Surface((self.pc_border, self.screenheight)),
pygame.Surface((self.pc_paperwidth, self.pc_border)))
self.paperborder = pygame.Surface((self.pc_paperwidth, self.pc_border))
self.paperborderrect = self.paperborder.get_rect(topleft = (self.pc_border, self.pc_border + self.pc_paperheight))
self.borderpositions = {0 : ((0, 0), (self.pc_border + self.pc_paperwidth, 0)),
1 : ((self.pc_border, 0),)}
def cls(self, colourname):
self.setPaperColour(colourname)
self.blitPaperToScreen()
def border(self, colourname):
self.setBorderColour(colourname)
self.blitBorderToScreen()
def setBorderColour(self, colourname):
for b in self.borderbars:
b.fill(self.colours[colourname])
self.paperborder.fill(self.colours[colourname])
self.bordercolourname = colourname
def setPaperColour(self, colourname):
self.paper.fill(self.colours[colourname])
self.papercolourname = colourname
def blitPaperToScreen(self):
""" If you drawed on the paper, you'd have to call "fill()"
to get it clean again. Instead, you blit the (clean) paper
and keep drawing on top of it onto the screen. """
self.screen.blit(self.paper, self.paperrect)
def blitPaperborderToScreen(self):
self.screen.blit(self.paperborder, self.paperborderrect)
def blitBorderToScreen(self):
for i in range(len(self.borderbars)):
for u in self.borderpositions[i]:
self.screen.blit(self.borderbars[i], u)
self.screen.blit(self.paperborder, self.paperborderrect)
def zxToPCxy(self, zx_x, zx_y):
x = self.pc_border + zx_x * SCALEFACTOR
y = self.pc_border + zx_y * SCALEFACTOR
return (x, y)
class StringSprite(pygame.sprite.Sprite):
def __init__(self, zx_x, zx_y, zxenv, image):
pygame.sprite.Sprite.__init__(self)
self.zxenv = zxenv
self.image = image
self.rect = self.image.get_rect()
self.rect.topleft = self.zxenv.zxToPCxy(zx_x, zx_y)
def draw(self, surface):
surface.blit(self.image, self.rect)
class UDGSprite(pygame.sprite.Sprite):
def __init__(self, name, zx_x, zx_y, zxenv, colourname):
pygame.sprite.Sprite.__init__(self)
self.name = name
self.zxenv = zxenv
self.zx_position = (zx_x, zx_y)
self.pc_position = self.zxenv.zxToPCxy(zx_x, zx_y)
self.colourname = colourname
self.colour = self.zxenv.colours[colourname]
self.transparent = (0, 0, 0, 0)
self.data = Data()
self.images = []
self.zx_imagesizes = []
self.pc_imagesizes = []
self.currentimage = 0
self.image = None
self.rect = None
self.createImages()
def setImage(self, imagenumber):
self.currentimage = imagenumber
self.image = self.images[imagenumber]
self.rect = pygame.Rect(self.pc_position,
self.pc_imagesizes[imagenumber])
def moveTo(self, zx_x, zx_y):
self.zx_position = (zx_x, zx_y)
self.pc_position = self.zxenv.zxToPCxy(zx_x, zx_y)
self.rect = pygame.Rect(self.pc_position,
self.pc_imagesizes[self.currentimage])
def moveBy(self, move_zx_x, move_zx_y):
self.zx_position = (self.zx_position[0] + move_zx_x,
self.zx_position[1] + move_zx_y)
self.pc_position = (self.pc_position[0] + move_zx_x * SCALEFACTOR,
self.pc_position[1] + move_zx_y * SCALEFACTOR)
self.rect = pygame.Rect(self.pc_position,
self.pc_imagesizes[self.currentimage])
def draw(self, surface):
surface.blit(self.image, self.pc_position)
def createImages(self):
# Format expected by imagedata: {'UDG1_0': (8, (1, 2, 3, 4)),
# 'UDG1_1': (8, (5, 6, 7, 8))}
imagedata = self.data.getImagedata(self.name)
a = imagedata.keys()
a.sort()
for i in a:
b = []
numstr = "{0:0" + str(imagedata[i][0]) + "b}"
for u in imagedata[i][1]:
binstring = numstr.format(u)
b.append(binstring)
self.addImage(b, self.colourname)
def addImage(self, binstringlist, colourname):
zx_spritesize = (len(binstringlist[0]), len(binstringlist))
pc_spritesize = (zx_spritesize[0] * SCALEFACTOR,
zx_spritesize[1] * SCALEFACTOR)
surface = pygame.Surface(pc_spritesize)
surface = surface.convert_alpha(surface)
surface = self.plotImage(surface, binstringlist, zx_spritesize[0], colourname)
self.images.append(surface)
self.zx_imagesizes.append(zx_spritesize)
self.pc_imagesizes.append(pc_spritesize)
def plotImage(self, surface, data_, spritewidth, colourname):
pxarray = pygame.PixelArray(surface)
t_x = 0
t_y = 0
for line in data_:
for bit in line:
if bit == "1":
plotcolour = self.zxenv.colours[colourname]
else:
plotcolour = self.transparent
# Plot one ZX pixel:
for pixelline in range(SCALEFACTOR):
for pixelrow in range(SCALEFACTOR):
pxarray[t_x * SCALEFACTOR + pixelline][t_y * SCALEFACTOR + pixelrow] = plotcolour
t_x += 1
# Next line (like a typewriter):
t_y += 1
t_x -= spritewidth
del pxarray
return surface
class GridSprite(UDGSprite):
def __init__(self, name, zx_x, zx_y, zxenv, colourname):
self.zx_x = zx_x
self.zx_y = zx_y
UDGSprite.__init__(self, name, zx_x, zx_y, zxenv, colourname)
def createImages(self):
imagedata = self.data.getImagedata(self.name)
b = []
for i in range(GRIDHEIGHT):
for u in imagedata:
bstr = "{0:08b}".format(u)
bstr *= GRIDWIDTH
b.append(bstr)
self.addImage(b, "blue")
class Tile(UDGSprite):
def __init__(self, name, zx_x, zx_y, zxenv, colourname, grid_x, grid_y, gridzero_y):
UDGSprite.__init__(self, name, zx_x, zx_y, zxenv, colourname)
self.colourname = colourname
self.grid_x = grid_x
self.grid_y = grid_y
self.gridzero_y = gridzero_y
self.active = False
self.moveable = False
self.falling = 0
def setMoveable(self, zx_to_x, zx_to_y):
self.active = True
self.moveable = True
self.moveTo(zx_to_x, zx_to_y)
self.grid_x = 3
self.grid_y = -1
def setImmoveable(self):
self.moveable = False
def setActive(self):
self.active = True
def setInactive(self):
self.active = False
def createImages(self):
imagedata = self.data.getImagedata(self.name)
b = []
for i in imagedata:
bstr = "{0:08b}".format(i)
b.append(bstr)
self.addImage(b, self.colourname)
def moveSideways(self, direction):
if not self.moveable:
return
if direction == "left":
if self.grid_x > 0:
self.grid_x -= 1
self.moveBy(-8, 0)
if direction == "right":
if self.grid_x < GRIDWIDTH - 1:
self.grid_x += 1
self.moveBy(8, 0)
def setTimer(self):
self.timer = pygame.time.get_ticks()
def update(self):
if self.moveable and self.falling == 1:
zx_ydest = self.gridzero_y + self.grid_y * 8
if self.zx_position[1] < zx_ydest:
self.moveBy(0, 1)
else:
self.falling = 2
self.setImmoveable()
def draw(self, surface):
if self.active:
surface.blit(self.image, self.pc_position)
class WinTile(UDGSprite):
def __init__(self, name, zx_x, zx_y, zxenv, colourname, grid_x, grid_y):
self.wincolour = colourname
UDGSprite.__init__(self, name, zx_x, zx_y, zxenv, colourname)
self.grid_x = grid_x
self.grid_y = grid_y
self.active = False
self.delaytime = 600
self.timer = pygame.time.get_ticks()
def setActive(self):
self.active = True
self.timer = pygame.time.get_ticks()
def setInactive(self):
self.active = False
def setWinColour(self, colourname):
self.wincolour = colourname
self.images = []
self.zx_imagesizes = []
self.pc_imagesizes = []
self.createImages()
def createImages(self):
imagedata = self.data.getImagedata(self.name)
b = []
for i in imagedata:
bstr = "{0:08b}".format(i)
b.append(bstr)
self.addImage(b, "magenta")
self.addImage(b, self.wincolour)
def update(self, currenttime):
if not self.active:
return
if currenttime - self.timer > self.delaytime:
self.setImage(1 - self.currentimage)
self.timer += self.delaytime
def draw(self, surface):
if self.active:
surface.blit(self.image, self.pc_position)
class Main:
def __init__(self):
self.zxenv = ZXEnvironment()
os.environ['SDL_VIDEO_WINDOW_POS'] = "218, 5"
pygame.init()
self.screen = pygame.display.set_mode((self.zxenv.screenwidth, self.zxenv.screenheight))
self.clock = pygame.time.Clock()
pygame.display.set_caption('Win with Four')
self.zxenv.initBorderAndPaper(self.screen)
self.data = Data()
self.combinations = self.initCombinations()
self.initGame()
# Main loop:
while True:
self.clock.tick(FPS)
self.timer = pygame.time.get_ticks()
r = self.processEvents()
if r == "quit":
pygame.quit()
return
if r == "replay":
self.initGame()
continue
self.zxenv.blitPaperToScreen()
self.drawMessages("headline")
for s in self.activetiles:
s.update()
for s in self.redtiles:
s.draw(self.zxenv.screen)
for s in self.yellowtiles:
s.draw(self.zxenv.screen)
self.gridSprite.draw(self.zxenv.screen)
if self.activetile.falling == 2:
if self.won:
for s in self.wintiles:
s.update(self.timer)
s.draw(self.zxenv.screen)
if self.won == "red":
self.drawMessages("redwin", "replay")
if self.won == "yellow":
self.drawMessages("yellowwin", "replay")
elif self.outofmoves:
self.drawMessages("tie", "replay")
else:
self.nextTile()
pygame.display.flip()
def initGame(self):
self.moves = 0
self.outofmoves = False
self.won = None
self.initSprites()
self.initGrid()
self.zxenv.cls("white")
self.zxenv.border("red")
for s in self.wintiles:
s.setInactive()
def dropTile(self):
# Selected column is already full:
if self.grid[self.activetile.grid_x][0]:
return
self.activetile.grid_y = 0
while self.activetile.grid_y < GRIDHEIGHT and not self.grid[self.activetile.grid_x][self.activetile.grid_y]:
self.activetile.grid_y += 1
self.activetile.grid_y -= 1
self.activetile.falling = 1
self.activetiles.append(self.activetile)
if self.activetile.colourname == "red":
self.grid[self.activetile.grid_x][self.activetile.grid_y] = 1
if self.activetile.colourname == "yellow":
self.grid[self.activetile.grid_x][self.activetile.grid_y] = 2
self.moves += 1
if self.moves == GRIDWIDTH * GRIDHEIGHT:
self.outofmoves = True
return
# Clever: Don't check every frame, but only, when a tile is dropped:
self.checkGameWon()
if self.won:
return
def undoMove(self):
if self.moves > 0:
self.moves -= 1
self.activetile.setImmoveable()
self.activetile.setInactive()
if self.activetile.colourname == "red":
self.redindex -= 1
if self.activetile.colourname == "yellow":
self.yellowindex -= 1
undotile = self.activetiles[len(self.activetiles) - 1]
undotile.setInactive()
self.grid[undotile.grid_x][undotile.grid_y] = 0
self.activetiles.pop()
self.nextTile()
def nextTile(self):
if self.moves % 2:
self.yellowindex += 1
self.activetile = self.yellowtiles[self.yellowindex]
self.activetile.setMoveable(self.gridSprite.zx_x + 3 * 8, self.gridSprite.zx_y - 8)
else:
self.redindex += 1
self.activetile = self.redtiles[self.redindex]
self.activetile.setMoveable(self.gridSprite.zx_x + 3 * 8, self.gridSprite.zx_y - 8)
def checkGameWon(self):
if self.won or self.outofmoves:
return
for i in self.combinations:
red = 0
yellow = 0
for u in i:
value_at_pos = self.grid[int(u[0])][int(u[1])]
if value_at_pos == 1:
red += 1
if value_at_pos == 2:
yellow += 1
if red == MATCHES:
self.won = "red"
wincoords = i
break
if yellow == MATCHES:
self.won = "yellow"
wincoords = i
break
if self.won:
# At this point, we already know, that someone has won the game,
# but the main loop still has to wait for the last tile to fall:
self.setWinTilesCoords(wincoords)
def setWinTilesCoords(self, coords):
for i in range(len(coords)):
self.wintiles[i].setWinColour(self.won)
self.wintiles[i].moveTo(self.gridSprite.zx_x + 8 * int(coords[i][0]),
self.gridSprite.zx_y + 8 * int(coords[i][1]))
self.wintiles[i].setActive()
def drawMessages(self, *msgnames):
for i in msgnames:
self.messages[i].draw(self.zxenv.screen)
def initCombinations(self):
return self.data.getAllMatchesInAGridCombinations(GRIDWIDTH, GRIDHEIGHT, MATCHES)
def initGrid(self):
self.grid = []
for column in range(GRIDWIDTH):
a = []
for row in range(GRIDHEIGHT):
a.append(0)
self.grid.append(a)
def initSprites(self):
self.gridSprite = GridSprite("Grid", 96, 48, self.zxenv, "blue")
self.gridSprite.setImage(0)
msgpos = {"headline" : (-24, -24),
"redwin" : (-16, 72),
"yellowwin" : (-24, 72),
"tie" : (-72, 72),
"replay" : (-64, 88)}
self.messages = {}
stringimages = self.data.getStringImages()
for i in msgpos.keys():
self.messages[i] = StringSprite(self.gridSprite.zx_x + msgpos[i][0], self.gridSprite.zx_y + msgpos[i][1], self.zxenv, stringimages[i])
n = GRIDWIDTH * GRIDHEIGHT // 2
# A few more tiles than needed (just in case :) ):
n += 5
self.redtiles = []
self.yellowtiles = []
for i in range(n):
tr = Tile("Tile", 0, 0, self.zxenv, "red", -1, -1, self.gridSprite.zx_y)
tr.setImage(0)
self.redtiles.append(tr)
ty = Tile("Tile", 0, 0, self.zxenv, "yellow", -1, -1, self.gridSprite.zx_y)
ty.setImage(0)
self.yellowtiles.append(ty)
self.wintiles = []
for i in range(MATCHES):
t = WinTile("Tile", 0, 0, self.zxenv, "magenta", -1, -1)
t.setImage(0)
self.wintiles.append(t)
self.redindex = 0
self.yellowindex = 0
self.activetile = self.redtiles[self.redindex]
self.activetile.setMoveable(self.gridSprite.zx_x + 3 * 8, self.gridSprite.zx_y - 8)
self.activetiles = [self.activetile]
def processEvents(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
return "quit"
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_e or event.key == pygame.K_a:
return "quit"
if event.key == pygame.K_r:
return "replay"
if not self.won and not self.outofmoves and self.activetile.falling != 1:
if event.key == pygame.K_q or event.key == pygame.K_o:
self.activetile.moveSideways("left")
if event.key == pygame.K_w or event.key == pygame.K_p:
self.activetile.moveSideways("right")
if event.key == pygame.K_u:
self.undoMove()
if event.key == pygame.K_SPACE:
self.dropTile()
return 0
class Data:
def __init__(self):
self.colours = {"black" : (0, 0, 0),
"blue" : (0, 0, 197),
"red" : (189, 0, 0),
"magenta" : (189, 0, 197),
"green" : (0, 190, 0),
"cyan" : (0, 190, 197),
"yellow" : (189, 190, 0),
"white" : (189, 190, 197)}
self.gridSpriteData = (255, 231, 195, 129, 129, 195, 231, 255)
self.tiledata = (0, 24, 60, 126, 126, 60, 24, 0)
def getImagedata(self, name):
if name == "Grid":
return self.gridSpriteData
if name == "Tile":
return self.tiledata
def getStringImages(self):
msgwidths = {"headline" : 312,
"redwin" : 288,
"yellowwin": 360,
"tie" : 600,
"replay" : 576}
msg = {"headline" : """eJztk8EOwzAIQ/v//7Td9l877ZQpSrAxNHXlUxWBeYbX+/OyLMuyLMuyrMfo+n21jx8oFp9YnW7pXKGv3LaeT+3jB8p3+teP7xTPy3daRZ5ep1s6vlNiXgI+3dJZaVprLMan26rT/Qj4xDzHjHULdzJFyWrl5ZUHqkmUdM7d+MQ8x4x1C3cyRclq5eWVB6pJlHTO3fjEPMeM5ZkHp1BmutVr5U8eHxaNybYo8W75Ye2G8g0YU14vMG46H1Bjr5U/eXxYNEYbdGN0P6zdUL4BY8rrBcZN5wNq7LXyJ48Pi8Zog26M7oe1G8o3YEyCXjFjdD6gxl4rfwTBHc85r47vFDfWf398pxrOeXV8p7ix/vvjO9Vwzqtzxp1ew6c01n9/QCz0KU7lnFdH+YY14GTrwIU8dX9ALPQpTuWcV0f5hjXgZOvAhTx1f0As9ClO5ZxXR/lGOWDMz/gpOdM1NgUPJMZnq/KNONN7sTjT6+SB2moBztVtfyZNa3NfqXwjzvReLM70OnmgtlqAc3Xbn0nT2txXKt+IM70XizO9jgCmZVmWZVmWZd1LX5CqQQk=""",
"redwin" : """eJztlEsSwjAMQ7n/ncqOe8EaZtLE+tQNYrTKRI39LHM8X0cURVEURVEU/eix8ru82q+aN3sr6qxaErJffd6KOiv7dfe3os4C94t12bCet94vFp8mf4NLkTD0NbCDfMAx0WHq5u4Mkq54kI+BM4tPLWO1vgZ2kA84JjpM3dydQdIVD/IxcGbxqWWs1tfADvIBxwRednIGQdX4GMqgM3TyWTrR9a5jaHANLtP7Ogu1KWPOMnTZMPBZOtH1rmNocA0u0/s6C7UpY84ydNkw8Fk60fWuYwi6wCCBdgOfmuj10EHV7Do+Myc6zrr8gC5w7qDdwKcmej10UDW7js/MiY6zLj+gC5w7aDfwqYleDx1Uza7jM3Oi46zLj86lq/nat7rxcTLU8dl1v3Sz6JaNXflkv/rc0fG5tuZ/5pP96nNHx4dV/OC39Bb4HQMfZ19NsMxAqNUD9kWfl9PlDADrO6Do8wL7aoJlBkKtHrAv+rycLmcAWN8BRZ8X2FcTLDMQavWAfdHnBbqiKIqiKIqi6KM3YxbLbw==""",
"yellowwin" : """eJztlDtuxFAMA3P/O2263CvFIpUBA6ZGfFyEBkt9noaEX98/r6qqqqqqqqqqqiR9/X2GriNPDXl8rEqjeutREvrf+Ocqjeqt/jcCHx+r0qje2vsVaH+k6+e8C58zvAvnfJYGzgefY+CjBWCYH5zP0KYQPtRd+BzKd8OlTqoUH3yOgY8WgGF+cD5Dm0L4UHfhcyjfDZc6qVJ88DkGPloAhvnB+eDt2l34C6nY7G3XaobAKRp4DvcYOkX5lVaDkx/GOPYuw3atZgiconHz4bsMLu+9WfMrrQYnP4xx7F2G7VrNEDhF4+bDdxlc3nuz5ldazR754XY8hyF34TVaDinhOaQCgOeH4qP5lVZDdeHbcd9D7sJrtBxSwnNIBQDPD8VH8yuthurCt+O+h9yF12g5pITnkAoAnh+Kj+ZXWg3Vlbb9E+/SarQcOqmezfPeHG2X5ldajZPYXpdz8t5dWo2WQyfVtDyf5aP5lVbjJLbX5Zy8d5dWo+XQSTUtz2f5aH6l1TiJae03HzXZOYc659p1xG48h0Pfh+1OUEPftbtwv4Zd+Jy9AJydQ51z7aKMw12m+DzaRXHeAzX0XbsL92vYhc/ZC8DZOdQ51y7KONxlis+jXRTnPVBD37W7cL+GXVVVVVVVVVVVVSH6BcRUuEE=""",
"tie" : """eJztlVGOgzAQQ3v/O3X/eq89ACodZhzbASN/RQmxnwfx/vu8oyiKoiiKoiiKoiiKoiiKnqTX7Dl5oTxaFHHkNvNaP240nqOQb9PIfzCKhnKb+fwHn6mQb9PIfzCKhnKb+fwHn6mQX0Gj9x54F5f+wky8Q2Pw46ji/Dkza7p0lwlnbXFDzwQ+KGNyaN+sMgOijq/LpaUKL9dkDk/8SObneGpYnD9nZk2X7jLhrC1u6JnAB2VMDu2bVWZA1PF1ubRU4eWazOGJH8n8HE8Ni/PnzKzp0l0mnLXFDT0T+KCMyaF9s8oMiDq+LpcbVRM+62gwyR/3VFaewxme69dQb+ZnXXG92+F8mJG1nHvkCeZ7nVZWmAGHtxNqIlQp8cOcn7tyhuf6NdSb+VlXXO92OB9mZC3nHnmC+V6nlRVmwOHthJoIVUr8MOfnrpzhuX4N9WZ+1hXXux3OhxlZy7lHnmC+12llhRlQO8+ourWdrgtYmZatOQ/99BgS9pjkIjQIPyXJhSqOQBU+SAQ+xz2VFUlASV9DvHChcqECVqZla85DPz2GhD0muQgNwk9JcqGKI1CFDxKBz3FPZUUSUNLXEC9cqFyogJVp2Zrz0E+PIWGPSS5Cg/BTklyo4ghU4YNE4HPcU1mRBJT0xZyxXkBU76g9vflx48ycXrc9zFxuDbrlur2fofl130VlhSntPGuzV4ydPBI+vflx44zyo+3CP5dbg265bu9naH7dd1FZYUo7z9rsFWMnj4RPb37cOKP8aLvwz+XWoFuu2/sZml/3XVRWmDKZ51fhkfDR5oLPjxtnOB9tX7bvIfR16TiqL0Kurf2gzK/zM3QIDwg/1eMz5EwQM1dlbLbmDOej7cv2PYS+Lh1H9UXItbUflPl1foYO4QHhp3p8hpwJYuaqjM3WnOF8tH3ZvofQ16XjqL4Iubb2gzK/zs/QoaSd58jkc4iiKIoiifIfjKIoip6s/AejKIrupH+lC6c3""",
"replay" : """eJztlduRAyEMBDf/nHx/zusCcBUGNEKNPFv9uZLnAevX3/tljDHGGGOMMcYYY4wxQ56Vp1ytGUCrCaIHIgOL8/lNevTu/6820GqC6IHIwOJ8fpMevfv/qw20miB6IDKwOJ/fpEfvSy72Xt77H1T9jdL21DZ4MihILD16H8gI6lGN7+mZeZkWeElxKj15sdTqyXu5ti/antoGTwYFiaVH7wMZQT2q8T09My/TAi8pTqUnL5ZaPXkv1/ZF21Pb4MmgILH06H0gI6hHNb6nZ+ZlWuAlxan05MVSq0f1ctCF6idUYZaUchIb3J46GV2enjwXtLvc1dfSnufjKfF+souT4q8+Gzdig9tTtHua57RWM+2I0nwt7Xk+nhLvJ7s4Kf7qs3EjNrg9RbuneU5rNdOOKM3X0p7n4ynxLu9i5pGHuadHtbBkD40eLuQGZ6ZORpenJ+jiy11VaC45ojRfQT2qVGl9zcSyl3OeHtXCkj00eriQG5yZOhldnp6giy93VaG55IjSfAX1qFKl9TUTy17OeXpUC0v20OjhQm5wZupkdHl6gi6+3FWF5pIjSvMV1KNKldaX/LeCC2/0flIzNgQsze6p6vNFyyfP4NW+5HpovQ+CynORt5B2VmmasSFgod3ToIvBc3U+eQav9iXXQ+t9EFSei7yFtLNK04wNAQvtngZdDJ6r88kzeLUvuR5a74Og8lwcWKjqfW9cvgdLDxdLTlUHoFlN2AtSGzjEl0qPalzeV56evFLy+gqOy/dg6eFiyanqADSrCXtBagOH+FLpUY3L+8rTk1dKXl/BcfkeLD1cLDlVHYBmNWEvSG3gEF8qPapxeV/yeI0xENpf6ry/CfsyxphC2n/0un7nu/oyxphJ2n/0un7nu/qq5R+7zemZ"""}
for i in msg.keys():
msg[i] = base64.b64decode(msg[i])
msg[i] = zlib.decompress(msg[i])
msg[i] = pygame.image.fromstring(msg[i], (msgwidths[i], 24), "RGB")
msg[i] = msg[i].convert(msg[i])
return msg
def getAllMatchesInAGridCombinations(self, width, height, matches):
a = []
# Horizontals:
for row in range(height):
for column in range(width + 1 - matches):
b = []
for u in range(matches):
b.append(str(u + column) + str(row))
a.append(b)
# Verticals:
for column in range(width):
for row in range(height + 1 - matches):
b = []
for u in range(matches):
b.append(str(column) + str(u + row))
a.append(b)
# DiagonalsTopLeftToDownRight:
# -2 to +3:
for d in range(- (height - matches), (width - matches) + 1, 1):
for i in range(width - matches):
b = []
for u in range(matches):
x = i + u
y = i + u
if d > 0:
x += d
if d < 0:
y -= d
if x >= width or y >= height:
break
b.append(str(x) + str(y))
if len(b) == matches:
a.append(b)
# DiagonalsTopRightToDownLeft:
# -3 to +2:
for d in range(- (width - matches), (height - matches) + 1, 1):
for i in range(width - matches):
b = []
for u in range(matches):
x = width - 1 - i - u
y = i + u
if d < 0:
x += d
if d > 0:
y += d
if x < 0 or y >= height:
break
b.append(str(x) + str(y))
if len(b) == matches:
a.append(b)
return a
if __name__ == '__main__':
Main()
I'm quite happy with that. It's also good to see, the forum lets me post a slightly longer piece of code.