Home > Software design >  Move a shape inside a list of lists
Move a shape inside a list of lists

Time:05-15

I have the following list of lists representing a matrix:

space = [ 
[0, 1, 1, 0],
[0, 1, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 0],
]

The number 1s represent an upside down L (like a gamma, "Γ"). How can I make this "object" move to the right, left, up and down as if it was a block? I move it with "asdw" keys.

Important: I am not able to use numpy, so thats makes the work way more difficult.

This is my failed method to make a RIGHT direction movement (btw it doesnt make the movement correctly), but i dont think its the best way and dont really think I can escalate it to other movements:

def show_space(space):
    for line in space:
        print(line)

x = input("Movement: ")

if x == 'd':
    for i in range(4):
        for j in range(4):
            if space[i][j] == 1:
                try:
                    if space[i][j 1] == 0:
                        space[i][j] = 0
                        space[i][j 1] = 1
                    if space[i][j 1] == 1 and space[i][j 2] == 0:
                        space[i][j] = 0
                        space[i][j 2] = 1
                except IndexError:
                    pass

show_space(space)

Is there any other method I could try? Or correct the one Im using? Thanks in advance

EDIT:

The gamma not only should be able to move right up down left, it should also be able to move 90 degrees, mirror itself, and all possible shapes that form can take. So if i had to hardcode all possible gamma or L combinations, i would have to hardcode 48 possibilities. I dont know wether hardcoding that is the optimal way to be honest.

Im not saying hardcoding the postions is not acceptable, it could definitely be a solution, but I just dont feel like its the correct way. i may be wrong of course.

What do you think?

CodePudding user response:

Here's how I'd suggest doing something like this:

Calculate all the indices for each gamma shape in the matrix, kept stored in a dictionary with the each corner index tuple as the dictionary keys, then whenever the corner moves, figure out the indices that should be 1s, and assign to a copy of a matrix of zeros.

positions = {(0, 0): ((0, 1), (1, 0), (2, 0)),
             (0, 1): ((0, 2), (1, 1), (2, 1)),
             (0, 2): ((0, 3), (1, 2), (2, 2)),
             (1, 0): ((1, 1), (2, 0), (3, 0)),
             (1, 1): ((1, 2), (2, 1), (3, 1)),
             (1, 2): ((1, 3), (2, 2), (3, 2))}


def move_gamma(corner):
    board = [[0 for _ in range(4)] for _ in range(4)]
    try:
        for (i, j) in (corner, *positions[corner]):
            board[i][j] = 1
        return board
    except KeyError:
        print("You can't move there!")
        return board


def flip_h(board):
    return [[*reversed(row)] for row in board]


def flip_v(board):
    return [*reversed(board)]


def transpose(board):
    return [[*t] for t in zip(*board)]

Demo:

In [3]: board = move_gamma((1, 1))

In [4]: print(*board, sep="\n")
[0, 0, 0, 0]
[0, 1, 1, 0]
[0, 1, 0, 0]
[0, 1, 0, 0]

In [5]: board = move_gamma((1, 2))

In [6]: print(*board, sep="\n")
[0, 0, 0, 0]
[0, 0, 1, 1]
[0, 0, 1, 0]
[0, 0, 1, 0]

In [7]: print(*transpose(board), sep="\n")
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 1, 1, 1]
[0, 1, 0, 0]

Just a heads up, you'd still need to implement the logic for mapping WASD to movement relative to the current corner indices.

CodePudding user response:

If you need to stay within the confines of the standards library, you can use collection.deque, which has a rotate method that does exactly what you need and will have to implement in lists if you can't use deque.

This is what I can offer with deque.

NB. this wraps around the edges which might not be intended,

from collections import deque

space = deque([
    deque([0, 1, 1, 0]),
    deque([0, 0, 1, 0]),
    deque([0, 0, 1, 0]),
    deque([0, 0, 0, 0]),
    ])

def move(mvt):
    if mvt == "s":
        space.rotate(1)
    elif mvt == "w":
        space.rotate(-1)
    elif mvt == "d":
        [x.rotate(1) for x in space]
    elif mvt == "a":
        [x.rotate(-1) for x in space]
    else:
        raise NotImplementedError

move("d")  # etc

CodePudding user response:

Your answer is in your question - instead of keeping track of all space (array with mostly 0s), use an object (python dict) to instead specify the shape, and where to start drawing it e.g.:

{ 
  'abs_pos': (0,1),
  'rel_points': [(0,0), (0,1), (1,0), (2,0)]
}

Then moving it only amounts to updating the location of (e.g.) the upper-left corner abs_pos.

When it's time to print your map of all space, start from abs_pos and then add a dot at each point in rel_points.

  • Related