1

I've been working on a grid-based application using pygame, and have run into a strange problem.

I'm generating a list of tiles, each of which can have 1 of 3 random colours. Every time I run the program, though, I get a fairly consistent pattern.

Test 1

Test 2

Test 3

All these tests were right after each other, and similar results were on all runs before the tests, having a giant single-coloured blob in the bottom right.

This is my tile code

from enum import Enum


class Colour(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3


class Tile():

    def __init__(self, _map, x : int, y : int, colour = 1):
        self.x = x
        self.y = y
        self.map = _map
        self.colour = Colour(colour)

    def PrintInfo(self):
        print("x: " + str(self.x) + "\ny: " + str(self.y) + "\nCol: " + str(self.colour.name))

This is where an array of tiles is made, (where the random number is generated)

from Tile import Tile
from random import randint
"""Map class creates a 2d array of tiles, and allows individual tiles, or
groups of tiles to be returned."""


class Map:
    def __init__(self, width : int, height : int):
        self.map = []

        #Create a 2d array of tiles.
        self.map = [[Tile(self, i, j, randint(1, 3)) for i in range(width)] for j in range(height)]



    def PrintInfo(self):
        #Print the info of each tile. use GetTile(x, y).PrintInfo() tp get
        #individual tile into
        for t in self.map:
            t.PrintInfo()

    def GetTile(self, x: int, y: int):
        #Get tile from coords
        return self.map[x][y]

This is where the visual component is made, based off a random number

def Main(self):
    #Create an array of data objects
    self.map = Map(8, 8)
    #Create dictionary to connect data object to display object
    self.tileToObjDict = {}

    for i in range(8):#change these from constants after testing
        for j in range(8):
            t = self.map.GetTile(i, j)#get tile at current position in loop
            #t.PrintInfo()
            bobj = BoxObject(self.win, t.x*self.gridSpacing, t.y*self.gridSpacing, t.x*self.gridSpacing+self.gridSpacing,
                             t.y*self.gridSpacing+self.gridSpacing, str(t.colour.name).lower())#Create onject based on info
            self.objects.append(bobj)#add display object to render list
            self.tileToObjDict[t] = bobj#connect tile to display obj in dictionary

Not needed, but code of assembled visual component

#Basic Object

    class BoxObject(Object):
        def __init__(self, surface, x1 = 0, y1 = 0, x2 = 0, y2 = 0, colour = 'grey', hitbox = Hitbox(EventManager())):#Take a surface, 4 coords, a colour, and an optional hitbox to manage events
            super().__init__(Box(surface, Rectangle(x1,y1,x2,y2).GetCorners(),ColourManager().GetColour(colour)),
                hitbox)
            
            #draw the object for 1 frame to reference
            self.drawn = draw.rect(self.graphic.surface, self.graphic.colour,(self.graphic.coord1, self.graphic.coord2))
    
        def Update(self):
            if self.visible:#Draw the object
                draw.rect(self.graphic.surface, self.graphic.colour,(self.graphic.coord1, self.graphic.coord2))
                if Hitbox == None:
                    return
                if len(self.hitbox.eventM.eventList) > 0:#If the hitbox has any events to manage, manage them
                    for e in self.hitbox.eventM.eventList:
                        e()

Colour Module

from pygame import Color

class ColourManager:
    colourDict : {}#holds custom colours

    def __init__(self, defaultColours = True):
        self.colourDict = {}

        if defaultColours:
            self.AddBasicColours()

    def AddColour(self, name : str, _r : int, _g : int, _b : int, _a : int = 255):
        self.colourDict[name] = Color(_r, _g, _b, _a)
    
    def GetColour(self, name : str) -> Color:
        return self.colourDict.get(name)

    def PrintColours(self):
        for key in self.colourDict.keys():
            print(key)

    def AddBasicColours(self):
        self.AddColour('red', 255, 0, 0)
        self.AddColour('green', 0, 255, 0)
        self.AddColour('blue', 0, 0, 255)

        self.AddColour('grey', 100, 100, 100)

    def LoadColourSheet():
        """TODO: Allow many colours to be loaded at once from txt file"""

Any help is appreciated, on either an effective alternative randomization method, or a problem with my code that could be causing this issue.

5
  • all pseudo-random generators (no matter how complex) eventually repeat themselves. In any case try using another PRNG, even a custom one Commented Sep 20, 2021 at 8:48
  • 1
    @NikosM. Eventually, yes, but that should take a very long time. Not what the OP is seeing. Commented Sep 20, 2021 at 8:51
  • 1
    You select a random number out of only out of 3 numbers, and you see 3 different patterns. I don't see an issue there. Commented Sep 20, 2021 at 8:53
  • Exactly the OP has very limited random choices, so patterns are very easy to form or repeat. Commented Sep 20, 2021 at 8:54
  • There is too much code to call this a practical minimal example, but at a guess: the colours are properly random, but the pattern is definitely not. This line, BoxObject(self.win, t.x*self.gridSpacing, t.y*self.gridSpacing, t.x*self.gridSpacing+self.gridSpacing, t.y*self.gridSpacing+self.gridSpacing, str(t.colour.name).lower())#Create onject based on info, sets a pattern that is pretty much fixed, and self.map = [[Tile(self, i, j, randint(1, 3)) for i in range(width)] for j in range(height)] defines t.x and t.y indirectly, also as fixed values. Commented Sep 20, 2021 at 9:05

1 Answer 1

1

9769953 was right about it being the pattern and not the randomization. I forgot about how pygame rendered shapes, and the same pattern was because of single blocks being way bigger than they should have been. I had to change the x2 and y2.

        #Box object: screen to draw it to, x1, y1, x2, y2, colour (x1, y1) = top left corner  of box, x2 = width, y2 = height
        bobj = BoxObject(self.win, t.x*self.gridSpacing, t.y*self.gridSpacing, self.gridSpacing, self.gridSpacing, str(t.colour.name).lower())#Create object based on info
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.