Day 19 - Instances, State, and Higher-Order Functions
From Virtual Sketching to Reptilian Races: Mastering Instances, State and Higher-Order Functions through 'Etch-A-Sketch' and 'Turtle Race' Projects
Today's Objective
Today, we took a look into some concepts not touched on yet in this course: Instances, State, and Higher-Order Functions. I'll touch post a quick definition and example of each concept below:
Instances: An instance is a single and unique unit of a class. A class is a blueprint, and an instance is an individual object created from that blueprint. For example, if you have a class
Dog
, you can create an instance ofDog
likemy_dog = Dog()
wheremy_dog
is an instance of the classDog
.State: In Python, state refers to the values of an object's attributes at a given time. For instance, if a
Dog
object has attributes likename
andage
, the combination of these attribute values at any moment constitutes the state of theDog
object. Ifmy_dog
's name is "Fido" and its age is 3, that's the current state ofmy_dog
.Higher-Order Functions: In Python, higher-order functions are functions that can either accept other functions as arguments, return a function as a result, or both. This concept is a key part of functional programming. For example, Python's built-in
map()
function is a higher-order function because it takes a function and an iterable, applies the function to every item in the iterable, and returns a new iterable with the results.
Now these are definitions and examples pulled from the interweb. I will admit I'm not all that well-versed when it comes to state and higher-order functions so I felt that trying to explain them in my own words would not come across clear. With that being said, we can just dive into the two projects for today's lesson: "Etch-A-Sketch" and the "Turtle Race"
Etch-A-Sketch
This project (or I should say challenge) was pretty easy. It mainly focused on incorporating event listeners, which are considered higher-order functions, to listen for the key input and then execute the action (or function) that is bound to that key.
So this was a pretty straightforward challenge and I've added the code below (was only one file):
from turtle import Turtle, Screen
import random
tim = Turtle()
screen = Screen()
def move_forward():
tim.forward(10)
def move_backwards():
tim.back(10)
def counter_clockwise():
tim.left(10)
def clockwise():
tim.right(10)
def clear():
tim.clear()
tim.penup()
tim.home()
tim.pendown()
screen.listen()
screen.onkey(key="d", fun=move_forward)
screen.onkey(key="a", fun=move_backwards)
screen.onkey(key="w", fun=counter_clockwise)
screen.onkey(key="s", fun=clockwise)
screen.onkey(key="c", fun=clear)
screen.exitonclick()
Nothing crazy here to note other than it was a decent re-introduction of the basics of Higher-Order Functions.
The Turtle Race
This project on the other hand was a bit more complicated and took me a little bit of re-reading the Turtle docs and some previous lessons to get through it. The goal was to prompt the user with an input box to guess which turtle they think would win. After the user chooses, the turtles would line up and then begin the race. If you win, you get a message in the terminal saying so and if you lose, you'll get a similar message. The main focus of this project was to understand the use and importance of State and Instances. Since this one only needed one file as well, I'll post the full code but you can still check changes in GitHub as well. Check out the race!
from turtle import Turtle, Screen
import random
screen = Screen()
screen.setup(width=550, height=500)
user_bets = screen.textinput(title="Make your bet!", prompt="Who will win the race? Pick your color: ")
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
y_pos = [100, 50, 0, -50, -100, -150]
all_turtles = []
for turtle_index in range(0, 6):
new_turtle = Turtle(shape="turtle")
new_turtle.color(colors[turtle_index])
new_turtle.penup()
new_turtle.goto(x=-250, y=y_pos[turtle_index])
all_turtles.append(new_turtle)
if user_bets:
race_on = True
while race_on:
for turtle in all_turtles:
if turtle.xcor() > 255:
race_on = False
winning_color = turtle.pencolor()
if winning_color == user_bets:
print(f"You won the race with {winning_color}!")
else:
print(f"You lost the race with {winning_color}!")
rand_distance = random.randint(0, 15)
turtle.forward(rand_distance)
screen.exitonclick()
The second for
loop is where I was tripped up the most because I didn't realize there were two methods for the color of the turtle before. I'm glad that it didn't frustrate me for too long though. For reference on what is considered a current "state", I've singled out which variables and objects are considered to hold a "state". Variables and Objects will be highlighted and state is what it holds:
The
screen
object with its width and height attributes.The
user_bets
variable that holds the user's bet.The
colors
list andy_pos
list.The
all_turtles
list which holds the turtle objects. Each turtle object also has a state, including attributes such as color and position (xcor()
andycor()
).The
race_on
boolean variable that controls whether the race continues or not.The
winning_color
variable which holds the color of the winning turtle when a turtle crosses the specified x-coordinate.Each
turtle
's x-coordinate in thewhile
loop, as it determines whether the race should end.The random distance each turtle moves during each iteration of the
while
loop.
This should be a good reference point to loop back to in the future when it comes to pulling examples.
EOD
And there goes day 19! Yeah, it's super late, but I'm chucking this up anyways - who cares about the 'perfect post time', amirite? lol.