1

In python, I am really confused right now regarding how to apply rows and cols(edit: lists) in order to create this piece. I'm creating a class Piece, this has the four values (left, right, up, and down) and generate at random (with randint(10, 99)). I also want to be able to turn the piece for example:

piece after 0 turns :

   30
83 00 34
   25

piece after 1 turns :

   83
25 00 30
   34

2 Answers2

0

If I understand correctly, I wouldn't worry about rows and columns. My class would generate random values in its constructor method (__init__) to stick in a list (vals = [top, right, bottom, left]) and would have two methods for rotating left and right (rotate_left and rotate_right) and one method for getting the current list back (get_vals).

import random as rn

class Piece():

    def __init__(self):
        #vals = [top, right, bottom, left]        
        self.vals = [rn.randint(10,99) for _ in range(4)]
        self.n = 4

    def rotate_left(self):
        self.vals = [self.vals[i-self.n+1] for i in range(self.n)]

    def rotate_right(self):
        self.vals = [self.vals[i-1] for i in range(self.n)]

    def get_vals(self):
        return self.vals

Rotating with this list is simply shifting the values left or right by one index.

Edit: This is written with python 3.4 but it works with 2.7 too.

wrkyle
  • 529
  • 1
  • 13
  • 36
  • This was a fun little distraction, thanks for posting the problem! Let me know if I missed anything. – wrkyle Feb 21 '16 at 06:14
  • thanks for answering. this looks good to me, it prints out the random values for top, left , right, bottom. im still trying to figure out how to format the values so that it looks sort of like the example i showed – Orlando Davila Feb 21 '16 at 06:31
  • I'm glad. Could you accept my solution so the question is marked as answered by clicking the check mark beside it? – wrkyle Feb 21 '16 at 06:33
  • Oops, I had a problem in my `rotate_right` method. It's fixed now. – wrkyle Feb 21 '16 at 06:39
0

I have a similar implementation - except using generators and itertools.

What @wrkyle is doing is that he is replacing the values by constructing new lists. Imagine if you would like to rotate 1000000000 times. You'd have to construct a new list 1000000000 times. It's not very memory efficient.

For scalability, I propose that we generate an infinite sequence and just call the values as needed. I designed the rotate method so that it takes in an argument for the number of turns; this way the user does not have use any loops to cycle through the pieces - just calculate how many positions are to be shifted, and update the values once.

from itertools import cycle, islice
from random import randint

class Piece:

    def __init__(self):
        self._values = cycle([randint(10, 99) for _ in range(4)])
        self._turns = 0

    def __str__(self):
        positions = list(islice(self._values, 0, 4))
        disp = (
            "piece after %s turns:" % (self._turns) + "\n\n" +
            "   %s   \n" % (positions[0]) +
            "%s 00 %s\n" % (positions[3], positions[1]) +
            "   %s   \n" % (positions[2])
        )
        return disp

    def rotate(self, num_turns, direction="right"):
        self._turns += num_turns
        if direction == "right":
            self._values = cycle(islice(self._values,
                                        2 + num_turns % 4,
                                        6 + num_turns % 4)
                                 )
        else:
            self._values = cycle(islice(self._values,
                                        0 + num_turns % 4,
                                        4 + num_turns % 4)
                                 )

Now if you run the following code, by rotating right -

p = Piece()

# rotate 4 times
for _ in range(4 + 1):
    print(p)
    p.rotate(1, direction="right")

You get:

piece after 0 turns:

   57   
86 00 89
   14   

piece after 1 turns:

   86   
14 00 57
   89   

piece after 2 turns:

   14   
89 00 86
   57   

piece after 3 turns:

   89   
57 00 14
   86   

piece after 4 turns:  # confirm it returns to original position

   57   
86 00 89
   14 

Of course, you can change the default argument of the rotate method to "left" so that it rotates left.

Eddo Hintoso
  • 1,442
  • 14
  • 22
  • Though I'm not exactly sure how efficient it is to loop the `next()`s like that. Theoretically, with a really huge `n = 10 ** 9` or something, this is far from optimized. It might be better off that you just slice it and cycle again, like: `x = cycle(islice(x, 0 + num_turns, 4 + num_turns))` – Eddo Hintoso Feb 21 '16 at 06:58
  • Hmm, I like the `__str__` method you used. I'd forgotten that was a thing. – wrkyle Feb 21 '16 at 06:59
  • 1
    Yep, turns out it's better to just make an infinite sequence again and cycle it through after `islic`-ing it. I've edited my implementation. Also, @wrkyle - it happens to the best of us. I'm a little salty you beat me by a few minutes to get best answer but kudos to you! – Eddo Hintoso Feb 21 '16 at 07:11