Mastermind Python Using "ABCDEF" - python-3.x

Mastermind Game using "ABCEF"I dont know how to check whether it is partial correct. I have to use red to mean correct letter and position. I use white to mean correct letter.
import random
def play_one_round():
N_code=''.join(random.sample("ABCDEF",4))
print (N_code)
guess=input("Enter your guess as 4 letters e.g. XXXX:")
count_guess= 1
while N_code != guess and count_guess < 10:
check(N_code,guess)
guess=input("Enter your guess as 4 letters e.g. XXXX:")
count_guess=count_guess + 1
print("This is your",count_guess, "guess")
if guess==N_code:
print('r') #Here I have if the code and guess are equal print r, which mean its the right letters in the right order.
def check(N_code,guess):
result=['r' if c1==c2 else c2 for c1,c2 in zip(guess, N_code)]
for index, char in enumerate(guess):
if result[index] !='r':
if char in result:
result[result.index(char)]='w'
print(result)
def Master_m():
print("Welcome to Mastermind!\n")
print("Start by Choosing four letters")
play_one_round()
answer=input("Play Again? ")
if answer[0]=='y':
Master_m()
Master_m()

I wrote this ages ago but it will do the trick
import random
import itertools
def start():
""" this function is used to initialise the users interaction with the game
Primarily this functions allows the user to see the rules of the game or play the game"""
print ('Mastermind, what would you like to do now?\n')
print ('Type 1 for rules')
print ('Type 2 to play')
path = input('Type your selection 1 or 2: ')
if path == '1':
print ('Great lets look at the rules')
rules()
elif path == '2':
print('Great lets play some Mastermind!\n')
begingame()
start()
else:
print('that was not a valid response there is only one hidden option that is not a 1 or a 2')
start()
def rules():
"""This just prints out the rules to the user."""
print ('The rules are as follows:\n')
print ('1)Mastermind will craft you a 4 digit number that will contain all unique numbers from 1-9, there is no 0s.\n')
print ('2)You will have 12 attempts to guess the correct number.\n')
print ('3)Whites represent a correct number that is not in the correct order\n')
print ('4)Reds represent a correct number in the correct order.\n')
print ('5)If you enter a single number or the same number during a guess it will consume 1 of your 12 guesses.\n')
print ('6)to WIN you must guess the 4 numbers in the correct order.\n')
print ('7)If you run out of guesses the game will end and you lose.\n')
print ('8)if you make a guess that has letters or more than 4 digits you will lose a turn.')
start()
def makeRandomWhenGameStarts():
"""A random 4 digit number is required this is created as its own
variable that can be passed in at the start of the game, this allows the user
to guess multiple times against the one number."""
#generate a 4 digit number
num = random.sample(range(1,9), 4)
#roll is the random 4 digit number as an int supplied to the other functions
roll = int(''.join(map(str,num)))
return roll
def begingame():
"""This is the main game function. primarily using the while loop, the makeRandomWhenGameStarts variable is
passed in anbd then an exception handling text input is used to ask the user for their guees """
print ('please select 4 numbers')
#bring in the random generated number for the user to guess.
roll = makeRandomWhenGameStarts()
whiteResults = []
redResults = []
collectScore = []
guessNo = 0
#setup the while loop to end eventually with 12 guesses finishing on the 0th guess.
guesses = 12
while (guesses > 0 ):
guessNo = guessNo + 1
try:
#choice = int(2468) #int(input("4 digit number"))
choice = int(input("Please try a 4 digit number: "))
if not (1000 <= choice <= 9999):
raise ValueError()
pass
except ValueError:
print('That was not a valid number, you lost a turn anyway!')
pass
else:
print ( "Your choice is", choice)
#Use for loops to transform the random number and player guess into lists
SliceChoice = [int(x) for x in str(choice)]
ranRoll = [int(x) for x in str(roll)]
#Take the individual digits and assign them a variable as an identifier of what order they exist in.
d1Guess = SliceChoice[0:1]
d2Guess = SliceChoice[1:2]
d3Guess = SliceChoice[2:3]
d4Guess = SliceChoice[3:4]
#combine the sliced elements into a list
playGuess = (d1Guess+d2Guess+d3Guess+d4Guess)
#Set reds and whites to zero for while loop turns
nRed = 0
nWhite = 0
#For debugging use these print statements to compare the guess from the random roll
# print(playGuess, 'player guess')
# print(ranRoll,'random roll')
#Use for loops to count the white pegs and red pegs
nWhitePegs = len([i for i in playGuess if i in ranRoll])
nRedPegs = sum([1 if i==j else 0 for i, j in zip(playGuess,ranRoll)])
print ('Oh Mastermind that was a good try! ')
#Take the results of redpegs and package as turnResultsRed
TurnResultsRed = (nRedPegs)
#Take the results of whitepegs and remove duplication (-RedPegs) package as TurnResultsWhite
TurnResultsWhite = ( nWhitePegs - nRedPegs) #nWhite-nRed
#Create a unified list with the first element being the guess number
# using guessNo as an index and storing the players choice and results to feedback at the end
totalResults = ( guessNo,choice , TurnResultsWhite ,TurnResultsRed)
# collectScore = collectScore + totalResults for each turn build a list of results for the 12 guesses
collectScore.append(totalResults)
#End the while loop if the player has success with 4 reds
if nRed == (4):
print('Congratulations you are a Mastermind!')
break
#Return the results of the guess to the user
print ('You got:',TurnResultsWhite,'Whites and',TurnResultsRed,'Red\n')
#remove 1 value from guesses so the guess counter "counts down"
guesses = guesses -1
print ('You have', guesses, "guesses left!")
#First action outside the while loop tell the player the answer and advise them Game Over
print('Game Over!')
print('The answer was', roll)
#At the end of the game give the player back their results as a list
for x in collectScore:
print ('Guess',x[0],'was',x[1],':','you got', x[2],'Red','and', x[3],'Whites')
if __name__ == '__main__':
start()

When you are stuck, decompose into smaller chunks and test those. Focusing on check, you can check whether a guess letter exactly matches the code via its index and whether its in the code at all with in. Here is a self-contained example. Notice that I've pulled out everything except the problem at hand.
If this works for you, I suggest writing a self-contained example of your next problem, test it, and if you are still stuck, post that as a new question.
def check(N_code, guess):
print('code', N_code, 'guess', guess)
result = []
# enumerate gives you each letter and its index from 0
for index, letter in enumerate(guess):
if N_code[index] == letter:
# right letter in right position
vote = 'red'
elif letter in N_code:
# well, at least the letter is in the code
vote = 'white'
else:
# not even close
vote = 'black'
# add partial result
result.append('{} {}'.format(letter, vote))
# combine and print
print(', '.join(result))
check('ABCD', 'ABCD')
check('DEFA', 'ABCD')

Related

Just started python and working through Automate The Boring Stuff with Python. Any recommendations on cleaning my code?

New here at stackoverflow. I'm learning python right now and picked up the book Automate the Boring Stuff with Python. Need some recommendations or tips on how to clean up my code. Here is one of the small projects from the book:
Write a function named collatz() that has one parameter named number. If number is even, then collatz() should print number // 2 and return this value. If number is odd, then collatz() should print and return 3 * number + 1. Then write a program that lets the user type in an integer and that keeps calling collatz() on that number until the function returns the value 1.
The output of this program could look something like this:
Enter number:
3
10
5
16
8
4
2
1
Here's the code I came up with. Any recommendations on cleaning up the code or is this good enough? Thank you all!
def collatz(number):
if number % 2 == 0: # Even numbers
print(number // 2)
return number // 2
elif number % 2 == 1: # Odd numbers
result = 3 * number + 1
print(result)
return result
while True: # Made a loop until a number is entered
try:
n = input("Enter a random number: ")
while n != 1:
n = collatz(int(n))
break
except ValueError:
print("Enter numbers only.")
Use else in the place of elif , it will give same reasult.
Optimized for readability and usage, not on performance.
def collatz(number):
print(n)
return number // 2 if number % 2 == 0 else 3 * number + 1
while True: # Made a loop until a number is entered
try:
n = input("Enter a random number: ")
while n != 1: n = collatz(int(n))
break
except ValueError: print("Enter numbers only.")

Python Collatz Infinite Loop

Apologies if similar questions have been asked but I wasn't able to find anything to fix my issue. I've written a simple piece of code for the Collatz Sequence in Python which seems to work fine for even numbers but gets stuck in an infinite loop when an odd number is enter.
I've not been able to figure out why this is or a way of breaking out of this loop so any help would be greatly appreciate.
print ('Enter a positive integer')
number = (int(input()))
def collatz(number):
while number !=1:
if number % 2 == 0:
number = number/2
print (number)
collatz(number)
elif number % 2 == 1:
number = 3*number+1
print (number)
collatz(number)
collatz(number)
Your function lacks any return statements, so by default it returns None. You might possibly wish to define the function so it returns how many steps away from 1 the input number is. You might even choose to cache such results.
You seem to want to make a recursive call, yet you also use a while loop. Pick one or the other.
When recursing, you don't have to reassign a variable, you could choose to put the expression into the call, like this:
if number % 2 == 0:
collatz(number / 2)
elif ...
This brings us the crux of the matter. In the course of recursing, you have created many stack frames, each having its own private variable named number and containing distinct values. You are confusing yourself by changing number in the current stack frame, and copying it to the next level frame when you make a recursive call. In the even case this works out for your termination clause, but not in the odd case. You would have been better off with just a while loop and no recursion at all.
You may find that http://pythontutor.com/ helps you understand what is happening.
A power-of-two input will terminate, but you'll see it takes pretty long to pop those extra frames from the stack.
I have simplified the code required to find how many steps it takes for a number to get to zero following the Collatz Conjecture Theory.
def collatz():
steps = 0
sample = int(input('Enter number: '))
y = sample
while sample != 1:
if sample % 2 == 0:
sample = sample // 2
steps += 1
else:
sample = (sample*3)+1
steps += 1
print('\n')
print('Took '+ str(steps)+' steps to get '+ str(y)+' down to 1.')
collatz()
Hope this helps!
Hereafter is my code snippet and it worked perfectly
#!/usr/bin/python
def collatz(i):
if i % 2 == 0:
n = i // 2
print n
if n != 1:
collatz(n)
elif i % 2 == 1:
n = 3 * i + 1
print n
if n != 1:
collatz(n)
try:
i = int(raw_input("Enter number:\n"))
collatz(i)
except ValueError:
print "Error: You Must enter integer"
Here is my interpretation of the assignment, this handles negative numbers and repeated non-integer inputs use cases as well. Without nesting your code in a while True loop, the code will fail on repeated non-integer use-cases.
def collatz(number):
if number % 2 == 0:
print(number // 2)
return(number // 2)
elif number % 2 == 1:
result = 3 * number + 1
print(result)
return(result)
# Program starts here.
while True:
try:
# Ask for input
n = input('Please enter a number: ')
# If number is negative or 0, asks for positive and starts over.
if int(n) < 1:
print('Please enter a positive INTEGER!')
continue
#If number is applicable, goes through collatz function.
while n != 1:
n = collatz(int(n))
# If input is a non-integer, asks for a valid integer and starts over.
except ValueError:
print('Please enter a valid INTEGER!')
# General catch all for any other error.
else:
continue

how to make a variable decrease by one everytime a loop rolls?

this might seem very basic to you, and I think I know what is wrong with my code, I just can't seem to figure out how to fix. Basically, I am building a very simple hangman game, and I want to make the user lose a life every time he guesses a letter wrong. Here is the code:
import random
word_choice = ["list", "microsoft", "cars", "philosophy", "mother", "powder", "star", "baby", "elephant"]
guessed_letters = []
right_guessed_letters = []
def user_turn(c):
lives = 10
while True:
guess = input("\nGuess a letter or a word: ")
guessed_letters.append(guess)
print ("\n")
if lives != 0 and guess != comp_choice:
if guess in comp_choice:
right_guessed_letters.append(guess)
for i in comp_choice:
if i in right_guessed_letters:
print (i, end= ' ')
else:
print ('-', end = ' ')
else:
lose_life(lives)
continue
elif guess == comp_choice:
print ("Good job, you guessed the word correctly!")
break
elif lives == 0:
print ("You lost, your lives are all depleated...")
break
def lose_life(l):
l -= 1
print (f'Wrong letter, you have {l} lives remaining')
print (f"The letters you already guessed are {guessed_letters}")
comp_choice = random.choice(word_choice)
word = '-' * len(comp_choice)
print (f"Your word is : {word} long.")
user_turn(comp_choice)
Basically, my problem is that the user can only lose one life. In fact, I would like that every time lose_life is called, the user loses a life so his lives decrease by one every time, however the variable lives gets it's original value right after the function is done rolling. So every time the function is called, the user is at nine lives. Here is the output:
microsoft
Your word is : --------- long.
Guess a letter or a word: d
Wrong letter, you have 9 lives remaining
The letters you already guessed are ['d']
Guess a letter or a word: e
Wrong letter, you have 9 lives remaining
The letters you already guessed are ['d', 'e']
Guess a letter or a word:
Anyways, If you could help, it would be very appreciated!
Your lose_life function is not returning anything, so all it effectively does is printing the two statements.
if you added a return l at the end of lose_life function, and change your lose_life(lives) in the else statement to lives = lose_life(lives), it should now work.
If this seems cumbersome and you're feeling adventurous, you may consider using Classes instead:
class Live(object):
def __init__(self, value=10):
self.value = value
def __str__(self):
return str(self.value)
def __repr__(self):
return self.__str__()
def lose(self):
self.value -= 1
print(f'Wrong letter, you have {self.value} lives remaining')
print(f"The letters you already guessed are {guessed_letters}")
def gain(self):
self.value += 1
# insert your own print messages if you wish.
Mind you I wouldn't recommend doing it for this use case (KISS principal applies), but for more complex projects where you have objects that need their own attributes and functions, Classes are great for that purpose.

Count iterations in a loop

New to programming. How to count and print iterations(attempts) I had on guessing the random number?` Let's say, I guessed the number from 3-rd attempt.
import random
from time import sleep
str = ("Guess the number between 1 to 100")
print(str.center(80))
sleep(2)
number = random.randint(0, 100)
user_input = []
while user_input != number:
while True:
try:
user_input = int(input("\nEnter a number: "))
if user_input > 100:
print("You exceeded the input parameter, but anyways,")
elif user_input < 0:
print("You exceeded the input parameter, but anyways,")
break
except ValueError:
print("Not valid")
if number > user_input:
print("The number is greater that that you entered ")
elif number < user_input:
print("The number is smaller than that you entered ")
else:
print("Congratulation. You made it!")
There are two questions being asked. First, how do you count the number of iterations? A simple way to do that is by creating a counter variable that increments (increases by 1) every time the while loop runs. Second, how do you print that number? Python has a number of ways to construct strings. One easy way is to simply add two strings together (i.e. concatenate them).
Here's an example:
counter = 0
while your_condition_here:
counter += 1 # Same as counter = counter + 1
### Your code here ###
print('Number of iterations: ' + str(counter))
The value printed will be the number of times the while loop ran. However, you will have to explicitly convert anything that isn't already a string into a string for the concatenation to work.
You can also use formatted strings to construct your print message, which frees you from having to do the conversion to string explicitly, and may help with readability as well. Here is an example:
print('The while loop ran {} times'.format(counter))
Calling the format function on a string allows you replace each instance of {} within the string with an argument.
Edit: Changed to reassignment operator

Using the random function in Python for Evil Hangman

What I am trying to do is alter my original hangman game into what is called evil hangman. In order to do this, I need to first generate a random length of a word and pull out all words of that length from the original list.
Here is the code I am working with:
def setUp():
"""shows instructions, reads file,and returns a list of words from the english dictionary"""
try:
print(60*'*' +'''\n\t\tWelcome to Hangman!\n\t
I have selected a word from an english dictionary. \n\t
I will first show you the length of the secret word\n\t
as a series of dashes.\n\t
Your task is to guess the secret word one letter at a time.\n\t
If you guess a correct letter I will show you the guessed\n\t
letter(s) in the correct position.\n
You can only make 8 wrong guesses before you are hanged\n
\t\tGood luck\n''' + 60*'*')
infile=open('dictionary.txt')
l=infile.readlines()# list of words from which to choose
infile.close()
cleanList = []
for word in l:
cleanList.append(l[:-1])
return(cleanList)
except IOError:
print('There was a problem loading the dictionary file as is.')
def sort_dict_words_by_length(words):
"""Given a list containing words of different length,
sort those words based on their length."""
d = defaultdict(list)
for word in words:
d[len(word)].append(word)
return d
def pick_random_length_from_dictionary(diction):
max_len, min_len = ( f(diction.keys()) for f in (max, min) )
length = random.randint(min_len, max_len)
return diction[length]
def playRound(w,g):
""" It allows user to guess one letter. If right,places letter in correct positions in current guess string g, and shows current guess to user
if not, increments w, number of wrongs. Returns current number of wrongs and current guess string"""
print('You have ' + str(8 - w) + ' possible wrong guesses left.\n')
newLetter = input('Please guess a letter of the secret word:\n')
glist = list(g)#need to make changes to current guess string so need a mutable version of it
if newLetter in secretWord:
for j in range (0,len(secretWord)):
if secretWord[j]==newLetter:
glist[j] = newLetter
g = ''.join(glist)#reassemble the guess as a string
print('Your letter is indeed present in the secret word: ' + ' '.join(g)+'\n')
else:
w += 1
print('Sorry, there are no ' + newLetter + ' in the secret word. Try again.\n')
return(w,g)
def endRound(wr, w,l):
"""determines whether user guessed secret word, in which case updates s[0], or failed after w=8 attempts, in s\which case it updates s[1]"""
if wr == 8:
l += 1
print('Sorry, you have lost this game.\n\nThe secret word was '+secretWord +'\n')#minor violation of encapsulation
else:
w +=1
print(15*'*' + 'You got it!' + 15*'*')
return(w,l)
def askIfMore():
"""ask user if s/he wants to play another round of the game"""
while True:
more = input('Would you like to play another round?(y/n)')
if more[0].upper() == 'Y' or more[0].upper()=='N':
return more[0].upper()
else:
continue
def printStats(w,l):
"""prints final statistics"""
wGames='games'
lGames = 'games'
if w == 1:
wGames = 'game'
if l ==1:
lGames = 'game'
print('''Thank you for playing with us!\nYou have won {} {} and lost {} {}.\nGoodbye.'''.format(w,wGames,l,lGames))
try:
import random
from collections import defaultdict
words=setUp()#list of words from which to choose
won, lost = 0,0 #accumulators for games won, and lost
while True:
wrongs=0 # accumulator for wrong guesses
secretWord = random.choice(words)[:#eliminates '\n' at the end of each line
print(secretWord) #for testing purposes
guess= len(secretWord)*'_'
print('Secret Word:' + ' '.join(guess))
while wrongs < 8 and guess != secretWord:
wrongs, guess = playRound(wrongs, guess)
won, lost = endRound(wrongs,won,lost)
if askIfMore()== 'N':
break
printStats(won, lost)
except:
quit()
What I would like to do is generate a random number with the lower bound being the shortest length word and the upper bound being the highest length word, and then use that random number to create a new container with words of only that length, and finally returning that container to be used by the game further. I tried using min and max, but it seems to only return the first and last item of the list instead of showing the word with the most characters. Any help is appreciated.
If your 'dictionary.txt' has a single word on each line, you could use the following, which is speed efficient, because it'll only go over the list once. But it'll consume the memory of your original list again.
from collections import defaultdict
import random
def sort_dict_words_by_length(words):
"""Given a list containing words of different length,
sort those words based on their length."""
d = defaultdict(list)
for word in words:
d[len(word)].append(word)
return d
def pick_random_length_from_dictionary(diction):
max_len, min_len = ( f(diction.keys()) for f in (max, min) )
length = random.randint(min_len, max_len)
return diction[length]
You would then pass the output from your setUp to sort_dict_words_by_length and that output to pick_random_length_from_dictionary.
If you are memory-limited, then you should first go over all words in the wordlist, keeping track of the minimal and maximal length of those words and then reiterate over that wordlist, appending only those words of the desired length. What you need for that is mentioned in the code above and just requires some code reshuffling. I'll leave that up to you as an exercise.

Resources