In this lab, you will be designing autonomous “animals” (called critters) that will compete in a simulation. You’ll be programming how they move and fight with each other. Often, the behavior of your critters will be repetitive: they’ll move north and then east, or in circles, or attack according to some pattern. In this exercise, you’ll design some data structures that will help you implement this behavior easily.
Your task is to program the Repeater
class. A Repeater
will store a sequence of values, and whenever asked, will return the next value in the sequence. When it gets to the end of its sequence, it loops back to the beginning and starts over. In other words, a Repeater
object has two attributes:
self.sequence
contains the list of values that the Repeater
will go throughself.current
contains the index of the element that the Repeater
will return next time it is asked (this should start at 0)A Repeater
object has one method, next()
, which returns the element of self.sequence
at index self.current
. If self.sequence
is the empty list, next()
should return None
. When self.current
reaches len(self.sequence)
, self.current
should be reset to 0. Otherwise, self.current
should increment every time next()
is called. You can do this with the %
operator or with a conditional statement. Be careful to make sure that you increment only after accessing the element to return - if you don’t, you could miss the first element of the sequence!
Finally, the constructor for a Repeater
object takes in one parameter seq
, so that the user can specify what they would like the sequence to be.
repeater.py
, implement the Repeater
interface.next()
enough times to go back to the beginning of self.sequence
.Now it’s time to practice with inheritance. You’re going to program a subclass of Repeater
, which we’ll call OppositeRepeater
. An OppositeRepeater
will have the same methods and attributes as a Repeater
.
The only thing that will be different in OppositeRepeater
is the constructor (__init__
method). An OppositeRepeater
instance should move backwards through the list of values provided, starting at the last element and moving to the element before until the first element, and then looping back around. How can you modify the inputed list of elements to __init__
such that when you call next()
from the Repeater
class (which moves forward in self.sequence
) it goes in the opposite order? (Hint: think about reversing seq
!).
opposite_repeater.py
, implement the OppositeRepeater
class. Remember all you should do is add code for __init__
. Think about how you can use inheritance to gain access to the next()
method from the Repeater
class. Then, assuming that next()
will move forward in self.sequence
, how can you set the value of self.sequence
accordingly.Repeater
class.Repeaters and OppositeRepeaters will be helpful for several of the critters you construct on the latter portions of this lab. However, one animal (the Tiger
) will benefit from having a slightly more sophisticated movement class. Let’s now design a new subclass of Repeater
, called FancyRepeater
, that will allow us to move in a random direction for a given number of steps before picking a new random direction to move.
As with all subclasses of Repeater
, FancyRepeater
will have self.sequence
, self.current
, and a next()
method. Our new subclass will have two additional attributes: self.period
and self.elt
(short for “element”). The constructor for FancyRepeater
should take the parameter seq
as before, but also optionally take a second argument, period
. On construction, self.elt
is assigned to a randomly selected value from self.sequence.
We would suggest using the random
module and in particular the method random.choice
. (Note that the default value for period
can be whatever you like; by default we set period
to be 1 in the interface).
Each call to next()
should have the following behavior:
next()
has been called for the current direction is less than or equal to self.period
, then return the current direction of self.elt
.self.sequence
to be self.elt
, and returns this new direction.The attribute self.current
should keep track of how many calls since you last switched self.elt
. So the code
fr = FancyRepeater(["a","b","c"], 4)
for i in range(13):
print(fr.current,fr.next())
might produce the output below.
0 a
1 a
2 a
3 a
0 b
1 b
2 b
3 b
0 a
1 a
2 a
3 a
0 c
Your tasks are the following:
fancy_repeater.py
, implement the FancyRepeater
classReadMe
Feel free to make use of Repeater
, OppositeRepeater
, and/or FancyRepeater
when completing the lab itself. However, if you run into issues or bugs with your implementations—don’t worry! You can complete the lab without relying on these classes.