I'm writing an automated test using Selenium Python that will play a Web-based game of tic-tac-toe. The method checkForWinner() needs to check the UI for a line of text displaying the winner after each click, but the method isn't getting called, and I don't know why.
def checkForWinner(self, load_browser):
if Tags.resultOh:
winner = 'O'
LOGGER.debug('Winner O')
assert winner
elif Tags.resultEx:
winner = 'X'
LOGGER.debug('Winner X')
assert winner
elif Tags.resultTie:
winner = 'None'
LOGGER.debug('Tie')
assert winner
else:
self.test_playGame(load_browser)
Whenever the script is run, the game reaches a conclusion and the script hangs. The browser should close after the game is over, but it doesn't. It's obviously waiting for a condition that's not being met, but I can't see what it is.
I think you're getting stuck inside your for loop, where you're calling the test_PlayTTT() method recursively. Since you're playing one bot against another, you need to keep track of the state of the game board after each bot moves. Right now, it looks like you're only tracking the moves of this bot, but it can potentially click on squares already claimed by the other player. You want clickedSquares to contain squares clicked by the opposing bot, not just this one.
The maximum number of squares either player can mark is five in a game of tic-tac-toe, so either check for a winner after each player clicks a square, or call checkForWinner() when the size of clickedSquares reaches 5.
Related
So, to preface this I’m self learning python and I’m trying to build a Tic-Tac-Toe game using the command line as an interface. The issue that I have is that I can’t get the input inside one of the inherited class for the player to work (so the game itself doesn’t work aside from the 3x3 board showing up on the command line)
The section of code that I’m having issues with goes as such:
class HumanPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self, game):
valid_square = False
val = None
while not valid_square:
square = input(self.letter + ' s turn. Input move (0-9):')
# we are going to check that this is a correct value by trying to cast
# it into an integer, and if it's not, then we will say its invalid
# if that spot is not available on the board, then we also say it's invalid
try:
val = int(square)
if val not in game.available_moves:
raise ValueError
valid_square = True # if these are successful, then oh yeah!
except ValueError:
print ('Invalid Square. Try Again. ')
return val
I’ve tried to make sure that my spacing is correct within this class, but now I’m not sure what else to do. Any help, suggestions, or the like would be appreciated since I’m learning to program in general
Thanks!
Although there is nothing wrong with an object-oriented approach, and it can be the (or at least a) right approach for many problems, it looks like your program has "classes because of classes". It's probably easier if you don't bother with the object-orientation too much at this stage and focus on the main gameplay loop.
Try to imagine how the game should progress: you start the game, you make a move, another player makes a move, this continues until the game decides either play has won and then perhaps you can start a new game. And the other player might be an "AI" (tic tac toe doesn't require much intelligence) or another live player.
Your code covers what needs to happen for a single player to enter a valid square and it appears you have another class somewhere that's a Game, an instance of which has an attribute available_moves that contains all the currently valid moves. Or perhaps that Game class is the next thing you plan to write.
The main game loop would be to ask players for a move in alternating fashion, update the game board, decide if someone has won yet, and keep doing that. And you'll need to get the whole thing started, some core routine that sets up the game and the players and gets the ball rolling.
If you have a more specific problem getting all that to work, you should post a question about that - but without a more specific problem, it's hard to provide a better answer.
Where is the code for th
So, I'm not sure the title describes my issue in a comprehensive manner.
I have made a working "loop" code in Python (even with working recursive functions) for some sort of a card game "AI". See the following pseudo-code:
def move():
if Turn == "Computer":
if Computer cannot play:
return False
else:
Do some "AI" stuff... the computer plays
Turn = "Player"
move()
elif Turn == "Player":
if Player cannot play:
return False:
else:
in = input("Select Card: ")
****So here the loop stops and waits for the input from the player
...then the input is evaluated and "played" as a player move
Turn = "Computer"
move()
while continue:
continue = move()
So if the computer can play, it plays the card, the turn changes to Player and the move function is called again, otherwise false is returned and the PC-Player back and forth turn is over. In the Player's turn the loop stops to wait for the user input from terminal and then it continues...
So far everything works, but now I want to implement a GUI for player input. I have some basic knowledge with Tkinter and so far I created buttons on screen rapresenting the player's cards. The question is how can I "stop" the loop waiting for the user to click a button (corresponding to the card - or the PASS TURN). Maybe with some sort of threading but sounds complicated... there must be an easier solution like in the "Terminal input version" that I have already working.
Thanks
You can't use a loop in a GUI, because the GUI has it's own loop that needs to run. The mainloop() in tkinter. You need to shift your planning to "event driven" programming. It sounds like in your case the event would be the user choosing a card.
def player_chooses_card():
# graphic and logic updates for player's choice
# computer turn
if Computer cannot play:
trigger graphic for end of game
else:
Do some "AI" stuff... the computer plays
# function is done; back to idle state waiting for an event
FWIW making a loop with recursion is bad style in python.
I feel your pain on the Tkinter loops. It was a hard lesson for me to learn as well. Loops such as while and for DO NOT WORK in tkinter. The way I typically solve this problem is with "root.after." Take the code in your loop and define it as a command (adding root.after(1, name of your command) like so:
def myloop():
move()
root.after(1, myloop)
Then, call it for the first time right before 'root.mainloop', like so:
<your other code>
root.after(1, myloop)
root.mainloop()
Also keep in mind that Tkinter does not make nice nice with multiprocessing/threading within mainloops, so you have to set up each process/thread as its own canvas and root.
Finally, you could set up a series of if statements and variables to separate your loop into chunks so that it stops and starts based on player input. For example,
def myloop():
if playerhasdonething == True:
move()
else:
print("waiting on player")
root.after(1, my mainloop)
I apologize if I missed the point of your question, this is how I personally would try to solve your problem
I am trying to copy from the app store in pygame for practice, i have set up a system where if you beat the current high score it will write it into the file so that it can be saved for later so the user can try and beat their score.
def player_death(player_score): # What happens when the player dies
end_font = pygame.font.Font('freesansbold.ttf', 50)
print("You have died") # For debugging
score_file = open('data/score.txt', 'a') # Don't think this is related
score_file.write(str(player_score)) # Don't think this is related
score_file.close() # Don't think this is related
b_score_file = open('data/score_best.txt', 'r')
score_read = int(b_score_file.read())
b_score_file.close()
if player_score >= score_read:
b_score_file = open('data/score_best.txt', 'w')
b_score_file.write(str(player_score))
b_score_file.close()
print("New best score!") # For debugging
print(score_read) # For debugging
return best_score2
Every time the player collides with a Rect it adds to the score, in the main game loop that is then passed as 'player_score' to be used in the death screen, there is a loop and other stuff in the function, but i think i have narrowed it down to this part. If more code is need i can add. The thing is it works completely fine if the high score saved in the score_best.txt is higher than the score you just got. In the main loop of code i have it so if you collide with the rect either at the top or the bottom of the screen it will run the function above. If any more information is needed, feel free to ask, as i am running out of ideas.
When the player hits either of the parts that run this function it still detects it and runs the "you have died" print statement but then the actual screen which has been drawn through this function (not shown in the pasted code) doesn't show and just makes the player hit the ground and bounce off.
I removed the line
return best_score2
This fixed the issues.
I am creating a trading game in Python, and want to know how to implement turns without pausing the gameloop. I know that I will have to change the way movement is implemented, but how would I do that?
Note: code can be reached here (May be old): http://pastebin.com/rZbCXk5i
This is usually done with something called a game state machine
What that is, is extremely simple. I can show you with an example.
def main_game_loop():
if state == "player_turn":
# logic for player's turn
elif state == "enemy_turn":
# logic for enemy's turn
# they can also be used for other things, such as where you are in the game
elif state == "paused":
# pause logic etc etc
I am new to programming with Python. I have been working through a tutorial book that I found, and got the game up and running, but then decided I wanted to have a "Play Again?" option at the end. I can get the game to quit out with a press of the "n" key, but cannot work out how to get the game to restart.
Here is the code I think is giving the trouble:
#player reaches treasure
if player_rectangle.colliderect(treasure_rectangle):
#display text
screen.blit(text,(screen_width/2-195,screen_height/2-25))
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_n:
exit()
elif event.key==pygame.K_y:
pygame.display.update()
I know something needs to go after the elif event, and I have tried all that I can think of. I tried to define the whole program, and call it but that stopped the whole thing running. I have looked around internet sites, but just cannot seem to come up with a answer.
Can some one help out in easy terms how to get the game to restart to the starting position when the y key is pressed? I know it has something to do with a loop, I just cannot place my finger on what.
Many thanks.
It's not entirely clear how your code is organized, so I'll be very general. Usually games are implemented with a "main loop" that handles all of the action. In "pseudo"-python:
def main_loop():
while True:
handle_next_action()
draw_screen()
if game_is_over():
break
Before you start the loop, you usually do some setup to get the game state how you want it:
def main():
setup()
main_loop()
shut_down()
Given those parts, you can reset the game by having the main loop code call setup again (it may need to be specifically designed to be runable more than once):
def main_loop():
while True:
handle_events()
draw_screen()
if game_is_over():
if play_again(): # new code here!
setup()
else:
break
You might want to split the setup code into two parts, one which only needs to be run when the program begins (to read configuration files and set up things like the window system), and a second that gets repeated for each new game (setting up the game's state).
To restart a game you normally need to reset all variables to their initial value (e.g. number of lives, score, initial position, ...).
The best way is to put all initialisations inside a procedure:
def init():
global score,lives # use these global variables
score=0
lives=3
init() # call init() to define and reset all values
while 1: # main loop
...
elif event.key==pygame.K_y:
init() # restart the game