Python New to Object Oriented Programming - python

I was wondering how to fix this problem I am having with my first piece of OOP code. The problem lies within the attack method of the Snake class. I have two snakes in the game and am trying to get the snake to attack the other one. At the moment I am using two variables to note which Snake's turn it is, then use this to try and attack the other snake. However this is not working. Anyone have any idea how to solve this? Thank you so much.
class Snake:
hp=100
attack=25
defense=1
def set_name(self, name):
self.name=name
def shed(self):
self.defense=self.defense+1
def attack(self, opposite, current):
opposite.hp=opposite.hp-(current.attack-opposite.defense)
def eat(self):
self.attack=self.attack+5
print(str(self.name) + " eats a rat!")
print(str(self.name) + "'s attack dmg is now " + str(self.attack))
def sleep(self):
print (str(self.name) + " goes to sleep")
self.hp=self.hp+10
if self.hp>100:
self.hp=100
print (str(self.name) + " wakes up with " + str(self.hp) + "hp")
##initialises the snakes
alpha=Snake()
beta=Snake()
## gives the snakes names of the user's choice
alpha_name=raw_input("What would you like to name your snake? ")
alpha.set_name(alpha_name)
beta_name=raw_input("What would you like to name the other snake? ")
beta.set_name(beta_name)
##starts the game
turn=True
while alpha.hp>0 and beta.hp>0:
while turn==True:
opposite="beta"
current="alpha"
action=raw_input("attack, sleep, eat or shed? ")
try:
if action=="attack":
alpha.attack(opposite, current)
if action=="sleep":
alpha.sleep()
if action=="eat":
alpha.eat()
if action=="shed":
alpha.shed()
turn=False
except IOError:
print("Please chose only one action, exaclty how it is typed")
while turn==False:
opposite="alpha"
current="beta"
if beta.hp<15:
beta.sleep()
elif alpha.hp>75:
beta.attack()
else:
index=random.randint(1, 3)
if index==1:
beta.shed()
elif index==2:
beta.eat()
else:
beta.attack(opposite, current)
turn=True

in "attack" you try to access "opposite.hp", but this method is called with a string instead of an object:
opposite="alpha"
current="beta"
=> change this to
opposite=alpha
current=beta
also, there is a field and a method with the same name in the class: attack. I suggest renaming the field to "attackpoints" or something.
additionaly, you call "beta.attack()". you forgot the method arguments there.

I see two problems. The first is you're passing the name of the variable instead of the variable itself.
change this:
while alpha.hp>0 and beta.hp>0:
while turn==True:
opposite="beta"
current="alpha"
action=raw_input("attack, sleep, eat or shed? ")
try:
if action=="attack":
alpha.attack(opposite, current)
to this:
while alpha.hp>0 and beta.hp>0:
while turn==True:
opposite=beta
current=alpha
action=raw_input("attack, sleep, eat or shed? ")
try:
if action=="attack":
alpha.attack(opposite, current)
Additionally, you have the attack field defined twice in the Snake class.
class Snake:
attack=25
def attack(self, opposite, current):
Here's what I came up with after playing with your code:
import random
class Snake:
hp=100
attack_skill=25
defense=1
def set_name(self, name):
self.name=name
def shed(self):
self.defense=self.defense+1
def attack(self, opposite):
opposite.hp = opposite.hp - (self.attack_skill - opposite.defense)
def eat(self):
self.attack_skill += 5
print(str(self.name) + " eats a rat!")
print(str(self.name) + "'s attack dmg is now " + str(self.attack_skill))
def sleep(self):
print (str(self.name) + " goes to sleep")
self.hp=self.hp+10
if self.hp>100:
self.hp=100
print (str(self.name) + " wakes up with " + str(self.hp) + "hp")
##initialises the snakes
alpha=Snake()
beta=Snake()
## gives the snakes names of the user's choice
alpha_name=raw_input("What would you like to name your snake? ")
alpha.set_name(alpha_name)
beta_name=raw_input("What would you like to name the other snake? ")
beta.set_name(beta_name)
##starts the game
turn=True
while alpha.hp>0 and beta.hp>0:
while turn==True:
opposite="beta"
current="alpha"
action=raw_input("attack, sleep, eat or shed? ")
try:
if action=="attack":
alpha.attack(beta)
if action=="sleep":
alpha.sleep()
if action=="eat":
alpha.eat()
if action=="shed":
alpha.shed()
turn=False
except IOError:
print("Please chose only one action, exaclty how it is typed")
while turn==False:
opposite="alpha"
current="beta"
if beta.hp<15:
beta.sleep()
elif alpha.hp>75:
beta.attack(alpha)
else:
index=random.randint(1, 3)
if index==1:
beta.shed()
elif index==2:
beta.eat()
else:
beta.attack(alpha)
turn=True

When you beta attack, you are calling the attack() method without any parameters. I assume you want beta.attack(alpha,beta)
But you could probably refactor the method to only require the opponent as a parameter (since you know who is attacking (it's the object calling the attack method))
def attack(self, opposite):
opposite.hp -= self.attack-opposite.defense

Related

How to take away health points when using a class?

I'm working on a game in python and I can't figure out how to take away health once attack function has taken place. I can run the program and the attack function works fine, it shows a random integer between 1 and 50 but doesn't actually take away health from castlehealth = 100
Underneath print("You attacked for " + str(self.attack)) I left the next line blank because I don't know what to type in, I tried a lot of different things and just can't get the attack to take away from castlehealth.
Here is my code:
import os
import time
from random import randint
class GameActions:
def __init__(self):
castlehealth = 100
self.castlehealth = castlehealth
def health(self):
print("Castle health is: " + str(self.castlehealth))
print()
def attack(self):
attack = randint(0, 50)
self.attack = attack
print("You attacked for " + str(self.attack))
def game():
while True:
game_actions = GameActions()
print("What do you want to do?")
print()
print("attack, view hp")
ans = input()
if ans == "hp":
game_actions.health()
if ans == "attack":
game_actions.attack()
You want the following:
self.castlehealth -= attack
Try something like self.castlehealth -= attack. I also fixed some potential indentation issues for you.
Your full code sample could look this this:
import os
import time
from random import randint
class GameActions:
def __init__(self):
castlehealth = 100
self.castlehealth = castlehealth
def health(self):
print("Castle health is: " + str(self.castlehealth))
print()
def attack(self):
attack = randint(0, 50)
self.attack = attack
print("You attacked for " + str(self.attack))
self.castlehealth -= attack
def game():
while True:
game_actions = GameActions()
print("What do you want to do?")
print()
print("attack, view hp")
ans = input()
if ans == "hp":
game_actions.health()
if ans == "attack":
game_actions.attack()
Explanation: self.castlehealth is an instance variable of your GameActions class. The function GameActions.attack() creates a new attack variable as a random integer and then subtracts that value from the instance variable self.castlehealth of the GameActions class. Now self.castlehealth will be the updated value. Consider also tracking the various attacks and resulting healths in a data structure, since every time you have a new attack self.castlehealth and self.attack will change values and you will lose the ability to access the previous values.

Call a class function in a self in another function so that the attributes only include one and the variable not included but is self function?

This code is in the main function:
Player and Computer are lists in this format:
player = ["name", 10, 20, 30]
10 is the health, 20 is the strength, and 30 is the dexterity
# Get the character for the user and the computer.
player = character_choices.get_and_remove_character(choice)
computer = character_choices.get_random_character()
# Preparation for the battle
print ("You have picked a " + player.name)
print ("The computer picked " + computer.name)
print ("Let's battle!\n")
# Battle Loop
rnd = 1
while (player.hit_points > 0 and computer.hit_points > 0):
print ("Round: " + str(rnd))
player.attack (computer)
computer.attack (player)
This is the function:
def attack (self, enemy):
self.player = [self]
if self.player[3] == enemy[3]:
I do not know how to call the player variable within the attack function in this format I can not change the attributes and I do not know how to get the player list items to compare to the enemies list items and fight.
self is a variable commonly related to objects in python by convention.
In your case, to make use of self, you should read up on python object oriented programming.
https://realpython.com/python3-object-oriented-programming/
Go through the tutorial in the link and once you are done, you will have a better understanding of what you want to achieve using your code. Have fun!

Yahtzee, using a dictionary instead of list of attributes

So my issue is that currently I have code for my yahtzee (I will not post all of the code, but the important stuff is looking like this (and it works):
from terminaltables import AsciiTable
class Player:
def __init__(self,name):
self.name=name
self.ones=0
self.twos=0
self.threes=0
self.fours=0
self.fives=0
self.sixs=0
self.abovesum=0
self.bonus=0
self.onepair=0
self.twopair=0
self.threepair=0
self.fourpair=0
self.smalladder=0
self.bigladder=0
self.house=0
self.chance=0
self.yatzy=0
self.totalsum=0
def welcome():
global spelarlista
spelarlista=[]
print("Welcome to the yahtzee game!")
players = int(input("How many players: "))
rounds=0
while not players==rounds:
player=input("What is your name?: ")
rounds=rounds+1
spelarlista.append(Player(player))
table_data = [["Name"] + spelarlista,
['Ones'] + [player.ones for player in spelarlista],
['Twos'] + [player.twos for player in spelarlista],
['Threes'] + [player.threes for player in spelarlista],
['Fours'] + [player.fours for player in spelarlista],
['Fives'] + [player.fives for player in spelarlista],
['Sixs'] + [player.sixs for player in spelarlista]]
table = AsciiTable(table_data)
table.inner_row_border = True
print(table.table)
spelarlista[0].add()
welcome()
The issue right now is that I want to add a dictionary instead of all those self.ones, self.twos etc. If you take a look at my welcome method, you can see that I have [player.ones for player in spelarlista]and I need this to assign the players points, how can I fix so this work for a dictionary instead? The dictionary is neccesary for my next method, add, if you were curious!
Thanks in advance!
dict_names = ['ones', 'twos', ..., 'totalsum']
self.dict = {name:0 for name in dict_names}
and to access you'd use player.dict['fours'] instead if player.fours

Adding a combat system to a text adventure game; confused by the structure of the code I'm using

Through some educational materials I've been tasked to use the below structure (the classes) for a text adventure game and am required to add a simple combat system for battle between a hero and an enemy.
Currently I am able to have an enemy created in each room and move between the start room(corridor) to the bathroom and back, but at this point I'm stuck. I can't determine where I should be creating my 'hero' or how I'd communicate the changes I'd need to make to the health attributes etc.
If I could structure the code in another way, I would be able to complete the game, but as it is there is a gap in my understanding of how to enable various sections of code communicate with each other.
Thanks,
Dave
# text based adventure game
import random
import time
from sys import exit
class Game(object):
def __init__(self, room_map):
self.room_map = room_map
def play(self):
current_room = self.room_map.opening_room()
while True:
next_room_name = current_room.enter()
current_room = self.room_map.next_room(next_room_name)
class Character(object):
def __init__(self, name, health, attack):
self.name = name
self.health = health
self.attack = attack
class Hero(Character):
def __init__(self, name):
super(Hero, self).__init__(name, 10, 2)
def __str__(self):
rep = "You, " + self.name + ", have " + str(self.health) + " health and " + \
str(self.attack) + " attack."
return rep
class Enemy(Character):
ENEMIES = ["Troll", "Witch", "Ogre", "Jeremy Corbyn"]
def __init__(self):
super(Enemy, self).__init__(random.choice(self.ENEMIES),
random.randint(4, 6), random.randint(2, 4))
def __str__(self):
rep = "The " + self.name + " has " + str(self.health) + \
" health, and " + str(self.attack) + " attack."
return rep
class Room(object):
def __init__(self):
self.commands = ["yes", "no"]
self.rooms = ["\'corridor\'", "\'bathroom\'", "\'bedroom\'"]
self.enemy = Enemy()
def command_list(self):
print("Commands: ", ", ".join(self.commands))
def enter_room_question(self):
print("Which room would you like to enter?")
print("Rooms:", ", ".join(self.rooms))
def leave_room_question(self):
print("Do you want to leave this room?")
print("Commands:", ", ".join(self.commands))
class Bathroom(Room):
def enter(self):
print("You enter the bathroom. But, wait! There is an", \
self.enemy.name, "!")
print(self.enemy)
print("You are in the bathroom. Need to take a dump? ")
self.command_list()
response = input("> ")
while response not in self.commands:
print("Sorry I didn't recognise that answer")
print("You are in the bathroom. Need to take a dump?")
self.command_list()
response = input("> ")
if response == "yes":
print("Not while I'm here!")
return "death"
elif response == "no":
print("Good.")
self.leave_room_question()
response = input("> ")
if response == "yes":
return "corridor"
else:
return "death"
class Bedroom(Room):
def enter(self):
pass
class Landing(Room):
def enter(self):
pass
class Corridor(Room):
def enter(self):
print("You are standing in the corridor. There are two rooms available to enter.")
self.enter_room_question()
response = input("> ")
if response == "corridor":
print("You're already here silly.")
else:
return response
class Death(Room):
QUIPS = ["Off to the man in sky. You are dead",
"You died, no-one cried.",
"Lolz. You're dead!"]
def enter(self):
time.sleep(1)
print(random.choice(Death.QUIPS))
exit()
class Map(object):
ROOMS = {"corridor": Corridor(),
"bathroom": Bathroom(),
"death": Death(),
"landing": Landing(),
"bedroom": Bedroom()}
def __init__(self, start_room):
self.start_room = start_room
self.hero = hero
def next_room(self, room_name):
return Map.ROOMS.get(room_name)
def opening_room(self):
return self.next_room(self.start_room)
a_hero = Hero("Dave")
a_map = Map("corridor")
a_game = Game(a_map, a_hero)
a_game.play()
If I were you, I would set out a game schema. You could find out asking yourself questions like this:
What are the really important entities?
In your case, as you have done, I would consider Character, Enemy, Room and Map, inheriting when it would be appropiate, like Character-> Hero and Enemy, and several types of room from Room as Bathroom, Corridor, ...
If I were you a consider using a data structure to represent the Map. For example, if you are considering do a text game adventure, you could think in different rooms as different states in your game. If you are in the bathroom, you could be attacked by an enemy and if you are in the bedroom, you can retrieve your hitpoints (life) so these places can be thought as different states.
As an example, you would an array for group all your different rooms (states)
rooms = ["bedroom", "bathroom", "corridor", "kitchen", "living_room"]
and other rooms that you can think about.
(there is probably a better example, more efficient and so on, so this example is to help you about not giving up when you gets stuck about an problem.
According to this example, if you use an array, you can assign a value to each room (equal to each position in the array)
Moreover, you will need to know the hero's position, so you could assign a random value to it using rand(). You can read links below for more information:
random docs python
stackoverflow answer
At last, you also would find useful to compare the hero's position, which would have a random assigned value previously with every position of your array or rooms
In this cases, you could use a if... elif.. elif... to compare those values and do something according to the room where your hero would be.
I hope this answer will be useful for you.
Let me know if you have any doubt about my answer.
Cheers

giving turns for attacks in mini game (python 2.7)

I've been learning python and I was creating a mini-game and did good so far. I need ideas to give each player a turn to attack, First here is the code:
from random import randint
class Dragon:
def __init__(self,name,health):
self.name = name
self.health = health
def kill(self,target):
while target.health >= 0:
if target.health <= 50:
hit = randint(1,20)
target.health -= hit
print '%s hits %s for %s' %(self.name,target.name,hit)
elif target.health <= 0:
print '%s has killed %s' %(self.name,target.name)
else:
hit = randint(1,50)
if hit >= 40:
target.health -= hit
print "%s critically hits %s for %s" %(self.name,target.name,hit)
else:
target.health -= hit
print "%s hits %s for %s" %(self.name,target.name, hit)
def Dead(self):
if self.health <= 0:
print "%s is dead" %self.name
class Hero:
def __init__(self,name,health):
self.name = name
self.health = health
Diet = Dragon('Diet',200)
Pizza = Hero('Pizza', 100)
if __name__ == '__main__':
Diet.kill(Pizza)
I will add more methods to the hero class once I figure out how to give turns to each player and my second problem is that the block that prints out the death of a player is not working, I've tried to nest it under each if function and it worked. But I think I shouldn't repeat the same code over and over and there must be a better way to do it.
Take the kill method out of a while loop, make it so each time the method is called it is just a single attack, rather than going till the other person is dead.
Then stick the entire game in a while loop, with some sentinel value for the end condition, e.g.:
GameIsRunning = True
while GameIsRunning:
#heros action
#enemies action
if EndConditionIsMet():
GameIsRunning = False
At the end of each loop check if the game is over, e.g. if all enemies are dead or the hero is dead, and set GameIsRunning to false.
Edit:
Dead option 1
As is, the Dead method just prints a message. You can't use this for much other than showing the user that so-and-so is dead. But if you want it like this, call it somewhere in either the attackers kill method. Or in the game loop. If you want this to get automatically called when the instance dies, then I would wrap up any damage dealing in a method:
def DealDamage(self, damage):
self.health -= damage
self.Dead()
Then use
def Kill(self, target):
#damage picking logic stays the same
target.DealDamage(damage)
Dead option 2
If you want said Dead method to mean that thing do or don't happen, it ought to have a boolean signature, e.g.:
def IsDead(self):
# Stick in a display message here if you like, or let the game do it
if self.health <= 0:
return True
else:
return False
Then you can let the game decide what to do about the fact that this person is dead. If you want to start adding multiple enemies then (as most games ultimately will), you might consider sticking them in a collection (a list or a dictionary), looping through this to take each enemies' turn if they're still alive, and removing them if they're dead. Then you're end condition can just be
if Hero.IsDead() or len(Enemies) == 0:
return True
This way gives you an easy way to spawn more enemies mid-game as well.

Categories

Resources