from __future__ import annotations from .coordinate import Coordinate from typing import Union OFF_STATES = [False, 0, None] OFF = False ON = True class Grid: def __init__(self, default=False): self.__default = default self.__grid = {} self.__minX = 0 self.__minY = 0 self.__maxX = 0 self.__maxY = 0 def __trackBoundaries(self, pos: Coordinate): if pos.x < self.__minX: self.__minX = pos.x if pos.y < self.__minY: self.__minY = pos.y if pos.x > self.__maxX: self.__maxX = pos.x if pos.y > self.__maxY: self.__maxY = pos.y def toggle(self, pos: Coordinate): if pos in self.__grid: del self.__grid[pos] else: self.__trackBoundaries(pos) self.__grid[pos] = not self.__default def set(self, pos: Coordinate, value: any): if value in OFF_STATES and pos in self.__grid: del self.__grid[pos] elif value not in OFF_STATES: self.__trackBoundaries(pos) self.__grid[pos] = value def getState(self, pos: Coordinate) -> bool: if pos not in self.__grid: return False else: return self.__grid[pos] not in OFF_STATES def getValue(self, pos: Coordinate) -> any: if pos not in self.__grid: return self.__default else: return self.__grid[pos] def getOnCount(self): return len(self.__grid) def isSet(self, pos: Coordinate) -> bool: return pos in self.__grid def isCorner(self, pos: Coordinate) -> bool: return pos in [ Coordinate(self.__minX, self.__minY), Coordinate(self.__minX, self.__maxY), Coordinate(self.__maxX, self.__minY), Coordinate(self.__maxX, self.__maxY), ] def add(self, pos: Coordinate, value: Union[float, int] = 1): if pos in self.__grid: self.__grid[pos] += value else: self.__trackBoundaries(pos) self.__grid[pos] = self.__default + value def sub(self, pos: Coordinate, value: Union[float, int] = 1): if pos in self.__grid: self.__grid[pos] -= value else: self.__trackBoundaries(pos) self.__grid[pos] = self.__default - value def getSum(self, includeNegative: bool = True): grid_sum = 0 for value in self.__grid.values(): if includeNegative or value > 0: grid_sum += value return grid_sum def getNeighbourSum(self, pos: Coordinate, includeNegative: bool = True, includeDiagonal: bool = True) \ -> Union[float, int]: neighbour_sum = 0 for neighbour in pos.getNeighbours( includeDiagonal=includeDiagonal, minX=self.__minX, minY=self.__minY, maxX=self.__maxX, maxY=self.__maxY): if neighbour in self.__grid: if includeNegative or self.__grid[neighbour] > 0: neighbour_sum += self.__grid[neighbour] return neighbour_sum