Created
June 7, 2021 23:15
-
-
Save tkshill/dafd645d9c12928662f0144a95309dba to your computer and use it in GitHub Desktop.
Python 3.10 with Typing and MyPy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import NewType, Literal, Union, Tuple | |
# Our standard grid is a 2d array of cells that are either a mine | |
# or not a mine | |
Mine = Literal["Mine"] | |
NotAMine = Literal["NotAMine"] | |
Cell = Union[Mine, NotAMine] | |
Grid = list[list[Cell]] | |
# Our annotated grid is a 2d array of cells that are either the number | |
# of mines nearby or NoMinesNearby or a Mine | |
NoMinesNearby = Literal["NoMinesNearby"] | |
MinesNearby = NewType('MinesNearby', int) | |
AnnotatedCell = Union[NoMinesNearby, MinesNearby, Mine] | |
AnnotatedGrid = list[list[AnnotatedCell]] | |
def annotate(minefield: list[str]) -> list[str]: | |
"""Given a list of strings representing rows in a minesweeper table, | |
returns a list of strings representing annotated rows.""" | |
# if all rows aren't the same length as the first row, throw an error | |
if not all(len(row) == len(minefield[0]) for row in minefield): | |
raise ValueError("Strings must be the same length") | |
grid: Grid = [list(map(toCell, row)) for row in minefield] | |
annotatedGrid = toAnnotatedGrid(grid) | |
result = ["".join((toChar(ac) for ac in row)) for row in annotatedGrid] | |
return result | |
def toCell(char: str) -> Cell: | |
match char: | |
case "*": return "Mine" | |
case " ": return "NotAMine" | |
case _: raise ValueError("Should be whitespace or an asterisk") | |
def toAnnotatedGrid(grid: Grid) -> AnnotatedGrid: | |
annotatedGrid: AnnotatedGrid = [] | |
for i, row in enumerate(grid): | |
annotatedGrid.append([]) | |
for j, cell in enumerate(row): | |
if cell == "Mine": # just pass along to the annotated grid | |
annotatedGrid[i].append(cell) | |
else: | |
mineNumber = countMines(grid, i, j) | |
if mineNumber == 0: | |
annotatedGrid[i].append("NoMinesNearby") | |
else: | |
annotatedGrid[i].append(MinesNearby(mineNumber)) | |
return annotatedGrid | |
def countMines(grid: Grid, i: int, j: int) -> int: | |
"""Given a grid and the position of cell in said grid, | |
count the number of mines around that cell.""" | |
# using max and min to clamp range down to values that exist in grid | |
rowRange = range(max(i-1, 0), min(i+2, len(grid))) | |
colRange = range(max(j-1, 0), min(j+2, len(grid[i]))) | |
minesFound = 0 | |
for r in rowRange: | |
for c in colRange: | |
if grid[r][c] == "Mine": | |
minesFound += 1 | |
return minesFound | |
def toChar(ac: AnnotatedCell) -> str: | |
match ac: | |
case "NoMinesNearby": return " " | |
case "Mine": return "*" | |
case _: return str(ac) # convert our mines nearby count to string |
Tuple, Union are no longer needed in 3.10?
Yes, I just found the PEPs that address this thanks to your comment. Unions can be achieved with |
and Tuples simply need the []
. Thank you. Very much appreciated.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tuple, Union are no longer needed in 3.10?