Understanding 2D Arrays in Python for Minesweeper Game Implementation
Explore the concept of 2D arrays in Python through the implementation of the Minesweeper game. Learn how to represent game boards, handle lists as arrays, and work with multi-dimensional data structures for efficient game development.
Download Presentation
![](/assets/img/so-down.gif)
Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. Download presentation by click this link. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
E N D
Presentation Transcript
2-D Arrays in Python And how not to get snake-bitten Bill Emshoff Software Engineer Lockheed Martin Bill.Emshoff@att.net
To get the most out of this presentation, follow along on your own PC in Python. Depending upon your installation, you can get there by typing python or py from a command window, or better still, idle from the search bar to bring up the Python Integrated Development and Learning Environment (IDLE). You should see something like this: Python 3.9.1 Type "help" for more information. >>> Don t be afraid to experiment with the command-line interface! First things first: Start Python!
An Excel spreadsheet can be thought of as a 2D array of rows and columns, but let s look at something more fun, like how we d implement the game Minesweeper in Python, where each element on the board is either a bomb (touch it and die!) or a safe spot, containing a clue about how many bombs are nearby. By Source (WP:NFCC#4), Fair use, https://en.wikipedia.org/w/index.php?curid=65727752 Motivation: what good is a 2D array for anyway?
Python lists can be used as arrays >>> shopping_list = [ "bread", "milk", "apples" ] >>> shopping_list[0] # first item 'bread' >>> shopping_list[2] # last item 'apples' >>> shopping_list[-1] # also last item: list indices wrap! 'apples' >>> len(shopping_list) 3 >>> # lists can be updated a number of ways: >>> shopping_list.append("oranges") >>> shopping_list.remove("apples") >>> shopping_list ['bread', 'milk', 'oranges'] Background: Python lists as arrays
A Python List can hold anything, so we can use a List of Lists as a 2D array >>> the_matrix = [ [1,2,3], [4,5,6] ] >>> the_matrix[0] # 1st row [1, 2, 3] >>> the_matrix[0][2] # element at 1st row, 2nd column 3 The syntax matrix[row][col] is the same used for other languages like Java List of Lists as a 2D Array
Our game needs to support variable-sized grids. Python has shortcuts to create arrays of any size: Using Python List Multiplication >>> myArraySize = 4 >>> myArray = [0] * myArraySize >>> myArray [0, 0, 0, 0] Using a List Comprehension: Python s killer feature >>> myArray = [ 0 for _ in range(myArraySize) ] >>> myArray [0, 0, 0, 0] Creating a zero-filled array of variable size
Creating a 2D array the WRONG way Nesting Python list multiplication (don t do this) >>> nRows = 3; nCols = 2 >>> myGrid = [ [0]*nCols ] * nRows >>> myGrid [[0, 0], [0, 0], [0, 0]] Looks as expected. Now set the 1st element: >>> myGrid[0][0] = 'B' >>> myGrid [['B', 0], ['B', 0], ['B', 0]] Say what? Is Python buggy??? Putting it all together: Creating an empty game grid: 1st attempt
Important point to remember about objects in Python (and languages like Java too!): Variables are like pointers to an object, so copying a variable doesn t copy data, only a pointer to the data: >>> a = [1,2]; b = a >>> a[0] = 3 >>> b # a is just pointer to the same array as b [3, 2] Lesson learned: If you want a copy of a list in Python, you must explicitly copy it Creating an empty game grid: why the 1st attempt failed
Nesting a list comprehension >>> myGrid = [ [ 0 for c in range(nCols) ] for r in range(nRows) ] >>> myGrid[0][0] = '*' >>> myGrid [['*', 0], [0, 0], [0, 0]] Alternative: use the list-multiply shortcut but for the inner list only: myGrid = [ [0]*nCols for r in range(nRows) ] Putting it all together: Creating an empty game grid: The right way
For a production-quality game, well want to print our grid using a graphic library, but for quick testing (and Code Quest competitions), we re going to just use text: >>> def printGrid(grid): for row in grid: for item in row: # print each item with no newline between print(item, end='') print("") # adds newline at end of row >>> printGrid(myGrid) B0 00 00 Printing out our grid
Next step in implementing the game: for a grid populated by mines, marked with a * at any selected point, we want a function to count the adjacent bombs, horizontally, vertically, or diagonally, e.g., >>> printGrid(myGrid) *0 0* 00 >>> countAdjacentBombs(myGrid,0,1) 2 >>> countAdjacentBombs(myGrid,2,1) 1 Important: your function can t access points outside the grid, e.g., to access a row < 0 or a row past the end Student Exercise: completing the Minesweeper grid
# loop from 0 to the length of an array: for r in range( len(myGrid) ): # loop from start to stop : for r in range(start, stop): min(x,y) # minimum of 2 numbers max(x,y) # maximum of 2 numbers Helpful python functions to help implement our bomb-counting function
Now that we can get the count of adjacent bombs to any square, let s create a function to fill up the empty spots on the grid, using that function we just created, e.g., >>> populateGrid(myGrid) >>> printGrid(myGrid) *2 2* 11 Filling the grid
Todays Minesweeper- themed exercises were based off a real recent Code Quest contest, and constitute 90% of the code for this problem the rest being boilerplate. Wrap up
Formatting / pretty printing Text Regular Expressions Beyond Lists: Other Python Containers: Tuples, Sets, and Dictionaries A Class on Classes in Python Maze escapes using AI techniques Handling the Unexpected: Exceptions Other suggestions? Possible Topics for another session
Appendix A completed Code Quest solution to the Minequest problem using code written while preparing this presentation
def printGrid(grid): import sys # for stdin for row in grid: # Always start with reading in the number of test cases from standard input. cases = int(sys.stdin.readline()) for item in row: # print each item with no newline between print(item, end='') # Loop for each test case. This is the last line common to all problems for caseNum in range(cases): s = sys.stdin.readline().split() numRows = int(s[0]) numCols = int(s[1]) numBombs = int(s[2]) grid = [[0 for c in range(numCols)] print("") # adds newline at end of row def countAdjacentBombs(grid, row, col): # count adjacent bombs above, below, left, and right numRows=len(grid); numCols=len(grid[0]) numBombs = 0 for r in range(max(0,row-1), min(numRows,row+2)): for r in range(numRows)] for bomb in range(numBombs): s = sys.stdin.readline().split() r = int(s[0]) c = int(s[1]) for c in range(max(0,col-1), min(numCols,col+2)): if grid[r][c] == '*': numBombs += 1 return numBombs grid[r][c] = '*' populateGrid(grid) printGrid(grid) def populateGrid(grid): numRows = len(grid) numCols = len(grid[0]) # assuming a rectangular grid for row in range(numRows): for col in range(numCols): if grid[row][col] != '*': # count adjacent bombs up, down, left, right numBombs = countAdjacentBombs(grid, row, col) grid[row][col] = numBombs Minesweeper.py a complete Code Quest program entry