[Tutor] Making Doubly Linked List with Less Lines of Code.

Steven D'Aprano steve at pearwood.info
Fri Jan 2 08:21:56 CET 2015


Fixing the mangled formatting, as best as I am able (and can be 
bothered).

On Thu, Jan 01, 2015 at 11:48:18PM -0500, WolfRage wrote:

class GameTile():
    def __init__(self, id, **kwargs):
        # id is (X,Y)
        self.id = id

What is the purpose of the **kwargs? It doesn't get used, it just 
silently ignores them.

Actually, what is the purpose of this GameTile class? It has no methods 
apart from the constructor. That is a sign of a class that isn't pulling 
its weight, its not doing anything. All the other code in your program 
looks inside the GameTile and accesses self.id directly. This is a sure 
sign of a class that doesn't need to exist.

It may be better to give this at least a __str__ method, so if 
nothing else you can print it without looking inside:


class GameTile():
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __str__(self):
        return "%d, %d" % (self.x, self.y)



class GameGrid():
    def __init__(self, **kwargs):
        self.cols = 7
        self.rows = 8
        # grid is 2d array as y, x ie [y][x].
        self.grid = [[None] * self.rows for i in range(self.cols)]

Why do you have GameTiles use X,Y but the grid uses the opposite order, 
Y,X? This is going to cause confusion. I'm already confused!


    def make_grid(self):
        for row in range(0, self.rows):
            for col in range(0, self.cols):
                self.grid[col][row] = GameTile(id=str(row) + ',' + str(col))

No need to write range(0, Whatever), since range defaults to 0. Better 
to write range(Whatever).

Why does the GameTile record the coordinates as strings?

I would prefer something like this:

    def make_grid(self):
        for row in range(self.rows):
            for col in range(self.cols):
                self.grid[col][row] = GameTile(row, col)


although it looks strange due to the backwards ordering of col/row.


Your __init__ method should automatically call make_grid. That is:

    def __init__(self, **kwargs):
        self.cols = 7
        self.rows = 8
        # grid is 2d array as y, x ie [y][x].
        self.grid = [[None] * self.rows for i in range(self.cols)]
        self.make_grid()


Actually, even better will be to move the self.grid = ... line out of 
the __init__ method, and make it part of make_grid. Since it is part of 
making the grid.



    def print_by_row(self):
        for col in range(0, self.cols):
            for row in range(0, self.rows):
                print(self.grid[col][row].id)

This now becomes:

    def print_by_row(self):
        for col in range(0, self.cols):
            for row in range(0, self.rows):
                print(self.grid[col][row])


since GameTiles now know how to print themselves. Likewise for this:

    def print_by_col(self):
        for row in range(0, self.rows):
            for col in range(0, self.cols):
                print(self.grid[col][row])


Another simplification here:


    def check_bounds(self, x, y):
        return (0 <= x < self.rows) and (0 <= y < self.cols)



Your lookup_node method returns a GameTile or False on failure:

    def lookup_node(self, x, y, ):
        if not self.check_bounds(x, y):
            return False
        return self.grid[y][x]

I'm not sure about that design. I wonder whether it would be better to 
return None, or raise an exception.

You have a lookup_node method that checks the bounds, but you don't seem 
to use it anywhere. Why does it exist?



    def draw_grid(self):
        for col in range(0, self.cols):
            print(end='| ')
            for row in range(0, self.rows):
                print(self.grid[col][row].id, end=' | ')
        print()


I'm not sure if I have reconstructed the indentation correctly here. A 
few changes: no need to call range(0, ...). GameTile instances now know 
how to print themselves, so you can call:

                print(self.grid[col][row], end=' | ')



This could be improved:

temp = GameGrid()
temp.make_grid()
temp.draw_grid()


Creating a GameGrid should automatically create the game grid, hence 
what I said above about having __init__ call make_grid. Then use a more 
meaningful name, and we have:


grid = GameGrid()
grid.draw_grid()  # Maybe this could be just called "draw"?



-- 
Steven


More information about the Tutor mailing list