Search code examples
pythonpython-3.xconways-game-of-life

Using 2D Lists to Print a Shape on a Board, Game of Life, Homework


I've had a pretty good grasp on concepts until I hit 2D lists, and I recently failed a homework assignment in which I had to make a simple rendition of "Conway's Game of Life" using 2D lists. I was able to print the board, and a U shape using for loops, but I couldn't even start trying to do the same with 2D lists. I'm just so lost, and I feel like if I can just get a jumping off point that I can figure out the rest. The other issue is that the "U" shape is static, and I've tried a few different things with "randint" function, but can't get the entire "U" shape to move around.

EDIT: Added code to the bottom starting at "tempGen".

I figured out how to print the 30 x 60 board using a 2D list, and I'm currently trying to figure out how to incorporate my "U" shape into there.

#! python3
import random
from random import randint
MAX_ROW = 30
MAX_COL = 60
currentGen = [ [MAX_ROW], [MAX_COL] ]
tempGen = [ [MAX_ROW], [MAX_COL] ]

def displayMenu(): #DISPLAY OUTPUT OPTIONS, DON'T COLLECT
    print("[P]lay - Press 'P' to play.\n[Q]uit - Press 'Q' to exit.\n")

def setZeroList(): #INITIALIZE 2-D LISTS TO ZERO
    currentGen = [[0], [0]]
    tempGen = [[0], [0]]
    return currentGen, tempGen

def copyList(): #COPY 2D LIST TO ANOTHER 2D LIST
    print("?????")

def displayList(): #PRINTS ANY 2D LIST
    print("?????")

def setInitialPatternList(): #CREATE THE "U" SHAPE
    for MAX_ROW in range(30):
        for MAX_COL in range(60):
            if ((MAX_COL == 0 or MAX_COL == 6) and MAX_ROW <= 5) or (MAX_ROW == 5 and (MAX_COL >= 0 and MAX_COL <= 6)):
                print("X", end="")
            else:
                print(end = ".")
        print()


tempGen = [["*"]* MAX_COL] * MAX_ROW

print("\ntable:")
for row in range(MAX_ROW):
    for col in range(MAX_COL):
        if (col == (MAX_COL - 1)):
            print(tempGen[row][col], end = "\n")
        else:
            print(tempGen[row][col], end = "")

Solution

  • Lets start with what 2D lists really are. A 2D list is simply a list of lists. With a normal list, you can do things like

    my_list[0] = 4
    

    For a 2D list, each element is a list-

    list_of_lists[4] = ["a","b"]
    

    In this case list_of_list[4][0] returns "a", because we are really doing (list_of_list[4])[0]. You can think of the something[i][j] notation to being equivalent to Coordinate Plane: 'something', Position: (i, j), with i and j being x and y values.

    With that out of the way, lets consider making 2D lists. Since every "row" in your 2D list consists of a list, you need to first populate your original list with empty lists. Something like

    list_of_lists = []
    for i in range(depth):
        list_of_lists.append([])
    

    This will allow you to assign to append to any row of your 2D list, within range of [0,depth). You cannot simply use tempGen = [["*"]* MAX_COL] * MAX_ROW as your original post does, because every row of your 2D list will be a reference to the same exact list, and thus changing one row affects all rows identically. If you also want to access each element without appending, consider filling the original list with something like [0] * width or [None] * width, instead of the empty list [].

    Now lets say you have a 2D list built, you populated it with some data, and now you would like to shift all elements rightwards. You can write a function to do this

    def right_shift(my_list):
        for row_num in range(len(my_list)):           # for each list in our list of lists
            row = my_list[row_num]
            for col_num in range(len(row)-2, -1, -1): # skip the last element, and iterate backwards
                row[col_num + 1] = row[col_num]       # assign the (col_num+1)th element to equal the col_num 'th element in that row.
        return my_list
    

    Just write the logic to handle one row, and then extend that logic to all other rows of your list of lists (usually with just a for loop).

    For good measure, lets cover printing your 2D array-

    def print_matrix(list_of_lists):
       for row in list_of_lists:
           print("".join(map(str, row))) # here map(str,...) is used to make sure every element is a string.
    

    Once you get comfortable with 2D lists, you may want to consider looking at dictionaries. You can avoid nesting lists by using a tuple as the key, for example my_dict[(14, 27)] = "A", or even using a defaultdict to avoid populating each entry with an empty list/dict first- from collections import defaultdict; my_2D_dict = defaultdict(dict), which could then be used directly my_2D_dict[4][2] = "something".