# VARIABLES
# we can store data in memory using variables
a = 1
b = 2
print("a =", a)
print("b =", b)


# DATA TYPES
# these are some of the common types of data we can store in memory
a = 5
print(a, "is an integer")
b = 3.14
print(b, "is a float")
c = "hello"
print(c, "is a string")
d = True
print(d, "is a boolean")


# OPERATORS
# operators allow us to do computational work with our data
a = 3
b = 5
# we can save that work we do into new variables so we can use them later
c = a + b  # addition
d = a - b  # subtraction
e = b * a  # multiplication
f = b / a  # division
print("a =", a)
print("b =", b)
print("a + b =", c)
print("a - b =", d)
print("b * a =", e)
print("b / a =", f)

# we can also use the addition operator to concatenate (put together) strings
first_name = "Nate"
last_name = "Page"
# here we concatenate the first and last name together with
# a space in the middle and save the result to a variable called `full_name`
full_name = first_name + " " + last_name
print(first_name)
print(last_name)
print(full_name)


# CONDITIONALS
# we use conditionals to check the truthiness of something
# (e.g. is this statement true or false)
a = 1
b = 2
c = 3

x = a == b
print(a, "=", b, "is", x)

y = a < b
print(a, "<", b, "is", y)

z = (a + b) == c
print(a, "+", b, "=", c, "is", z)


# FLOW CONTROL
# we use conditionals in conjunction with if else statements to control the
# "flow" of the code
money = 30
cost = 50

if money >= cost:
    print("You can buy it!")
else:
    print("You're broke!")
counter = 0


# LOOPS
# loops are useful for when we want to do some action multiple times without
# having to manually write the code to do so
print(counter)
while counter < 15:
    counter = counter + 1
    print(counter)


# LISTS
# lists are how we can store ordered sets of data
nums = [0, 1, 2, 3, 4]
print(nums)
# we can access the slots in a list via "indexing" or giving the numerical
# position of the item we want out of the list
a = nums[0]
print(a)
print(nums[0])
print(nums[1])
print(nums[2])
print(nums[3])
print(nums[4])

# we can also add to our list with the append method
nums.append(5)
print(nums)

# we can remove items with the pop method
a = nums.pop()
print(a)
print(nums)

# we can also update the data in a certain position with indexing
nums[2] = 6
print(nums)


# FOR LOOPS
# for loops are a more specific kind of loop for running a code block for
# each item in a list or for each number in a series
nums = [0, 1, 2, 3, 4]

# this takes each item in the list `nums` and assigns it to the variable `i`
# then it runs all of the code inside the for loop for each value of `i`
for i in nums:
    print(i)


for i in nums:
    print(i * 2)

doubled = []
for i in nums:
    doubled.append(i * 2)

print(doubled)

# the range function is a built in function that returns a list of numbers
# we can use that list of numbers in a for loop (range(5) = [0, 1, 2, 3, 4])
for i in range(5):
    print(i)


# FUNCTIONS
# functions are ways we can name chunks of code for calling later
def say_hello():
    print("Good day gentlemen!")
    print("My name is Sir Gunther III.")
    print("It's a pleasure to make your acquaintance.")
    print()

# we can call a function like this to run our code without having to rewrite it
say_hello()
say_hello()


# FUNCTION PARAMETERS
# we can also define parameters to give our functions
# they allow us to change how our function runs by providing different inputs
def greet_patron(patron_name):
    print("Hello " + patron_name + ", welcome to our shop!")


greet_patron("Norman")
greet_patron("Nate")

names = [
    "Billy",
    "Bob",
    "Joe",
    "John",
    "Jacob",
    "Joseph",
]


for name in names:
    greet_patron(name)


# RETURN VALUES
# to make functions more useful, we can return data from the function
# as a result that we can do things with
# (this may remind you of math where we say f(x) = y; where f is the
# function, x is the input or parameter, and y is the result or return value)
def add(a, b):
    c = a + b
    return c


result = add(15, 23)
print(result)
