Alternating between players in a connect four python game - python

I'm currently writing a function to play Connect Four in Python3. I've progressed well through much of it but am having trouble alternating between two players.
What I'm trying to do is run a function that will place a chip in the appropriate location as a function of the current player, playturn(curr). So what I'm trying to say is that while there's no tie and while there's no winner, the game will continue and alternate between the two players.
If it's Player 1's turn, curr=1, and if it's Player 2's turn, curr=2.
My current code isn't working, as it won't allow me to switch between players after each turn if there's no tie or no winner. My logic here was that if curr=1 is initially 1, then I'll have to set curr=2 after the first move. Then, when curr=2, I have to switch curr equal back to 1. In the following code, checkforwinner and checkfortie are two functions that will return False if there is no winner and if there is no tie. playturn(curr) will place a chip in the correct column depending on the column chosen by either Player1 or Player2.
curr=1
while checkforwinner==False and checkfortie==False:
if curr==1:
curr==2
print(playturn(curr))
if curr==2:
curr==1
print(playturn(curr))
Can someone explain why this code is not working and what can be done to fix it?

curr==2 is a comparison. You probably want curr=2. The second if should be an elif.

There are a couple ways to make this nicer!
To make your original code work, you should use jspcal's recommendation to turn the comparison operators (==) to assignment operators (=).
You also need to use an elif for the second comparison, or every single loop will switch the player twice.
curr=1
while not (checkforwinner() or checkfortie()):
if curr==1:
curr=2
print(playturn(curr))
elif curr==2:
curr=1
print(playturn(curr))
You can also clean up the code a little:
def switch_player(current_player):
if current_player == 1:
return 2
elif current_player == 2:
return 1
while not (checkforwinner() or checkfortie()):
print(playerturn(curr))
curr = switch_player(curr)
The last version you might go with is the shortest, but is a little harder to read:
while not (checkforwinner() or checkfortie()):
print(playerturn(curr))
curr = 1 if curr == 2 else 2

If checkforwinner and checkfortie are functions, you need parenthesis after them:
while checkforwinner()==False and checkfortie()==False:
Also, as #jspcal pointed out, you want to assign values with a single '=' and only use '==' for boolean comparison.

Related

Having trouble solving this problem recursively

Assume we are given a string variable named word.
We are playing a game with 2 players, player A, and player B.
Each player, at their respective turn (with player A always beginning), chooses either the first or the last letter of the string and gets points based on the ordered count of that letter in the ABC (i.e. a = 1, b = 2, c = 3 and so on, so it's ord(char) - 96 in python). Then the other player is given the same string but without the letter that was chosen.
At the end of the game, whoever has the most points wins.
We are given that player B's strategy is a greedy strategy, meaning he will always choose the best option from the current given options (so if the word was "abc" he would choose the letter "c" because it's better for him at the moment).
We define a string to be "good" if no matter what player A picks in his turn, at any given point in the game, player B will always win.
Need: I need to create a function that recursively finds whether a word is considered "good" (returns True), and if not it returns False.
Restriction: The only allowed input is the word, so the function would look like: is_word_good(word).
If needed, memoization is allowed.
I tried wrapping my head around this problem but I am having difficulties solving it recursively, specifically, I cannot find a way to efficiently pass/save the cumulative score between the function calls. Maybe I'm missing something that makes the problem simpler.
I would've added a code but I kept deleting my ideas and trying to redo them. My main idea was to (maybe) save using memoization every word and the respective score each player can get at that word, and the score will depend on the chosen letter currently + recursion of chosen letters later on in the recursion. I failed to implement it correctly (let alone efficiently).
Example of expected outputs:
>>> is_word_good("abc")
False
>>> is_word_good("asa")
True
Help would be appreciated!
It is usual for such problem to have a "wrapper" function, with only parameters for the problem, here it would be :
def is_word_good(word: str) -> bool:
...
But this function can use other functions. For example, you can create a "solver" method with many more parameters (about the current state of the solution) :
def _solving__is_word_good(current_word: str, player_A_points: int, player_B_points: int, player_turn) -> bool:
...
So that your main ("wrapper") function will just do :
return _solving__is_word_good(
current_word=word,
player_A_points=0,
player_B_points=0,
player_turn=A,
)
And this second function will do the heavy lifting (and could be memoized, look for functools.lru_cache).

Trouble understanding break vs else statements with nested loops

I'm practicing python and one of the coding tasks assigned was to create a function that looks through a list and ignores numbers that occur between a 6 and a 9 and returns the sum of all other values.
Edit: this does not mean to add numbers whose values are less than 6 or greater than 9. It means to add all numbers of any value, but to ignore any numbers that come after a 6, until a 9 is seen. Symbolically if i means include and x means exclude, the code should return all the values marked as i:
[i,i...6, x,x,...,9,i,i...,6,x,x,...]
In other words, 6 turns off adding and if adding is off, 9 turns it back on.
Note that a 9 with no preceding 6 is just a number and will be added.
For example if I have a list:
[4,5,6,7,8,9,9]
the output should be:
8 <---(4+5+9)
The solution is provided but I'm having trouble understanding the code. I don't understand the purpose of the break statements in the code. The solution provided is as follows:
def summer_69(*arr):
total = 0
add = True
for num in arr:
while add == True:
if num!=6:
total = total + num
break
else:
add = False
while add == False:
if num !=9:
break
else:
add = True
break
return total
I'm really confused how the break statements help with the code. Particularly, I'm confused why the first 'break' is needed when there is already an 'else'.
The second break confuses me as well.
I understand that 'break' statements stop a loop and go onto the next loop.
My interpretation of the code so is 'if the number does not equal to 6 then total = total + num, if it does equal 6 then the loop is broken and if it is broken, add changes to False'.
I'm not sure if that interpretation is correct or not.
I was wondering how seasoned Python coders interpret 'breaks' vs 'else'.
break will exit whatever loop the statement is in. It's useful for many things, but often it's used to "short-circuit" the loop. If we know that the rest of the loop is irrelevant after some condition is met, then it's just wasted resources to keep looping through.
The break statement allow you to leave the while loop, but the if else statement allow you to stay in loop, until the condition of the while loop change or a break statement is in the action into the while loop
The solution you've provided is extremely convoluted and hard to understand.
A much better solution is:
total = 0
for num in arr_2:
if(num >= 6 and num <=9):
continue
total += num
Or a more pythonic way:
filtered_arr = filter(lambda x: x <6 or x > 9, arr_2)
total = reduce(lambda x, y: x + y, arr)
Anyways, in your solution, the first break is absolutely redundant. The reason why there is a break there, is because when you've found a number that doesn't equal 6, you add it, and you get out of the while loop.
In other words, the solution should have used an if statement, instead of the while statement. The break is there to basically have the while loop execute once.
Because, if a number does equal 6, then add will be false, and the while loop will terminate. If a number does not equal 6, you get out of the while loop. So the while loop is pointless, and meant to be an if statement instead.
This is a tricky way to handle program flow with a toggle nested in conditional loops.
It's a little hard to follow, but it is a well-known classic pattern.
Initially ADD == True, so if we start with a number that is not 6 (as in your example), the algorithm adds the number & breaks out of the first while loop. When it breaks, the next statement executed will be the line while add == False
At this point ADD == TRUE so the second while loop will not be entered. The next statement executed will be for num in arr (the outermost loop).
The outer FOR loop will go again and this process will repeat.
When you encounter a 6, the number will not be added and the break will not occur. The program will execute the else clause, setting ADD = FALSE.
After the else clause, execution continues with statement while add == false. Since ADD == FALSE at this point, the second while loop will be entered.
From now on ADD will be FALSE so the first While loop will not be entered and numbers will not be added. Instead, the condition for the second while loop will be evaluated for each number. As long as numbers are not equal to 9, the second while loop will not be entered.
When you encounter a 9, you will enter the second while loop, switch ADD back to TRUE, and break out of the while loop.
The first 9 comes after a 6 (ADD is FALSE) so it just toggles ADD from FALSE to TRUE and the number 9 doesn't get added.
When the NEXT 9 is encountered, ADD is TRUE and the number is not 6, so the first while loop will be entered and the number 9 will get added.
This is a classic pattern that used to be used in assembly language code perhaps 40 years ago. As written, the IF statements toggle a state variable. The state variable is turned on when the start condition is met, and turned off when a stop condition is met. The while loops ensure that the toggle can only be turned ON when it was OFF and vice versa, and provide places to put in different handling when the state is ON vs when it is OFF. This pattern brings certain efficiencies that are completely irrelevant in modern high-level languages.
There are better ways to do this in all modern languages, but as an exercise in following tricky program flow it's quite good :)

Adding more values to a key in a dictionary without overwriting the existing value

I am creating a bingo game where the user is guessing on five numbers and the computer takes out ten random numbers between 1-26.
The part I am having trouble with is that when the user have guessed, the numbers have been compared and added to the dictionary. If I then play the "game" once more it overwrites the last rounds points (which I want to keep).
def user_vs_cpu(cpu_random):
global players
for player in players:
correct_guess = 0
for guess in player["guess"]:
for bingo_number in cpu_random:
if guess == bingo_number:
correct_guess += 1
player["points"] = {correct_guess}
print(players)
players is a list that contains the dictionaries.
cpu_random is the computer's randomly generated numbers.
player["points"] is where the compared points is stored.
-edit-
I forgot to mention is that there is more dicts in the list players so that i can add more players to the game.
With player["points"] = {correct_guess} you're correct_guess variable turns into a set object due to the curly braces. You could then operate with this object according to PythonDocs Set Types. That's not what you want. Like suggested try to work with a list with append or use an integer if only the current points are important, this would be for example:
player["points"] += 1
See also 'PythonDocs Data Structures'
Suggestion: Try to get familiar with a good IDE like PyCharm, set a BreakPoint to player["points"] = {correct_guess} and see where you going wrong (you will be able to see the state of all variables/objects simultaneously.

Having trouble with a lab assignment (Using lists and integers)

Our lab assignment this week is to make a simple version of blackjack running in Python 3. I've got most of the assignment finished but I'm having trouble with the part where I need to determine points for each card. Here's a mockup of my code for the segment I'm stuck on.
def score(playerhand, comhand):
playerscore = 0
comscore = 0
for i in playerhand:
if playerhand == str('A'):
playerscore += int(11)
elif playerhand == str('J'):
playerscore += int(10)
elif playerhand == str('Q'):
playerscore += int(10)
elif playerhand == str('K'):
playerscore += int(10)
else:
playerscore += int(playerhand) #This is where it breaks
Playerhand is a list that will contain 2 or 3 random strings between 1-10, or A, J, Q, or K (These are aces and face cards). As it stands, I can't think of a simple way to convert the value of playerhand to an integer without making a bunch of elif statements to convert every string to its integer counterpart. I can't use playerhand[x] since the for loop is going to loop through every value in playerhand anyway. I've been at this for a while, if anyone can throw some help, I'd really appreciate it.
First of all, you are misusing playerhand inside the loop. Given the loop expression for i in playerhand, i represents a single element of the list. So inside the loop, you should be using i instead of playerhand to refer to the current element. playerhand still refers to the entire list.
With that change, the solution you have of calling int() may work fine. A better overall solution would be using a dictionary as already suggested in a comment, but given that this is a lab assignment, it may be intended for you to use only certain data structures.
Another solution would be to have a list that contains all the possible strings, and a second list of the same length that contains the corresponding scores. Find a given string in the first list, then find the element of the second list at the same position, and that is the score.
The problem within the given text of code I see straight away is using playerhand rather than i; for i represents each value of playerhand in sequential order from the beginning of the list.
Everything else seems as though it'd work fine, nevertheless using a dictionary may be a good way to go as well. Though since you're doing this as a lab assignment, that may be more than what your teacher is looking for.

Python leave multiple if statements [duplicate]

This question already has answers here:
"if", and "elif" chain versus a plain "if" chain
(2 answers)
Closed 8 years ago.
grid = 0
if grid == 0:
grid == 1
print("grid 0")
elif grid == 1:
print("grid 1")
grid == 2
When first if statement is true, the second will become true as well.
Is there a statement, to skip the whole if structure otherwise i would have to split the if functions which would double the if statements.
First of all, grid == 1 will not change the value of grid; it's only comparing it to 1, obtaining a boolean value and then immediately throwing it away by not using it. To change the value of a variable, you need to use the assignment operator = (as opposed to the equality comparison operator ==): for example grid = 1.
Also, there's nothing bad with using more if-s it it makes sense. In fact, I would recommended making your program work with as simple and straightforward logic as possible first before trying to "optimize" it or make it more compact.
Also, I would say modifying the value of a variable WHILE you are in the process of testing that variable using a chain of if-elif-else, is considered bad style because it makes your code more complicated and hard to reason about (to yourself and to others).
And in any case, if the first if "fails", any subsequent elifs will not even be looked at, so basically you're forced to use multiple ifs anyway in this case.
As a bonus to get you inspired (and maybe even start reading something like http://learnpythonthehardway.org), here's a demonstration of how = and == could also be used together:
# set `is_wet` to `True` if `precipitation` is "raining", otherwise `False
is_wet = (precipitation == "raining")
The second statement will be skipped alone because you used elif instead of a second if.
if condition_a:
statement_a
elif condition_b:
statement_b:
else:
default_statement
Only one of these conditions will EVER activate. In the case of:
if i > 1:
do_stuff
elif i > 1000:
do_bigger_stuff
if i==2000, only the first statement will execute (do_stuff, not do_bigger_stuff)
Be aware in your example that grid == 1 will not set grid to 1, it will just evaluate False :)

Categories

Resources