When to use classes and when to use functions?

I’ve started making my own game in exercise 43.

I’m trying to make a dating game where the player is thrown into different awkward dating scenario he\she needs to solve to be able to get a boyfriend/girlfriend.

I realised I don’t really know when I should use a class or a function.
I’ve tried to google it and think I read somewhere that a class is simply a grouping of functions.
But I guess a function can also nest functions?
I know thats classes are a blueprint to make instances out of whereas functions does things.

The first bit of my game is I’ve made the ‘opening scene’ which is a class called ‘Phone’ that lets you swipe left or right until you find a matching partner.

However I’m not entirely clear why I made a class called Phone instead of a function called Phone?
It just seems to work.
I think I’m confused when classes are used as ‘navigation’ as it seems to me that it could also be done with functions.

Is there something I’ve missed?

#import pdb; pdb.set_trace()

from random import randint
import random
from textwrap import dedent

def Person_generator():
#Randomly choose a name for a swipe.
    names_dic = {
    1 : 'Mary',
    2 : 'Rosalie',
    3 : 'Madeleine',
    4 : 'Jamie'
    name = names_dic[randint(1,len(names_dic))]

    age = randint(25,45)

    match = random.choice([True,False])

    return name, age, match

#generating a date
class Phone(object):

    def __init__(self, like, name=None, age=None):
        self.like = like
        self.name = name
        self.age = age

        match = False

        You're staring at your phone screen waiting for Tinder 🔥 to load.
        The first person slides onto your screen.
        What do you think is she a match?
        Do you want to swipe right ('R') or left ('L')

        while self.like != True or match != True:

            self.name, age, match = Person_generator()

            print(f'Screen:\nName: {self.name}\nAge: {self.age}\nMatch: {match}')

            choice = input(dedent('[Swipe L/R]')).upper()

            if choice == 'R':
                self.like = True
            elif choice == 'L':
                self.like = False
                print(dedent("You're not swiping"))

        print(dedent('🥁🥁there is a match🥁🥁'))

date = Phone(False)

print(f'You got matched with\nDatename: {date.name}\nDateage: {date.age}')

Hi. The easiest way to think about OOP is representing real world things and their actions. It’s kind of the idea behind it really.

Classes are the things like nouns and functions/methods are doing things like verbs.

So you can have a class of Phone (the object) that has functions to open app, play dating game, send stalking email, etc.

I can see the confusion but in Zeds game the rooms are not navigation, they are objects. The game engine navigates between them.

One recommendation on your own game, keep it simple at this stage. I think we all put loads of text in, and tried scoring engines, or weapons points systems that didn’t actually add to the learning, but made the game really hard to debug when it broke.

Good luck.

A good way to break down the confusion is go to the “is-a” and “has-a” exercise, and also throw in “uses-a”. You can then do this:

Person has-a Phone.
Person uses-a Phone to call Person.

Which translates like:

class Phone:
   def call(self, other_person):

class Person:
    def match(self, other_person):

Now, here’s the interesting thing: Do you really need a phone? Don’t two people have two phones? I would just get rid of phone and use a method that lets them talk to each other. The phone is kind of unnecessary unless you plan to allow some kind of extensive phone features or maybe have it as a central component.

Thanks @gpkesley and @zedshaw

I’m not entirely sure I understand at @zedshaw example?

I’m a little stuck on this exercise.
I agree with @gpkesley point that I can expand my own game with all sorts of bells and whistles, but probably not going to enhance my learning even though it’s tempting. Especially if im stuck on what Zed tried to explain above.

What I done sofar

#import pdb; pdb.set_trace()

from random import randint
import random
from textwrap import dedent
from sys import exit

class Scene(object):
    def enter(self):

class Start(Scene):
    def enter(self):
        return 'middle'

class Middle(Scene):
    def enter(self):
        return 'almost_finished'

class Almost_finised(Scene):
     def enter(self):
         return 'finish'

class Finish(Scene):
    def enter(self):

class Map(object):

    scene_list= {
    'start' : Start(),
    'middle' : Middle(),
    'almost_finished' : Almost_finised(),
    'finish' : Finish()


    def __init__(self, start):

        #Is set to 'phone' in the beginning
        self.start = start

    def opening_scene(self):
        #start = 'phone'
        return self.next_scene(self.start)

    def next_scene(self, scene_name):
        self.scene_name = scene_name

        scene_select = Map.scene_list.get(scene_name)
        return scene_select

class Game_Engine(object):
    def __init__(self, scene_map):
        #is set to map1 that is-a Map
        self.scene_map = scene_map

    #the function that starts the game
    def play(self):
        #These Map methods can be called because scene_map is a Map instance (map1)
        #Sets current_scene to opening_scene in Map.

        current_scene = self.scene_map.opening_scene() # = Phone()
        last_scene = self.scene_map.next_scene('finish') # = Finish()

        while current_scene != last_scene:

            #will return a name for the next scene
            next_scene_name = current_scene.enter()
            current_scene = self.scene_map.next_scene(next_scene_name)

        print("game is over")

class Person():
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.stamina = 100

def DateGen():
    name_list = {
    1 : 'Avah',
    2 : 'Raina',
    3 : 'Giovanna',
    4 : 'Nala',
    5 : 'Ayla',
    6 : 'Marlee',
    7 : 'Vivian',
    8 : 'Patricia'

    date_interested = False
    player_interested = False

    while player_interested == False or date_interested == False:
        name = name_list[randint(1, len(name_list))]
        date_interested = random.choice([True, False])
        age = randint(25,34)

        print(f'Date profile\nName: {name}\nAge:{age}\nInterested: {date_interested}\n')

        choice = input("'R' for like\n'L' for no thank you\n[Swipe]").upper()

        if choice == 'R':
            player_interested = True
        elif choice == 'L':
            player_interested = False
            print("If you can't swipe you're too old")

    print("you got matched")

    return name, age

gen_name, gen_age = DateGen()
date = Person(gen_name, gen_age)

#makes an instance of Map called game_map and sets start to 'phone'
map1 = Map('start')

#makes an instance of Game_Engine that is-a map1
game1 = Game_Engine(map1)

It’s pretty simple first I have a date generator function (Date_gen) that generates match. I’m using the return as parameters when I generate an instance of the Person class.

After that is the game uses Zed’s engine to loop through different scenes which I’ve left clear.

Sofar I’ve recreated the game from the book - I understand how the navigation works, however I’m lying if I say I can recreate it from scratch without looking at Zed’s example. But I don’t know if that’s the point? Or is it’s worth just building out my own game? going to next exercise? or if anyone has any suggestions what I can do to my own game to drill this exercise more?

1 Like

I spent weeks on that exercise and I know I couldn’t recreate Zed’s code either. But what I can do is make something that functions in a similar manner and has different parts to a game sequence in it because I spent so much time learning what his code did.
Sometimes, now I know this doesn’t work for everyone, going off into your own version, something you can really sink your teeth into, can help you learn more in depth than trying to relate to someone else’s vision for a concept.

If you really want to do the phone/dating app, take the bits you understand and start going for it. Dive in and go for it. Modify things into words that you understand.
if changing the name of ‘Scenes’ to ‘Date_night’ or something that fits your story helps, go for it.

It’s about learning, do what you want to do. Try things, break things, and have fun.

1 Like

That’s a good start. Keep it simple and work out the structure. Now, I have a couple questions for you on how you’re approaching this:

  1. Are you first designing the whole game without code before you try to write it?
  2. Are you gradually translating your design into code, starting with comments, then psuedo code, then python?
  3. Are you obsessively running your code to make sure it keeps working as you code?
  4. Are you implementing the structure, confirming that it matches your #1 work, and then filling in the structure?

Here’s my answers:

  1. I designed the game entirely on paper before I did any coding. I drew out a map, ideas of monsters, names of things, then I did a full writeup of what the game would do. From the writeup and the paper notes I compiled a list of important Nouns mentioned in the design. These nouns became my classes. The map became my connections between the classes that made up rooms. This is all mentioned in the book on doing an OOP design.
  2. My first batch of code was JUST the Room classes, nothing in them at all. Then the Map that put them together. Then the Engine that ran the Map. Then I filled in the classes for rooms with what they did.
  3. I run my program about once ever 1-10 lines of code, usually when I have some small chunk written that could run I try to run it and confirm it runs and works.
  4. I do the classes, work out just their names, then subclasses, then how they’re connected, then how the Map works, then how the Engine works, then fill in each Room and confirm it keeps working. This is only possible because I spent a lot of time in #1.
1 Like

Thank you @nellietobey for the encouragement.
It’s good to be reminded that I’m travelling a well worn path.
I’ll go back to my game again.

Hi @zedshaw
I did design my game on paper, but then left the details out what should happen in each room as I thought it was more about learning about the game engine…
You’re right, I went top down instead of bottom up.
I’ll get back to my colouring pens and likely be back here again in a few days.

Also I want to say I’m not sure if I have ever gotten so much value for my money then when I purcased LPTHW and then connecting with everyone on this forum. I’m not sure how you have the energy to probably answer the same questions over and over again. But thank you.

It is said a lot, but it’s very true:

Programming is more thinking than coding.

I spend a lot of time thinking about what to write before I do write it. If I am “hacking” it’s an interactive thinking with code, but usually I’ve done some kind of research first and I’m just testing out the idea I’ve got from a lot of research, planning, and thinking.

Usually if I didn’t do any planning and I’m just hacking live on an idea, I end up throwing that code out as it’s really my research.

So, spend a lot more time planning, or plan on throwing out your trash code since it was just for planning. :wink:

1 Like