Package: minesweeper-model
Minesweeper ModelThis package is aMinesweeper gamewithout a frontend. In other words, it only offers a Minesweeper model and an interface to access and modify the minefield or "play" the game programmatically. As a result, this package is not meant to be a Minesweeper game playable by an end user.This package is mostly meant for people who develop Minesweeper solvers. Anyone developing such a solver can use this package to skip the step of developing a Minesweeper model to test their solver on and start working on the solver itself straightaway.InstallationThe package is hosted onPyPI. You can install it withpip:pipinstallminesweeper-modelUsageThis package offers aFieldclass which models a minefield in a Minefield game. It stores all the necessary state of a field: the open tiles, flagged tiles, tiles with a mine under it, etc. By the rules of the game, the player isn't allowed to know where the mines are hidden.TheFieldclass has methods to allow interacting with it as a player (i.e. you are only given hints, the number of mines surrounding a tile, but not the mine locations). However, of course, direct access to mine locations are possible if desired as well.Initializationfromminesweeper_modelimportfield# Mine locations are expressed as two-tuples (x, y)# The top-left tile in the minefield has coordinates (0, 0).# Mine locations argument is optional, so a field without mines# is theoretically possible.mine_coords=[(0,0),(1,0)]field=field.Field(5,5,mine_coords)Data stored in theFieldclass# List of tuples (x, y) of mine coordinates.field.mine_coords# List of tuples (x, y) of coordinates which have been opened by the player.field.open_coords# List of tuples (x, y) of coordinates which have been flagged as having a mine.field.flag_coords# Dictionary populated with the "hint" for all tiles in the Field given# during initialization of the `PlayerField` class. This is the number# of mines in the surrounding 8 tiles for each tile. Dictionary is in the# format `{(x, y): int}` where int is the hint with possible values# being 0 to 8 or -1 (for tiles which have mines underneath)field.hintsInteract with theFieldclassUse thetileandnine_tilesmethods to get information about a single field and a group of nine fields respectively. You will only receive the information a player would get (i.e. anything but the location of mines)# Return a dictionary {"hint": int, "flag": bool} where# "hint" is the hint revealed by openning the tile, or# the value None if the tile is closed. "flag" is whether# the tile is flagged.field.tile(x,y)# Returns the same data as `tile` method for the given# tile as well as the 8 tiles surrounding it.# Data is returned in format: {(x, y): {"hint": int, "flag": bool}, ...}field.nine_tiles(middle_x,middle_y)Open tiles and place flags in the field:# This will open the tile in given coordinates. Will return# True if tile does not hide a mine, False otherwise.# If tile has no mine, given coordinates will be added to open_coords.field.open_tile(x,y)# Pass True to the third coordinate so that in addition to the given tile# being opened, all the adjacent tiles with a hint of 0 will also be opened,# similar to the way it does in some versions of the Minesweeper game.field.open_tile(x,y,True)# Add or remove flag on tile.field.toggle_flag(x,y)Visual representation of fieldsDraw the field showing mine locations:print(field.render_mines())# x...# ...x# ....# .x..# You can use custom strings when drawingprint(field.render_mines(tile_str="o",mine_str="@"))# @ooo# ooo@# oooo# o@ooDraw the field a player would see, only showing hints and flags but not mines:print(field.render_player_field())# !...# 22..# xx..# ....# You can use custom strings when drawingprint(player_field.render_player_field(flag_str="?",closed_str="o"))# ?ooo# 22oo# xxoo# ooooGenerator utilitiesThe package also contains utilities to help you generate minefields.Generate N many mine locations randomly for a given field size:fromminesweeper_modelimportgenerator# generate 4 mine coordinates# for a field of size (5, 10)generator.random_mine_coords(5,10,4)# => [(1, 5), (3, 2), (0, 0), (1, 6)]Generate hint for a single tile given a list of mine coordinates:mines=[(4,1),(6,4)]# Generate hint for a tile at (1, 1)generator.hint_for_tile(1,1,mines):# => 0Generate hints for an entire field:mines=[(4,1),(6,4)]# Generate hints for a field of size (10, 10)generator.hints_for_field(10,10,mines)# => {(0, 0): 0, (0, 1): 0, ... , (9, 9): 0}General utilitiesGet coordinates of surrounding tiles:fromminesweeper_modelimportutilityutility.surrounding_tiles(1,1)# => [(0, 0), (0, 1), (0, 2), (1, 0),#     (1, 2), (2, 0), (2, 1), (2, 2)]# If the tile is on the edge, method will# return -ve coordinates as well.utility.surrounding_tiles(0,0)# => [(-1, -1), (-1, 0), (-1, 1), (0, -1),#     (0, 1), (1, -1), (1, 0), (1, 1)]# You can choose to remove -ve coordinates:utility.surrounding_tiles(0,0,True)# => [(0, 1), (1, 0), (1, 1)]Convert a textual representation of a field to parameters you can pass to aFieldobject as an easier way of creating fields (Thanks to@27Anuragfor the contribution):str_field="""..x...x...........x........xx......"""width,height,mine_coords=utility.str_input_to_mine_coords(str_field)# => width: 7, height: 5, mine_coords: [(2, 0), (6, 0), (4, 2), (6, 3), (0, 4)]f=field.Field(width,height,mine_coords)DevelopmentThe package currently only officially supportspython3.Tests are written withunittestand are under the "tests" directory. You can run all tests on the command line withpython3 -m unittest.flake8is used for checking the code follows some Python best practices and styling standards. You can run the checks on the command line withflake8(need to install flake8 first).toxis used to automate testing. You can run all tests and checks (e.g. flake8) on the command line withtox(need to install tox first).