Can you make a universal function for multiple objects? - python

I'm making a chess game, and I have to restate the same set of rules every time I make a pawn, is there any way to make this easier. Here is the script i have to restate every time.
elif spacesdirection == "DR":
if bpawn8xpos - 1 == wpawn1xpos and bpawn8ypos - 1 == wpawn1ypos:
bpawn8xpos -= 1
bpawn8ypos -= 1
print("wpawn1 is dead!")
wpawn1a = "dead"
move += 1
start()
Is there any good way do this for multiple pawns such as, bpawn7, wpawn3, etc.

You would want to use lists instead of numbered variables, and at least put repeating code inside helper functions.
It would be better to define classes representing each piece, and they would store the relevant procedures.

Related

Function vs if-statement: Function is not working, but the code in the function will work when outside a function?

I was working on building a randomized character generator for Pathfinder 3.5 and got stuck.
I am using the Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill): function to populate a randiomized list of skills with their class based points total, class bonus, and point buy. So modelling the action of a player picking skills for their character.
As an example below, Wizards.
I pick Knowledge_Arcana as a skill and spend one of my skill point pool (Calculated by taking my intelligence modifier +2) on it. So that skill now equals my intelligence modifier(+1 in this case), class skill bonus as a wizard (+3), plus the point I spent(+1) for a total of 5.
The problem is while the function prints the correct result of 5, the outstanding variables do not populate with the final total. To continue our example I'd run the function on Knowledge_Arcana, get a +5, and then check the Knowledge_Arcana after the function call and get just +1. Conversely, if I write out the function as just an if statement it works. Example is next to the function for comparison.
Does anyone know why Im getting the different result?
## Creating the lists and breaking into two separate sections
Int_Mod = 1
Skill_Ranks = 3
Rand_Class = 'Wizard'
Knowledge_Arcana = Int_Mod
Knowledge_Dungeoneering = Int_Mod
Wizard_Class_Top_Skills = ["Knowledge_Arcana"]
Wizard_Class_Less_Skills = ["Knowledge_Dungeoneering"]
Class_Skill = 3
Important_Skills_Weighted = .6
Less_Important_Skills_Weighted = .4
Important_Skills_Total_Weighted = round(Skill_Ranks*Important_Skills_Weighted)
Less_Skill_Total_Weighted = round(Skill_Ranks*Less_Important_Skills_Weighted)
Wiz_Draw =['Knowledge_Arcana', 'Knowledge_Dungeoneering']
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
## Function Calls
Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
Populate_Skills('Knowledge_Dungeoneering', Wiz_Draw, Knowledge_Dungeoneering, Class_Skill)
print(Knowledge_Arcana,Knowledge_Dungeoneering)
Edited to be a MRE, I believe. Sorry folks, Im new.
You are passing in a reference to a list and expect the function to modify it; but you are reassigning the variable inside the function which creates a local variable, which is then lost when the function is exited. You want to manipulate the same variable which the caller passed in, instead.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List.extend(Class_Skill + Draw.count(Skill_String))
print(Skill_String, Skill_List)
else:
print('Nuts!')
Alternatively, have the function return the new value, and mandate for the caller to pick it up and assign it to the variable.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
return Skill_List
Skill_List = Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
# etc
You should probably also rename your variables (capital letters should be used for classes and globals; regular Python functions and variables should use snake_case) and avoid using global variables at all. The entire program looks like you should probably look into refactoring it into objects, but that's far beyond the scope of what you are asking.

How to get rid of the global variables

I don't want to use the global-variable, but how do I make this without them?
(I have more functions and so on, so this isn't all)
Players turn. I use the global-variable to make sure the turns are switching, tried some other sulotion however the turns didn't switch...
#Check if the shot hit any computerships
def player_hit_check():
global players_turn
shot = player_shot()
check_if_hit = set(computer_ships) & set(player_turn_shot)
if(check_if_hit == set()):
print("You missed! Switching turns...")
time.sleep(3)
players_turn = 1
else:
print(f"YOU MADE A BIG BANG ON ",player_turn_shot,"!")
computer_ships.remove(shot)
all_player_hits.append(shot)
Computers turn
#Check if the computers shot hit any player ships
def computer_hit_check():
global computers_turn
computer_random_shot = computer_shot()
check_if_hit = set(player_ships) & set(computer_turn_shot)
if(check_if_hit == set()):
print("Computer missed! It's now your turn.")
time.sleep(3)
computers_turn = 1
else:
print(f"COMPUTER MADE A BIG BANG ON ",computer_turn_shot,"!")
player_ships.remove(computer_random_shot)
all_computer_hits.append(computer_random_shot)
The game it self
#Runs the game
while True:
#Players turn
players_turn = 0
while players_turn < 1:
print('\n'.join('\t'.join(row) for row in board.values()))
print("Playerships:",player_ships)
print("Computerships:",computer_ships)
print("You have shot on",all_player_shots,"and has knocked out these ships:",all_player_hits)
print("The computer has shot at these coordinates",all_computer_shots,"and has knocked out these ships:",all_computer_hits)
player_hit_check()
#Computers turn
computers_turn = 0
while computers_turn < 1:
computer_hit_check()
In your case you don't need global variables at all. Your program is not using them to carry information back and forth.
In your case you just need to get information back from your functions. So in the case of player_hit_check():
def player_hit_check():
shot = player_shot()
check_if_hit = set(computer_ships) & set(player_turn_shot)
if(check_if_hit == set()):
print("You missed! Switching turns...")
time.sleep(3)
return 1
else:
print(f"YOU MADE A BIG BANG ON ",player_turn_shot,"!")
computer_ships.remove(shot)
all_player_hits.append(shot)
return 0
And the call site would be like this:
while True:
#Players turn
players_turn = 0
while players_turn < 1:
# prints elided ...
players_turn = player_hit_check()
The problem with global variables is, that they fly around in an unstructured manner.
There are several approaches to solve global variables
One first step to get rid of global variables is to use singletons (https://en.wikipedia.org/wiki/Singleton_pattern). This will bundle similar values into one class. So the values are more structured and easier to track.
Use classes. If the global value is used in an environment that can be associated to a single responsibility, it can be productive to bundle all functions in a class and make the global variable to a class variable or property of the class
Pass it through. In many programs there is the need of settings class or state class. Put everything in there that defines the current state or starting state of the program and pass it through your code. The downside of passing is, that this classes tend to become almighty classes that appear in every constructor.
There are certainly more approaches how to get rid of global variables, but this are some common strategies.

Is there a way to create a function that will run this code but without passing so many arguments?

I am trying to make code from my project more efficient, shorter but not hard to read/understand.
I see that there are some actions that repeat themselves a couple of times in the code. It is a game so it is required to repeat those.
I thought that maybe I should create a function to call every time instead, but it does not seem friendly to read, because, following a condition, I need to change a couple of variables so I need to pass all of them to the function.
Here is an example:
if nxtTurn == 'player1':
card2, player1 = EgyptionWarHelper.pull_out_card(player1, nxtTurn)
storage.append(card2)
nxtTurn = 'player2'
else:
card2, player2 = EgyptionWarHelper.pull_out_card(player2, nxtTurn)
storage.append(card2)
nxtTurn = 'player1'
I wanted to create a function that does this, but then realized I will need to pass all of the variables to it and then return a tuple of 2 variables at the end of it. I did hear about global variables but I never really used them and I don't know if they are the solution for this.
EDIT: I found out that I didn't have to pass some of the argument so after I edit the function and used temporary variables as well, the code is much more readable.
Additionally, as commented, I didn't have to return player and player2 because python passes lists by reference and not by value.
why not using a temporary variable ?
if nxtTurn == 'player1':
player = player1
nxtTurn = 'player2'
else:
player = player2
nxtTurn = 'player1'
card2, player1 = EgyptionWarHelper.pull_out_card(player, nxtTurn)
storage.append(card2)
it's easily readable and maintainable.

Algorithm to return all possible paths in this program to a nested list

So I have a game with a function findViableMoves(base). If i call this function at the start with the parameter base, I get an output [move1, move2 ... moven] which denotes all of the n viable moves that the user can perform give the state base. (there are in fact 2 root moves)
Upon performing a move, say move2 - base gets changed depending on the move, the function gets called again and now we have an output for findViableMoves(base) of [move21,move22 .... move2n].
Depth-first-tree
If you look at this diagram, it's a very similar situation - there's no looping back, it's just a normal tree. I need a program that performs a depth-first search (i think?) on all the possible moves given a starting state of base, and then returns then in a list as such:
[[move1,move11,move111],[move1,move11,move112],....[moven,moven1,moven11],...]
There will be more elements in these lists (14 at most), but I was just wondering if someone could provide any hints over how I can build an algorithm to do this? Efficiency doesn't really matter to me as there isn't too many paths, I just want it done for now.
I'm not 100% clear on what you're after, but if you have a list or similar iterable that is changing while the loop is happening you could try something like the below.
This example allows the list and the loop condition to both remain dynamic during the loop execution.
import random
import sys
import time
changing_list = ['A', 27, 0.12]
def perform_operation(changing_list, counter):
sometimes_add_another_element_threshold = 0.6
if random.random() > sometimes_add_another_element_threshold:
changing_list.append(random.random())
print(changing_list[counter])
def main(z=0):
safety_limit = 100
counter = 0
condition = True
while condition and counter < safety_limit:
perform_operation(changing_list, counter)
counter += 1
condition = counter<len(changing_list)
print("loop finished")
if __name__ == '__main__':
start_time = time.time()
main(int(sys.argv[1])) if len(sys.argv)>1 else main()
print(time.time() - start_time)
which provides output of varying length that looks something like:
A
27
0.12
0.21045788812161237
0.20230442292518247
loop finished
0.0058634281158447266

python class doesn't work for different variable

dear expert i am trying to write a simulation and in my code i have a class like this:
... (some def are here)
class multipole:
global xxp,yyp,zzp,x,y,z,xp,yp,zp,t,tm,h
xxp,yyp,zzp,x,y,z,xp,yp,zp =xxpyypzzp() # some initial values calling
#staticmethod
def quad(f1, f2,f3):
global t,h,mass,ksimax
while t < ksimax:
rk4_two(t,h,mass, f1, f2, f3, xxp, yyp, zzp) # rk function for new xxp, yyp and zzp
t = t + h
tm.append(t)
xp.append(xxp[1])
x.append(xxp[0])
yp.append(yyp[1])
y.append(yyp[0])
zp.append(zzp[1])
z.append(zzp[0])
return xp, x, yp,y,zp,z,tm
if __name__ == "__main__":
qp=multipole()
quxp, qux, quyp,quy,quzp,quz,qutm=qp.quad(0.,0.,0.)
hxp, hx, hyp,hy,hzp,hz,htm =qp.quad(0.022,0.,0.)
oxp, ox, oyp,oy,ozp,oz,otm =qp.quad(-0.023,-0.032,0.0 )
my question is this code only calculate (quxp, qux, quyp,quy,quzp,quz,qutm), but not others (others will turn same value of quxp, qux, quyp,quy,quzp,quz,qutm) could you please tell me why? i am new in python any comments will be appreciated.
Ignoring the fact that this code is... somewhat flawed. I think that the problem is that you are using t which is apparently global but you don't reset it anywhere - so this loop:
while t < ksimax:
...
Will only run once, unless you reset t somewhere. Some pseudo code to explain why this happens:
counter = 0
def do_something():
global counter
print "Starting at", counter
while counter <= 10:
print counter
counter += 5
print "Done"
do_something()
# Starting at 0
# 0
# 5
# 10
# Done
do_something() # Called again, the counter is at 10 now:
# Starting at 10
# Done
As others have mentioned, your code could benefit from some heavy refactoring. Some starting points:
Naming! What does xxpyypzzp even mean? Even if it's obvious to you today, it must be hard to read even for you and unless you have Rainman-like memory you will not understand this next week. Try using descriptive names and if you find yourself adding prefixes or suffixes to variables because you run out of names - think about encapsulating some of this complexity in a class. It seems like the suffixes xp, x, yp, y, zp, z and tm are used a lot. At least create a named tuple to hold these values.
Global variables is generally considered harmful. They make it hard to reason about code - which is why you got this bug in the first place. If you are sprinkling global statements over your code there is time to redesign it. Think about which part of your code should "own" which parts of the state.
Python has a coding standard, called PEP8 - read it and try to follow it.

Categories

Resources