在网格中的对角线的正方形

时间:2013-05-11 17:26:28

标签: python python-3.x grid pygame grid-layout

我有一个python网格类,我正在尝试创建一个方法来获取某个图块所属的对角线。我已经成功地通过对角线从左向右下降,并想知道如何更改它,以便我可以通过更改“方向”参数从右向左移动。这是我的方法:

    def getDiagonal(self, tile, direction = 1):
        index = self.index(tile)
        diagonal = []

        currentIndex = [i - index[0] for i in index]

        while currentIndex[1] != self.y:
            diagonal.append(self[currentIndex[0]][currentIndex[1]])

            currentIndex = [i + 1 for i in currentIndex]

        return diagonal

这是包含Grid类的整个模块:

# Grid library for Pygame by Bobby Clarke
# GNU General Public License 3.0

# Version 1.1

import pygame
import math
from fractions import gcd
from functools import reduce

def _isEven(i):
    return i % 2 == 0

def product(_list):
    return reduce(lambda x, y: x * y, _list, 1)

def _range(start, stop, step=1):
    """Range function which can handle floats."""
    while start < stop:
        yield start
        start += step

def _simplify(a, b):
    hcf = gcd(a, b)
    return (a / hcf, b / hcf)

class Tile(pygame.Rect):
    def __init__(self, point, size, colour = None, imgs = [], tags = []):
        self.size = [int(i) for i in size]
        self.point = point
        self.colour = colour

        for img in imgs:
            if isinstance(img, tuple):
                imgs[imgs.index(img)] = pygame.image.fromstring(img[0],
                                                                img[1],
                                                                img[2])
        self.imgs = imgs[:]
        self.tags = tags[:]

        pygame.Rect.__init__(self, self.point, self.size)

    def __lt__(self, other):
        return (self.point[0] < other.point[0] or
                self.point[1] < other.point[1])
    def __gt__(self, other):
        return (self.point[0] > other.point[0] or
                self.point[1] > other.point[1])
    def __le__(self, other):
        return (self.point[0] <= other.point[0] or
                self.point[1] <= other.point[1])
    def __ge__(self, other):
        return (self.point[0] >= other.point[0] or
                self.point[1] >= other.point[1])

    def toData(self, imgFormat = "RGBA"):
        return (self.point, self.size, self.colour,
               [(pygame.image.tostring(img, imgFormat),
                 img.get_size(), imgFormat) for img in self.imgs], self.tags)

    def fromData(data, baseTile = None):
        tile = Tile(*data)

        if baseTile and isinstance(baseTile, Tile):
            baseTile = tile
        else:
            return tile

    def getRect(self):
        return self
    def getColour(self):
        return self.colour
    def setColour(self, colour):
        self.colour = colour
    def getPoint(self):
        return self.point
    def addTag(self, *tags):
        if isinstance(tags[0], list):
            self.tags.extend(tags[0])
        else:
            self.tags.extend(tags)
    def hasTag(self, tag):
        return (tag in self.tags)
    def delTag(self, tag):
        self.tags.remove(tag)
    def clearTags(self):
        self.tags = []
    def addImg(self, img, resize = False):
        if isinstance(img, pygame.Surface):
            if img.get_rect() != self and resize:
                img = pygame.transform.scale(img, (self.size))
            self.imgs.append(img)
        elif img is not None:
            raise TypeError("Images must be pygame.Surface object")
    def delImg(self, img):
        self.imgs.remove(img)
    def clearImgs(self):
        self.imgs = []

    def isClicked(self):
        return self.collidepoint(pygame.mouse.get_pos())

    def draw(self, surface):
        if self.colour is not None:
            surface.fill(self.colour, self)
        for img in self.imgs:
            surface.blit(img, self)

class Grid():
    def __init__(self, surface, num, colour = None, tiles = None, 
                 force_square = False):
        self.WIDTH = surface.get_width()
        self.HEIGHT = surface.get_height()
        self.surface = surface

        aspect_ratio = _simplify(self.WIDTH, self.HEIGHT)

        if isinstance(num, int):
            if aspect_ratio == (1, 1) or force_square:
                self.x = math.sqrt(num)
                self.y = math.sqrt(num)

            else:            
                self.x = aspect_ratio[0] * (num / product(aspect_ratio))
                self.y = aspect_ratio[1] * (num / product(aspect_ratio))
        else:
            try:
                self.x = num[0]
                self.y = num[1]
            except TypeError:
                raise TypeError("2nd argument must be int or subscriptable")

        self.tilesize = (self.WIDTH / self.x,
                         self.HEIGHT / self.y)
        self.num = num
        self.colour = colour

        if tiles:
            if hasattr(tiles, "__getitem__") and isinstance(tiles[0], Tile):
                self.tiles = tiles
            else:
                self.tiles = [[Tile.fromData(tile) for tile in column]
                              for column in tiles]
        else:
            self.tiles = self.maketiles(colour)

    def __getitem__(self, index):
        return self.tiles[index]

    def __setitem__(self, index, new):
        self.tiles[index] = new

    def __len__(self):
        return len(self.tiles)

    def index(self, tile):
        for column in self.tiles:
            if tile in column:
                return self.tiles.index(column), column.index(tile)

    def getTiles(self):
        """Get all tiles. Returns a generator"""
        for column in self.tiles:
            for tile in column:
                yield tile

    def tagSearch(self, tag):
        """Search for tiles by tag. Returns a generator"""

        for tile in self.getTiles():
            if tile.hasTag(tag):
                yield tile

    def pointSearch(self, point):
        """Search for tiles by point. Returns a tile"""

        for tile in self.getTiles():
            if tile.collidepoint(point):
                return tile

    def rectSearch(self, rect):
        """Search for tiles by rect. Returns a generator"""

        for tile in self.getTiles():
            if tile.colliderect(rect):
                yield tile

    def getColumn(self, i):
        return self.tiles[i]
    def getRow(self, i):
        return [column[i] for column in self.tiles]

    def checker(self, colour1, colour2 = None):
        for column in self.tiles:
            for tile in column:
                if _isEven(self.tiles.index(column) + column.index(tile)):
                    tile.setColour(colour1)
                else:
                    if colour2:
                        tile.setColour(colour2)

    def getDiagonal(self, tile, direction = 1):
        index = self.index(tile)
        diagonal = []

        currentIndex = [i - index[0] for i in index]

        while currentIndex[1] != self.y:
            diagonal.append(self[currentIndex[0]][currentIndex[1]])

            currentIndex = [i + 1 for i in currentIndex]

        return diagonal

    def getBetweenTiles(self, tile1, tile2):
        """Inefficient and badly implemented"""

        index1 = self.index(tile1)
        index2 = self.index(tile2)

        if index1[0] != index2[0] and index1[1] != index2[1]:
            raise ValueError("Tiles must be in same row or column")

        for column in self.tiles:
            if tile1 in column and tile2 in column:
                return column[column.index(tile1) : column.index(tile2)]

        for i in range(self.y):
            row = self.getRow(i)
            if tile1 in row and tile2 in row:
                    return row[row.index(tile1) : row.index(tile2)]

    def getSurroundingTiles(self, tile,  adjacent = True, diagonal = True):    
        di = (0, 1, 0, -1, 1, 1, -1, -1)
        dj = (1, 0, -1, 0, 1, -1, 1, -1)
        # indices 0 - 3 are for horizontal, 4 - 7 are for vertical

        index = list(self.getTiles()).index(tile)
        max_x = self.x - 1 # Offset for 0 indexing
        max_y = self.y - 1

        i = int(math.floor(index / self.x))
        j = int(index % self.y)

        surroundingTiles = []

        startat = 0 if adjacent else 4
        stopat = 8 if diagonal else 4

        for k in range(startat, stopat):
            ni = i + di[k]
            nj = j + dj[k]
            if ni >= 0 and nj >= 0 and ni <= max_x and nj <= max_y:
                surroundingTiles.append(self[ni][nj])

        surroundingTiles.reverse()

        return sorted(surroundingTiles)

    def draw(self, drawGrid = False, gridColour = (0, 0, 0), gridSize = 1):
        for tile in self.getTiles():
            tile.draw(self.surface)

            if drawGrid:
                pygame.draw.rect(self.surface, gridColour, tile, gridSize)

    def maketiles(self, colour):
        """Make the tiles for the grid"""

        tiles = []

        width = self.WIDTH / self.x
        height = self.HEIGHT / self.y

        for i in _range(0, self.WIDTH, width):
            column = []

            for j in _range(0, self.HEIGHT, height):
                sq = Tile((i, j), (width, height), colour)

                column.append(sq)

            tiles.append(column)

        return tiles

    def toData(self):
        return (self.num, self.colour,
                [[tile.toData() for tile in column] for column in self.tiles])

    def fromData(data, surface):
        return Grid(*([surface] + list(data)))

更新: 我有我想要做的图片示例:

https://dl.dropboxusercontent.com/u/127476718/Images/this%20tile.png https://dl.dropboxusercontent.com/u/127476718/Images/diags.png

0 个答案:

没有答案