mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-25 12:25:10 -08:00
253 lines
9.6 KiB
Python
253 lines
9.6 KiB
Python
import random
|
|
|
|
def main():
|
|
|
|
global colors, color_letters, num_positions, num_colors, human_score, computer_score
|
|
colors = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"]
|
|
color_letters = "BWRGOYPT"
|
|
|
|
num_colors = 100
|
|
human_score = 0
|
|
computer_score = 0
|
|
|
|
# get user inputs for game conditions
|
|
print("Mastermind")
|
|
print('Creative Computing Morristown, New Jersey')
|
|
while (num_colors > 8):
|
|
num_colors = int(input("Number of colors (max 8): ")) # C9 in BASIC
|
|
# TODO no more than 8 colors
|
|
num_positions = int(input("Number of positions: ")) # P9 in BASIC
|
|
num_rounds = int(input("Number of rounds: ")) # R9 in BASIC
|
|
possibilities = num_colors**num_positions
|
|
all_possibilities = [1] * possibilities
|
|
|
|
print("Number of possibilities {}".format(possibilities))
|
|
#TODO tab fixed formatting
|
|
print('Color Letter')
|
|
print('===== ======')
|
|
for element in range(0, num_colors):
|
|
print("{} {}".format(colors[element], colors[element][0]))
|
|
|
|
num_moves = 1
|
|
guesses = []
|
|
current_round = 1
|
|
|
|
while current_round <= num_rounds:
|
|
print('Round number {}'.format(current_round))
|
|
num_moves = 1
|
|
turn_over = False
|
|
print('Guess my combination ...')
|
|
answer = int(possibilities * random.random()) # A in BASIC
|
|
numeric_answer = init_possibility()
|
|
for i in range(0, answer):
|
|
numeric_answer = get_possibility(numeric_answer)
|
|
#debug
|
|
print("{} - {}".format(numeric_answer, make_human_readable(numeric_answer)))
|
|
#human_readable_answer = make_human_readable(numeric_answer)
|
|
while (num_moves < 10 and not(turn_over)):
|
|
print('Move # {} Guess : '.format(num_moves))
|
|
user_command = input('Guess ')
|
|
if user_command == "BOARD":
|
|
print_board(guesses) #2000
|
|
elif user_command == "QUIT":
|
|
quit_game(numeric_answer) #2500
|
|
quit()
|
|
elif len(user_command) != num_positions: #410
|
|
print("BAD NUMBER OF POSITIONS")
|
|
else:
|
|
invalid_letters = get_invalid_letters(user_command)
|
|
if (invalid_letters > ""):
|
|
print("INVALID GUESS: {}".format(invalid_letters))
|
|
else:
|
|
guess_results = compare_two_positions(user_command, make_human_readable(numeric_answer))
|
|
print("Results: {}".format(guess_results))
|
|
if (guess_results[1] == num_positions): # correct guess
|
|
turn_over = True
|
|
print("You guessed it in {} moves!".format(num_moves))
|
|
human_score = human_score + num_moves
|
|
print_score()
|
|
else:
|
|
print("You have {} blacks and {} whites".format(guess_results[1], guess_results[2]))
|
|
num_moves = num_moves + 1
|
|
guesses.append(guess_results)
|
|
if (not(turn_over)): # RAN OUT OF MOVES
|
|
print ("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!")
|
|
print("THE ACTUAL COMBINATION WAS: {}".format(make_human_readable(numeric_answer)))
|
|
human_score = human_score + num_moves
|
|
print_score()
|
|
|
|
# COMPUTER TURN
|
|
turn_over = False
|
|
all_possibilities = [1] * possibilities
|
|
num_moves = 1
|
|
print ("NOW I GUESS. THINK OF A COMBINATION.")
|
|
player_ready = input("HIT RETURN WHEN READY: ")
|
|
while (num_moves < 10 and not(turn_over)):
|
|
foundGuess = False
|
|
computer_guess = int(possibilities * random.random())
|
|
if (all_possibilities[computer_guess] == 1): # random guess is possible, use it
|
|
foundGuess = True
|
|
guess = computer_guess
|
|
else:
|
|
for i in range (computer_guess, possibilities):
|
|
if (all_possibilities[i] == 1):
|
|
foundGuess = True
|
|
guess = i
|
|
break
|
|
if (not(foundGuess)):
|
|
for i in range (0, computer_guess):
|
|
if (all_possibilities[i] == 1):
|
|
foundGuess = True
|
|
guess = i
|
|
break
|
|
if (not(foundGuess)): # inconsistent info from user
|
|
print('YOU HAVE GIVEN ME INCONSISTENT INFORMATION.')
|
|
print('TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.')
|
|
quit()
|
|
# TODO start computer turn over
|
|
else:
|
|
numeric_guess = init_possibility()
|
|
for i in range(0, guess):
|
|
numeric_guess = get_possibility(numeric_guess)
|
|
human_readable_guess = make_human_readable(numeric_guess)
|
|
print('My guess is: {}'.format(human_readable_guess))
|
|
blacks, whites = input("Enter blacks, whites (e.g. 1,2): ").split(",")
|
|
blacks = int(blacks)
|
|
whites = int(whites)
|
|
if (blacks == num_positions): #Correct guess
|
|
print('I GOT IT IN {} moves'.format(num_moves))
|
|
turn_over = True
|
|
computer_score = computer_score + num_moves
|
|
print_score()
|
|
else:
|
|
num_moves += 1
|
|
for i in range (0, possibilities):
|
|
if(all_possibilities[i] == 0): #already ruled out
|
|
continue
|
|
numeric_possibility = init_possibility()
|
|
for j in range (0, i):
|
|
numeric_possibility = get_possibility(numeric_possibility)
|
|
human_readable_possibility = make_human_readable(numeric_possibility) #4000
|
|
comparison = compare_two_positions(human_readable_possibility, human_readable_guess)
|
|
print("{} {} {}".format(human_readable_guess, human_readable_possibility, comparison))
|
|
if ((blacks != comparison[1]) or (whites != comparison[2])):
|
|
all_possibilities[i] = 0
|
|
if (not(turn_over)): # COMPUTER DID NOT GUESS
|
|
print("I USED UP ALL MY MOVES!")
|
|
print("I GUESS MY CPU IS JUST HAVING AN OFF DAY.")
|
|
computer_score = computer_score + num_moves
|
|
print_score()
|
|
current_round += 1
|
|
|
|
def get_invalid_letters(user_command):
|
|
#TODO
|
|
return ""
|
|
|
|
def validate_human_guess(user_input):
|
|
|
|
guess_results = compare_two_positions(user_input, answer)
|
|
return guess_results
|
|
|
|
#2000
|
|
def print_board(guesses):
|
|
print("Board")
|
|
print("Move Guess Black White")
|
|
for guess in guesses:
|
|
print('{} {} {} {}'.format(guess[0], guess[0], guess[1], guess[2]))
|
|
|
|
#2500
|
|
def quit_game(numeric_answer):
|
|
human_readable_answer = make_human_readable(numeric_answer)
|
|
print('QUITTER! MY COMBINATION WAS: {}'.format(human_readable_answer))
|
|
print('GOOD BYE')
|
|
|
|
#3000
|
|
def init_possibility():
|
|
possibility = [0] * num_positions
|
|
return possibility
|
|
|
|
#3500
|
|
def get_possibility(possibility):
|
|
if possibility[0] > 0: #3530
|
|
current_position = 0 # Python arrays are zero-indexed
|
|
while (True):
|
|
if possibility[current_position] < num_colors:
|
|
possibility[current_position] += 1
|
|
return possibility
|
|
else:
|
|
possibility[current_position] = 1
|
|
current_position += 1
|
|
else: #3524
|
|
possibility = [1] * num_positions
|
|
return possibility
|
|
|
|
#4000
|
|
def convert_q_to_a():
|
|
return map_num_to_vals(q, color_letters)
|
|
|
|
#4500
|
|
def compare_two_positions(guess, answer):
|
|
f = 0
|
|
b = 0
|
|
w = 0
|
|
initial_guess = guess
|
|
for pos in range(0, num_positions):
|
|
if (guess[pos] != answer[pos]):
|
|
for pos2 in range(0, num_positions):
|
|
if not(guess[pos] != answer[pos2] or guess[pos2] == answer[pos2]): # correct color but not correct place
|
|
w = w + 1
|
|
answer = answer[:pos2] + chr(f) + answer[pos2+1:]
|
|
guess = guess[:pos] + chr(f+1) + guess[pos+1:]
|
|
f = f + 2
|
|
else: #correct color and placement
|
|
b = b + 1
|
|
# THIS IS DEVIOUSLY CLEVER
|
|
guess = guess[:pos] + chr(f+1) + guess[pos+1:]
|
|
answer = answer[:pos] + chr(f) + answer[pos+1:]
|
|
f = f + 2
|
|
return [initial_guess, b, w]
|
|
|
|
|
|
|
|
|
|
|
|
#5000
|
|
def print_score(is_final_score=False):
|
|
if (is_final_score):
|
|
print("GAME OVER")
|
|
print("FINAL SCORE:")
|
|
else:
|
|
print("SCORE:")
|
|
print(" COMPUTER {}".format(computer_score))
|
|
print(" HUMAN {}".format(human_score))
|
|
|
|
#5500
|
|
def convert_q_to_g():
|
|
return map_num_to_vals(q, g)
|
|
|
|
#6000
|
|
def convert_q_to_h():
|
|
return map_num_to_vals(q, h)
|
|
|
|
#6500
|
|
def copy_g_to_h():
|
|
g = h
|
|
|
|
def make_human_readable(num):
|
|
retval = ''
|
|
for z in range(0, len(num)):
|
|
retval = retval + color_letters[int(num[z])]
|
|
return retval
|
|
|
|
|
|
def map_num_to_vals(num, v):
|
|
retval = ''
|
|
print(len(num))
|
|
for z in range(0, len(num)):
|
|
print(num[z])
|
|
print(v[int(num[z])])
|
|
retval = retval + v[int(num[z])]
|
|
return retval
|
|
|
|
if __name__ == "__main__":
|
|
main() |