def destroy_piece(self, piece):
""" Removes piece from the canvans and click-handler
automatily called by move_piece
"""
img1=piece.get_img_int(0)
img2=piece.get_img_int(1)
del self._on_clicks[str(img1)]
del self._on_clicks[str(img2)]
self.delete(piece.get_img_int(0))
self.delete(piece.get_img_int(1))
self.destroyed_pieces = []
self.destroyed_pieces.append(piece)
for elem in self.destroyed_pieces:
if ......
messagebox.showinfo("WINNER")
class GUIKing(GUIChessPiece,King):
def __init__(self,board,row,col,color,path="./imagepack/"):
if color==BLACK:
path1=path+"bk.png"
path2=path+"bk_s.png"
else:
path1=path+"wk.png"
path2=path+"wk_s.png"
GUIChessPiece.__init__(self,board,row,col,color,path1,path2)
def on_click(self,event):
GUIChessPiece.on_click(self,event)
I am having trouble with continuing this code to detect win, simply by checking if the king is in the list, pieces are classes represented by pictures on a canvas. Though is it the images or the piece that is getting appended to the list? I am attaching the code for the king class
Because 'King' is a class, then to identify whether a member of that class is in the list self.destroyed_pieces you can do:
for elem in self.destroyed_pieces:
if isintance(elem,King):
messagebox.showinfo("WINNER")
Related
import random
class Game():
def __init__(self, username, gameId):
self.users = []
self.users.append(str(username))
self.gameId = gameId
def new_user(self, username):
self.users.append(str(username))
def remove_user(self, username):
try:
self.users.remove(username)
except:
print("[-] User not found!")
def generate_gameId():
gameId = ""
letters = 5
while(letters>0):
gameId += chr(random.randint(65, 90))
letters-=1
return(gameId)
lobby = []
for i in range(2):
lobby.append(generate_gameId())
lobby[i] = Game("Test", lobby[i])
lobby[i].new_user("Test123")
lobby[i].remove_user("Test123")
This is my code for a simple networking game, I will have multiple Game classes at the same time, but I need to find the specific object of a specific gameId. The gameId is randomly generated. Each time a user wants to join the lobby he has to enter the gameId to enter.
How would you achieve something like this? Am I doing it wrong?
There are some things that can be refactored in your code:
In the constructor of your Game class, there's no need for a username parameter, since there's already a new_user method:
class Game():
def __init__(self, gameId):
# Just create the list of users
self.users = []
self.gameId = gameId
# ...
lobby = []
for i in range(2):
lobby.append(generate_gameId())
lobby[i] = Game(lobby[i])
# Use the `new_user` method to create a Test
lobby[i].new_user("Test")
lobby[i].new_user("Test123")
lobby[i].remove_user("Test123")
You're storing the ids in an integer list. You should use a dictionary given that a game will have an unique id:
lobby = {}
for i in range(2):
game_id = generate_gameId()
game = Game(game_id)
# Create a entry in the dictionary
lobby[game_id] = game
game.new_user("Test")
game.new_user("Test123")
game.remove_user("Test123")
Then, you can access the list of games and their ids:
for game_id, game in lobby.items():
print(f'The game {game_id} has the following users:')
for user in game.users:
print(user)
print()
The other guys said everything I was going to say so I deleted most of my post, but here's some other things you could improve on if you want:
You are not looking up a "Class" here. You're looking up an instance of a class, otherwise known as an object. The word "class" in programming always means "The definition of an object". Classes can be instantiated to make objects AKA instances. A good analogy is that a "class" is the blueprints for making a car, while the instance/object would be the car itself that was made using the blueprints(the class).
Don't combine naming conventions. You're combining camel case and snake case which is never a good idea, choose one or the other (python is usually snake case). Specifically, generate_gameId() should be generate_game_id(). This just makes it easier to write code without making spelling mistakes.
i want to create a quest menu for my text rpg, it should be a list of all quests and after completion the finished quest should be removed fromt the menu. I tried it with a class but i get this error:
IndexError: list assignment index out of range
<main.quest_menu object at 0x000001D4F8EC3FD0>
#generate a class for my quest menu
class quest_menu():
def __init__(self, quests):
self.quests = quests
generate functions to remove single quests from the menu
def delete_quest_1(self):
del self.quests[0]
def delete_quest_2(self):
del self.quests[1]
generate quests in a list
quests = quest_menu( ["Quest: Murder: kill Rottger = exp: 100, gold 100",
"\nQuest: Ring of strenght: Find the ring of strenght= : exp 50"])
commands to delete quest from inventory when quest is completed
quests.delete_quest_1()
print(quests)
quests.delete_quest_2()
print(quests)
What am I doing wrong? Does anybody have some tips to improve the code?
Thx in advance!
I think what's wrong is that, You deleted a quest first then the only Quest that remains is the second one, this makes that quest first item in the list so using the function to delete the quest will result in IndexError as the quest is now at Index 0. Try to this instead.
class quest_menu():
def __init__(self, quests):
self.quests = quests
def delete_quest_1(self):
del self.quests[0]
def delete_quest_2(self):
del self.quests[1]
quests = quest_menu( ["Quest: Murder: kill Rottger = exp: 100, gold 100", "\nQuest: Ring of strenght: Find the ring of strenght= : exp 50"])
quests.delete_quest_1()
print(quests.quests)
quests.delete_quest_1()
print(quests.quests)
I have 2 python classes: Player, and Board. The board contains a dict with "A1" reference style for spaces.
player.py's Player class:
from board import Board
class Player:
def __init__(self):
self.name = input("Name: ")
self.board = Board(3, ["A", "B", "C"])
board.py's Board class:
class Board:
EMPTY = "0"
spaces = {}
def __init__(self, size, letters):
for let in letters:
for num in range(1, size + 1):
self.spaces["{}{}".format(let, num)] = self.EMPTY
def place_piece(self, spot):
self.spaces[spot] = "X"
def display_board(self):
for let in letters:
for num in range(1, size + 1):
print("\n" + self.spaces["{}{}".format(let, num)]
When Player is instantiated, it creates a Board object inside.
2 players are created, and each is added to the list players[]. Each player's turn is selected with a simple 1/0 variable called current_player.
from player import *
from board import *
current_player = 1
players = []
player_1 = Player()
player_2 = Player()
players.append(player_1)
players.append(player_2)
while True:
# Switches players
current_player = abs(current_player - 1)
# Prints the current player's name
print(players[current_player].name)
# Calls some method which should alter the current player's board
players[current_player].board.place_piece(input("> "))
# Calls some method which should show the current player's board
players[current_player].board.show_board()
Obviously, very simplified. The name prints out correctly every single time. The board, however, only uses the first player's board for both players. I know it's working because the players' name prints correctly.
The issue persists even if the boards are created separately and placed in their own list.
What am I doing wrong?
As it is written now the code posted shouldn't be working. The two methods in Board, place_piece and display_board, need to accept 'self' as a first argument.
Assuming this is a typo here's what's happening. The class Board is created with a class member spaces. Each time you're referencing self.spaces in an object, it is not found in the object is instead looked up in the class. Meaning you're using the same dict for all object of the class Board. Instead, to create a regular member place the declaration in the init method as you do in the Player class:
class Board:
EMPTY = "0"
# Remove spaces = {}
def __init__(self, size, letters):
self.spaces = {}
...
Finally, since you're using Python 2x please let me encourage you to always use new style classes (i.e. write class Board(object)). See What is the difference between old style and new style classes in Python?
I've been working on making my text based game more realistic, and one design I would like to implement is to make sure the rooms stay 'static' to a point (i.e. a player uses a potion in the room, if they come back to that room that potion should no longer be there.)
This is how my code is basically set up (I have been using "Learn Python The Hard Way" by Zed Shaw so my code is set up much in the same way):
class Scene(object):
def enter(self):
print "This scene is not yet configured. Subclass it and implement enter()."
class Room(Scene):
potions = []
for i in range(3):
potions.append(Potion())
def enter(self):
...
When I run this, I get a NameError: global name 'potions' is not defined. I know I can fix this one of two ways: 1. make potions a global variable, but then I would have to make a new list for each room that contains potions (There are 36 rooms in total, set up as a 6x6 grid) OR
2. Put this line of code in the enter function, but that would cause the list to reset to 3 potions each time the user enters the room.
potions = []
for i in range(3):
potions.append(Potion())
If there's no other way, I suppose declaring a new variable for all the rooms that contain potions (There's only 5). But my question is if there's another way of making this work without making it a global.
Thanks for your help!
First, let's look at your example (I'll simplify it):
class Room(Scene):
potions = [Potion() for x in range(3)]
What you have done there is create a class attribute potions that are shared among all instances of Room. For example, you'll see my potions in each of my rooms are the same instances of potions (the hex number is the same!). If I modify the potions list in one instance, it modifies the same list in all of the Room instances:
>>> room1.potions
[<__main__.Potion instance at 0x7f63552cfb00>, <__main__.Potion instance at 0x7f63552cfb48>, <__main__.Potion instance at 0x7f63552cfb90>]
>>> room2.potions
[<__main__.Potion instance at 0x7f63552cfb00>, <__main__.Potion instance at 0x7f63552cfb48>, <__main__.Potion instance at 0x7f63552cfb90>]
>>>
It sounds like you want potions to be a unique attribute of each instance of a Room.
Somewhere you will be instantiating a room, e.g., room = Room(). You need to write your constructor for your Room in order to customize your instance:
class Room(Scene):
def __init__(self): # your constructor, self refers to the Room instance.
self.potions = [Potion() for x in range(3)]
Now when you create your room instance, it will contain 3 potions.
You now need to think about how you will make your rooms instances persist between entrances by your characters. That will need to be some sort of variable that persists throughout the game.
This idea of object composition will extend through your game. Perhaps you have a Dungeon class that has your 36 rooms:
class Dungeon(object):
def __init__(self):
self.rooms = [[Room() for x in range(6)] for x in range(6)]
Or perhaps your rooms have up to four doors, and you link them up into something potentially less square:
class Room(Scene):
def __init__(self, north_room, east_room, south_room, west_room):
self.north_door = north_room
self.east_door = east_room
[... and so on ...]
# Note: You could pass `None` for doors that don't exist.
Or even more creatively,
class Room(Scene):
def __init__(self, connecting_rooms): # connecting_rooms is a dict
self.connecting_rooms = connecting_rooms
Except both examples will get you a chicken and egg problem for connecting rooms, so it is better to add a method to add each room connection:
class Room(Scene):
def __init__(self):
self.rooms = {}
# ... initialize your potions ...
def connect_room(self, description, room):
self.rooms[description] = room
Then you could do:
room = Room()
room.connect_room("rusty metal door", room1)
room.connect_room("wooden red door", room2)
room.connect_room("large hole in the wall", room3)
Then perhaps your dungeon looks like this:
class Dungeon(Scene):
def __init__(self, initial_room):
self.entrance = initial_room
Now in the end, you just have to hold onto your dungeon instance of Dungeon for the duration of the game.
btw, this construct of "rooms" connected by "paths" is called a Graph.
For context, I'm working on an inventory system in an RPG, and I'm prototyping it with python code.
What I don't understand is how to make separate variables for each instance of an item without declaring them manually. For a short example:
class Player(object):
def __init__(self):
self.Items = {}
class Item(object):
def __init__(self):
self.Equipped = 0
class Leather_Pants(Item):
def __init__(self):
#What do i place here?
def Pick_Up(self, owner):
owner.Items[self.???] = self #What do i then put at "???"
def Equip(self):
self.Equipped = 1
PC = Player()
#Below this line is what i want to be able to do
Leather_Pants(NPC) #<-Create a unique instance in an NPC's inventory
Leather_Pants(Treasure_Chest5) #Spawn a unique instance of pants in a treasure chest
Leather_Pants1.Pick_Up(PC) #Place a specific instance of pants into player's inventory
PC.Items[Leather_Pants1].Equip() #Make the PC equip his new leather pants.
If I did something silly in the above code, please point it out.
What I want to do if the code doesn't make it clear is that I want to be able to dynamically create variables for all items as I spawn them, so no two items will share the same variable name which will serve as an identifier for me.
I don't mind if I have to use another class or function for it like "Create_Item(Leather_Pants(), Treasure_Chest3)"
What's the best way to go about this, or if you think I'm doing it all wrong, which way would be more right?
As a general rule, you don't want to create dynamic variables, and you want to keep data out of your variable names.
Instead of trying to create variables named pants0, pants1, etc., why not just create, say, a single list of all leather pants? Then you just do pants[0], pants[1], etc. And none of the other parts of your code have to know anything about how the pants are being stored. So all of your problems vanish.
And meanwhile, you probably don't want creating a Leather_Pants to automatically add itself to the global environment. Just assign it normally.
So:
pants = []
pants.append(Leather_Pants(NPC))
pants.append(Leather_Pants(chests[5]))
pants[1].pickup(PC)
The pants don't have to know that they're #1. Whenever you call a method on them, they've got a self argument that they can use. And the player's items don't need to map some arbitrary name to each item; just store the items directly in a list or set. Like this:
class Player(object):
def __init__(self):
self.Items = set()
class Item(object):
def __init__(self):
self.Equipped = 0
class Leather_Pants(Item):
def __init__(self):
pass # there is nothing to do here
def Pick_Up(self, owner):
self.owner.Items.add(self)
def Equip(self):
self.Equipped = 1
Abernat has tackled a few issues, but I thought I weigh in with a few more.
You appear to be using OOP, but are mixing a few issues with your objects. For example, my pants don't care if they are worn or not, I care though for a whole host of reasons. In python terms the Pants class shouldn't track whether it is equipped (only that it is equippable), the Player class should:
class CarryableItem:
isEquipable = False
class Pants(CarryableItem):
isEquipable = True
class Player:
def __init__(self):
self.pants = None # Its chilly in here
self.shirt = None # Better take a jumper
self.inventory = [] # Find some loot
def equip(self,item):
if is.isEquipable:
pass # Find the right slot and equip it,
# put the previously equipped item in inventory, etc...
Also, its very rare that an item will need to know who its owner is, or that its been grabbed, so verbs like that again should go onto the Player:
class Player:
maxCarry = 10
def take(Item):
if len(inventory) < maxCarry:
inventory.append(item)
Lastly, although we've tried to move most verbs on to actors which actually do things, sometimes this isn't always the case. For example, when instantiating a chest:
import random
class StorageItem:
pass
class Chest(StorageItem):
__init__(self):
self.storage = random.randint(5)
self.loot = self.spawnLoot()
def spawnLoot(self):
for i in range(self.storge):
# Lets make some loot
item = MakeAnItem # Scaled according to type level of dungeon, etc.
loot.append(item)
def remove(item):
self.loot[self.loot.index(item)]=None
Now the question about what to do when a Player wants to plunder a chest?
class Player:
def plunder(storage):
for item in storage.loot:
# do some Ui to ask if player wants it.
if item is not None and self.wantsItem(item) or \
(self.name="Jane" and self.wantsItem(item) and self.doesntWantToPay):
self.take(item)
storage.remove(item)
edit: Answering the comment:
If you are curious about calculating armor class, or the like, that again is a factor of the user, not the item. For example:
class Player:
#property
def clothing(self):
return [self.pants,self.top]
#property
def armorClass(self):
ac = self.defence
for item in self.clothing:
def = item.armorClass
if self.race="orc":
if item.material in ["leather","dragonhide"]:
def *= 1.5 # Orcs get a bonus for wearing gruesome dead things
elif item.material in ["wool","silk"]:
def *= 0.5 # Orcs hate the fineries of humans
ac += def
return ac
pants = Pants(material="leather")
grum = Player(race="orc")
grum.equip(pants)
print grum.armorClass
>>> 17 # For example?