1
\$\begingroup\$

I am a rock climber so I made a rock climbing game. I have two conceptual objects; the climber and the route. I ended up putting them both into a single Climber class, and made route an instance method on the class.

I feel like they should be separate, but I was having problems with inheritance, which is why I merged them.

I've also removed some other code to make this more succinct. My code works but I can't help but think it could be better - any and all feedback is appreciated.

import sys

print ("""We are playing a game today at Ship Rock. All the bros are 
here. Most points wins.""")

class Climber(object):
    def __init__(self, climber_name, ability): 
    self.climber_name = climber_name
    self.ability = ability
    self.routes_climbed = []
    self.energy_level = 100
    self.pump_level = 0
    self.total_score = 0
    self.pitch_count = 0

    def engine(self):
        next_action = input("What next? ")
        if next_action == "climb":
            self.climb_route((str(input("Enter route name: "))), (float(input("Enter route grade: " ))))
        elif next_action == "finish":
            self.grand_finale()

    def climb_route(self, route_name, grade):
        print ("Climbing...", route_name, " Grade...", grade)
        if grade < (.9 * self.ability):
            self.pump_level += (grade * .8)
        elif grade >= (.9 * self.ability):
            self.pump_level += (grade * 1.5)
        self.energy_level -= (grade * 1.7)
        self.total_score += grade
        self.routes_climbed.append(route_name)
        self.pitch_count += 1
        if self.energy_level <= self.pump_level:
            print ("Your day is over.")
            self.grand_finale()
        self.engine()

    def grand_finale(self):
        sys.exit() #quits program

climber1 = Climber("Erich Purpur", 13.0)
climber1.engine()
\$\endgroup\$
  • 1
    \$\begingroup\$ Can you give us some example inputs and outputs so we can see what it would look like? \$\endgroup\$ – Dannnno Mar 12 '18 at 15:25
  • 1
    \$\begingroup\$ Can you also include all code? Here on CR we don't care as much about succinctness, but rather completeness so we can give the most accurate review. \$\endgroup\$ – Dannnno Mar 12 '18 at 15:28
  • \$\begingroup\$ @Dannnno an example input for route name and grade would be "route1" and "10". Thanks for clarifying. \$\endgroup\$ – Erich Purpur Mar 13 '18 at 12:19
1
\$\begingroup\$

I don't know anything about climbing. But I'll try this by way of analogy.

I imagine that climbing routes might be something like ski runs. You can have a resort with multiple mountains. Each mountain can have multiple runs. The runs don't necessarily start at the same place, nor end at the same place. The runs can have different levels of challenge.

So you have:

  • A Resort has m Mountains
  • A Mountain has
    • s starting points (where lifts take you)
    • e ending points (where runs take end, and you can go home)
    • p points
  • A Point has r runs leaving it
  • A Run has a difficulty rating (green circle, blue square, black diamond)

How to approach this in a game? Well, you have some of it already. The pump_level and energy_level are fine.

I would say that the top few items (resort, mountain, starting point) are a series of text prompts. What you really have is a graph. When the player starts, it is at a central node on the graph. This is the "big decision" that will decide the rest of the decisions: "What resort do you want to visit?"

From there, you can change resorts (which is slow and time consuming and expensive, but might be necessary for game play, or might be a "level up" feature- you can only change resorts as you get better). Or you can head for different starting points by taking different ski lifts. Or you could head for a different mountain by taking a van over, then a ski lift. Etc.

Finally, you get to a starting point, pick from a small set of runs. You reach a point at the end if your run, pick from a different small set of runs, reach a different point at the end of that run, etc. Eventually, you reach an ending point - the bottom of the hill. You can call it a day, or go back up for more runs!

I would reverse this for climbing. There are some places to start, maybe some "trails" that take you to the bottoms of a few routes. When you climb up, you reach a point that you can change routes. Then eventually you reach the top, or some other ending point, etc.

Update:

So you have a climber traversing this graph of starting/middle/ending points by various routes. So the nodes (points) have various weighted edges (weights = difficulty, cost, etc.) and they all have names.

Your climber will need some kind of "current node" or "current location" indicator. Your graph of routes should have a common "node" class, with various "routes" connecting the nodes.

class PathNode:
    def __init__(self, ...):
        self.routes = []

class Route:
    def __init__(self, name: string, grade: float, start: PathNode, end: PathNode):
        ...

Whatever your "bottom of the mountain" type is (I called it "Resort" in the ski example) would have a set of standard starting nodes.

class Resort:
    def __init__(self, ...):
        self.start_nodes = []

Your climber would have a current node:

class Climber:
    def __init__(self, ...):
        self.location = None

You might consider making a Resort inherit from PathNode and use a bunch of zero-cost routes to connect to the starting points. That would make everything a graph traversal.

If you put a "message" into each route, describing the struggle, then the Resort -> Start messages could play into that:

You get in a van with a couple of hipsters, and head for the bottom of El Diablo. I wonder if those guys have what it takes to make the climb?"

You might consider adding in some "trap" nodes, that can only be reached by random chance. Thus, if your energy is low and you try to climb a difficult route, maybe you fall off and have to wait for a rescue chopper...

\$\endgroup\$
  • \$\begingroup\$ Thanks @Austin. The skiing analogy is good and is more or less the same. So in your opinion, is my way "wrong"? Because I've basically created one class which encapsulates all other objects, it seems like I have defeated the purpose of classes in the first place. \$\endgroup\$ – Erich Purpur Mar 13 '18 at 12:18
  • \$\begingroup\$ I think you haven't gone far enough yet. Once you start adding in various mountains, routes, etc., it will become impossible to hold everything in a single class, and the data will force the code into a cleaner structure. \$\endgroup\$ – Austin Hastings Mar 13 '18 at 14:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.