Im currently taking a python class and im new in programming. I have written the code below and want to write a code that tests if the ResilientPlayer actually does what it is supposed to. The code is from a chutes and ladders board game where the ResilientPlayer is a "special" type of player that gets a "superpower" in its next move afther falling down a chute. The next round afther he has fallen down a chute, he will add a given or a default number to the die_roll, and I want to test if my code actually does this! Hope someone can help me with this problem :)
class Player:
def __init__(self, board):
self.board = board
self.position = 0
self.n_steps = 0
def move(self):
die_roll = random.randint(1, 6)
self.position = self.get_position() + die_roll
self.board.position_adjustment(self.position)
self.n_steps += 1
def get_position(self):
return self.position
def get_steps(self):
return self.n_steps
class ResilientPlayer(Player):
default_extra_steps = 1
def __init__(self, board, extra_steps=None):
super().__init__(board)
self.extra_steps = extra_steps
if self.extra_steps is None:
self.extra_steps = self.default_extra_steps
def move(self):
if self.get_position() in self.board.chutes.values():
die_roll = random.randint(1, 6)
self.position = self.get_position() + die_roll + self.extra_steps
self.board.position_adjustment(self.position)
self.n_steps += 1
else:
super().move()
def get_position(self):
return self.position
def get_steps(self):
return self.n_steps
The best way to do this is using the unittest class, I do this as following:
import unittest
from .... import ResilientPlayer
class TestResilientPlayer(unittest.TestCase):
def setUp(self):
self.resilient_player = ResilientPlayer(....)
def test_move(self):
# Do stuff
self.assertEqual(1, 1)
if __name__ == '__main__':
unittest.main()
Here, unittest.main() will run all the tests in the file. setUp is run before each test (so you can have multiple tests with the same starting conditions).
This is an incredible useful module and I strongly suggest reading more on it, check the documentation
Related
I am still learning Python programming and currently struggling to achieve one goal. I got a class Dot that is used to create coordinates and compare them later on. Also, I got a class Player with two other child classes that are inherited from the Parent class.
class Dot:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __repr__(self):
return {self.x, self.y}
class Player:
def __init__(self, board, enemy):
self.board = board
self.enemy = enemy
def ask(self):
raise NotImplementedError()
def turn(self):
while True:
try:
target = self.ask()
repeat = self.enemy.shoot(target)
return repeat
except BoardExceptionError as e:
print(e)
class Viki(Player):
def ask(self):
answer = Dot(randint(0, 5), randint(0, 5))
time.sleep(3)
print(f'Turn of Viki: {answer.x} {answer.y}')
return answer
class Human(Player):
def ask(self):
while True:
h = input('Your turn: ').split()
if len(h) != 2:
print('Add 2 coordinates...')
continue
x, y = h
if not (x.isdigit()) or not (y.isdigit()):
print('Add numbers from 0 to 6...')
continue
x, y = int(x), int(y)
return Dot(x - 1, y - 1)
What I would like to expect is that class "Viki(Player)" kind of an AI, forcing it to not use the same coordinates(Dots) that are already used(generated) previously. So, every time it should use none used cells on the board.
I understand that it might help in this case logical operators or count function. For example,
Example 1:
a = Dot(1, 2)
b = Dot(1, 3)
c = Dot(1, 4)
abc_list = [Dot(1, 2), Dot(2, 2), Dot(2, 3)]
print(a in abc_list)
Output
True
Example 2:
print(abc_list.count(a))
Output
1
I tried to play with both options but gettings different types of errors when I try to use loops and blocks. I understand that the bottleneck here is my knowledge :) Your help is much appreciated if someone can help me to sort this out. Thanks in advance!
Here is a generator that produces all the dots in random order (no repeats):
from itertools import product
from random import shuffle
def random_dots():
dots = [Dot(*p) for p in product(range(6), repeat=2)]
shuffle(dots)
yield from dots
rd = random_dots()
Now, you can use it in you code:
dot = next(rd)
If pre-generating all dots is not an option because there are too many, you could use the following which is lighter on memory/time:
dots = set()
def random_dot():
while (tpl := (randint(0, 5), randint(0, 5))) in dots:
pass
dots.add(tpl)
return Dot(*tpl)
And use like:
dot = random_dot()
I have this code. [enemy.py].
# Enemy behaviour.
# Entities.
from ursina import Entity
# Colors.
from ursina.color import red
# 3D Vectors.
from ursina import Vec3
# Capsule model.
from ursina import Capsule
# Random.
from random import randint, choice
# Sequences and tools for it.
from ursina.sequence import Sequence, Wait, Func
# Some enemy constants.
ENEMY_MODEL = Capsule() # NOTE (TODO): Maybe later can be replaced on new enemy 3D model.
ENEMY_SCALE = (2, 2, 2)
ENEMY_COLLIDER = 'mesh'
ENEMY_COLLISION = True
ENEMY_COLOR = red
ENEMY_SPAWN_POS = (16.328, 1.500, 16.773) # XXX: Generated by console.
# Enemy class.
class Enemy(Entity):
def __init__(self) -> None:
"""Enemy class."""
super().__init__(
model=ENEMY_MODEL,
scale=Vec3(ENEMY_SCALE),
collider=ENEMY_COLLIDER,
collision=ENEMY_COLLISION,
color=ENEMY_COLOR,
position=ENEMY_SPAWN_POS
)
self.ai_enabled = False
self.friendly = False
self.move_every_secs = 5
self.sequences = [
Sequence(
Func(self.simulate_moving),
Wait(self.move_every_secs),
loop=True
)
]
self.sequences_started = False
# Enemy update function.
def update(self):
if self.ai_enabled:
if not self.sequences_started:
for sequence in self.sequences:
sequence.start()
self.sequences_started = True
elif not self.ai_enabled:
if self.sequences_started:
for sequence in self.sequences:
sequence.pause()
self.sequences_started = False
def simulate_moving(self):
"""Simulate enemy moving."""
move_by = ['x', 'z']
move_by_random = choice(move_by)
move_on = randint(5, 10)
if move_by_random == 'x':
for _ in range(int(self.position.x + move_on)):
self.position.x += 1
elif move_by_random == 'z':
for _ in range(int(self.position.z + move_on)):
self.position.z += 1
self.ai_log('Moved.')
def enable_ai(self) -> None:
"""Enable enemy AI."""
self.ai_enabled = True
def disable_ai(self) -> None:
"""Disable enemy AI."""
self.ai_enabled = False
def set_friendly(self) -> None:
"""Make enemy friendly."""
self.friendly = True
def set_not_friendly(self) -> None:
"""Make enemy not friendly."""
self.friendly = False
def update_moving_per_secs(self, new_val: int) -> None:
"""Update moving activity per seconds."""
self.move_every_secs = new_val
def ai_log(self, message) -> None:
"""Create AI log into console."""
print(f'AI (Core) : {message}')
[game.py] (Not full code, but anyway that's what we need to know).
from enemy import Enemy
enemy = Enemy()
enemy.enable_ai()
And every 5 seconds it must move, but it's doesn't move at all.
Note, that function get called.
What to do?
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
Oh, i solved it.
We need to use self.x, not self.position.x.
I keep getting this, have no idea how to make it work, I'm kinda new at python coding and this is giving me a headacke. Could not find any answer at all so please, just tell me what to do
'''
from tkinter import *
import random
import time
# Variables
# Player
class Player(object):
health = random.randint(70,100)
strength = random.randint(70,80)
defence = random.randint(45,55)
speed = random.randint(40,50)
luck = random.randint(40,50)
def __init__(self, arg):
super(Player, self).__init__()
self.arg = arg
# Beast
class Beast(object):
health = random.randint(60,90)
strength = random.randint(60,90)
defence = random.randint(40,60)
speed = random.randint(40,60)
luck = random.randint(25,40)
def __init__(self, arg):
super(Beast, self).__init__()
self.arg = arg
def begin():
print("\nHero"," Beast"
"\nHealth:", Player.health, " Health:", Beast.health,
"\nStrength:", Player.strength, " Strength:",Beast.strength,
"\nDefence:", Player.defence, " Defence:", Beast.defence,
"\nSpeed:", Player.speed, " Speed:", Beast.speed,
"\nLuck:", Player.luck, " Luck:", Beast.luck)
print("\nBEGIN FIGHT")
def round_stat():
print("Hero"," Beast",
"\nHealth:", Player.health," Health:", Beast.health)
def who_move():
hero_first = 1
if Player.speed > Beast.speed:
hero_first = 1
elif Player.speed < Beast.speed:
hero_first = 0
else:
if Player.luck > Beast.luck:
hero_first = 1
else:
hero_first = 0
begin()
round_stat()
who_move()
if who_move().hero_first == 1:
print("SUPPPPPPP")
'''
who_move() is function, not an object. So you can not access variable inside function.
So the quickest solution is set the hero_first as global:
def who_move():
global hero_first
hero_first = 1
who_move()
if hero_first == 1:
print("SUPPPPPPP")
and then I got:
dubak#dubak-thinkpad:~/projects/$ python3 test.py
SUPPPPPPP
or rewrite the who_move function so it is returning directly value of hero_first. Something like this:
def who_move():
hero_first = None
if 2 > 1:
hero_first = 1
return hero_first
if who_move() == 1:
print("SUPPPPPPP")
You cannot access the internal variables of a function using the . syntax. If you want that data to be accessible outside of the function, return it:
def who_move():
if Player.speed > Beast.speed:
return 1
elif Player.speed < Beast.speed:
return 0
else:
if Player.luck > Beast.luck:
return 1
else:
return 0
Then, use it like:
if who_move() == 1
The other answer mentions global, but I would not use that here. Use of global should be limited, as it has a general tendency of making your code harder to maintain and understand.
I'm practicing writing classes in Python and I'm stumped on how to do something.
class GolfClub:
def __init__(self, size, distance):
self.size = size
self.distance = distance
def hits_further(self, other):
if self.distance > other.distance:
return "(name of club variable) hits further"
else:
return "(name of club variable) hits further"
If I do:
club1 = GolfClub(5, 200)
club2 = GolfClub(6, 300)
club1.hits_further(club2)
How can I make the hits_further method return the name of the variable? For example, I would like it to return:
"club2 hits further"
How can I get the variable names into the method?
Traditionally, you'd give the instance a name:
class GolfClub:
def __init__(self, name, size, distance):
self.name = name
self.size = size
self.distance = distance
def hits_further(self, other):
if self.distance > other.distance:
return "%s hits further" % self.name
else:
return "%s hits further" % other.name
club1 = GolfClub('Driver', 5, 200)
club2 = GolfClub('9Iron', 6, 300)
club1.hits_further(club2)
The instance itself has no possible way of knowing what name you've given to the variable containing it. So, store the name inside the instance.
Fundamentally, you can't do what you want here, because, in Python, the name is not a property of the variable. It's just a handle, which can be attached and reattached, while the object can have multiple names pointing to it, none of which is the name.
This is why others have suggested adding a name as an init parameter.
If I were to do what you were doing, I would change your class to do something like:
class GolfClub:
def __init__(self, size, distance):
self.size = size
self.distance = distance
def hits_further(self, other):
if self.distance > other.distance:
return True
else:
return False
And the code to do something like:
club1 = GolfClub(5, 200)
club2 = GolfClub(6, 300)
if club1.hits_further(club2):
print("club1 hits further")
else:
print("club2 hits further")
Change the return statement to a print statement.
Add a name attribute to your class. Then do something like this:
class GolfClub:
def __init__(self, size, distance,name):
self.size = size
self.name = name
self.distance = distance
def hits_further(self, other):
if self.distance > other.distance:
print self.name, "club hits further"
else:
print other.name ,"That club hits further"
club1 = GolfClub(5, 200,"c1")
club2 = GolfClub(6, 300,"c2")
club1.hits_further(club2)
As far as i know, what you wish to achieve is not really possible
In fact it can be done asking the stack
import inspect
import traceback
import sys
import re
class GolfClub:
def __init__(self, size, distance):
self.size = size
self.distance = distance
def hits_further(self, other):
call_str= traceback.extract_stack()[0][3]
m = re.search('([\w]+)\.hits_further\((.*)\)',call_str)
self_name=m.group(1)
other_name=m.group(2)
if self.distance > other.distance:
return self_name+" hits further"
else:
return other_name+" hits further"
club1=GolfClub(1,1)
club2=GolfClub(2,2)
print club1.hits_further(club2)
print club2.hits_further(club1)
The result is:
club2 hits further
club2 hits further
As asked by geogeogeo
You can make it like this:
def name(**variable):
return [x for x in variable]
I've encountered a problem with my class file and I can't seem to find a fix around it. I was hoping someone could point me to the right direction.
Here's my code:
class Car:
def __init__(self, year_model, make, speed):
self.__year_model = year_model
self.__make = make
self.__speed = 0
def set_year_model(self, year_model):
self.__year_model = year_model
def set_make(self, make):
self.__make = make
def get_year_model(self):
return self.__year_model
def get_make(self):
return self.__make
def accelerate(self):
self.__speed + 5
return self.__speed
def decelerate(self):
self.__speed - 5
return self.__speed
def get_speed(self):
return self.__speed
Essentially, I want the speed attribute set to 0, and have 3 methods (accelerate, decelerate, and get_speed) which add and subtract 5 to the speed attribute and eventually return the speed attribute so it can be printed.
I would guess there's a problem with my formatting but I can't seem to find the correct arrangement that would fix the class.
The real program is suppose to loop the accelerate method 5 times, but the class method is supposed to handle the sequential addition and return the final speed.
import car
user_year = 1995
user_make = "toyota"
user_speed = 0
user_car = car.Car(user_year, user_make, user_speed)
for count in range(1,6):
user_car.accelerate()
print user_car.get_speed()
I know this code is very weak, but it's all makeshift to help make my problem clearer.
So hopefully it's not too confusing and I can get an answer.
self._speed + 5 computes the current speed plus 5. But you're not actually storing the computed value anywhere. You want to use self._speed = self._speed + 5, or the more commonly used form, self._speed += 5.
The problem is, of course, the "+=" and "-=" portions that are missing, but I'd go a step further and suggest that if you're writing new python code, you become familiar with new style classes. In a new style class, your code could be written as follows:
class Car(object):
def __init__(self, year_model, make, speed):
self.year_model = year_model
self.make = make
self.speed = 0
def __set_year_model(self, year_model):
self.__year_model = year_model
def __set_make(self, make):
self.__make = make
def __set_speed(self, speed):
self.__speed = speed
def __get_year_model(self):
return self.__year_model
def __get_make(self):
return self.__make
def accelerate(self):
self.speed += 5
def decelerate(self):
self.speed -= 5
def __get_speed(self):
return self.__speed
speed = property(fget=__get_speed,fset=__set_speed,fdoc="Set or Retrieve the current speed of this instance of the Car object")
make = property(fget=__get_make,fset=__set_make,fdoc="Set or Retrieve the make of this instance of the Car object")
year_model = property(fget=__get_year_model,fset=__set_year_model,fdoc="Set or Retrieve the Year and Model of this instance of the Car object")
In addition, the code changes in the main file:
import car
user_year = 1995
user_make = "toyota"
user_speed = 0
user_car = car.Car(user_year, user_make, user_speed)
for count in range(1,6):
user_car.accelerate()
print user_car.speed