mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-23 15:37:51 -08:00
Refactoring of the #get_possibility and #make_human_readable methods into one method, #possibility_to_color_code, that just converts a solution permutation (out of the possible permutations) straight into a string code of letters.
Both of these methods are essentially a flow of the first method being fed into the second and thus they are combined and the intermediate data structure (List[int]) is no longer needed.
This commit is contained in:
@@ -6,7 +6,7 @@ from typing import List, Union
|
|||||||
colors = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"]
|
colors = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"]
|
||||||
color_letters = "BWRGOYPT"
|
color_letters = "BWRGOYPT"
|
||||||
num_positions = 0
|
num_positions = 0
|
||||||
num_colors = 100
|
num_colors: int = 100
|
||||||
human_score = 0
|
human_score = 0
|
||||||
computer_score = 0
|
computer_score = 0
|
||||||
|
|
||||||
@@ -44,21 +44,16 @@ def main() -> None:
|
|||||||
guesses: List[List[Union[str, int]]] = []
|
guesses: List[List[Union[str, int]]] = []
|
||||||
turn_over = False
|
turn_over = False
|
||||||
print("Guess my combination ...")
|
print("Guess my combination ...")
|
||||||
answer = int(possibilities * random.random())
|
secret_combination = int(possibilities * random.random())
|
||||||
|
answer = possibility_to_color_code(secret_combination)
|
||||||
numeric_answer = [-1] * num_positions
|
numeric_answer = [-1] * num_positions
|
||||||
for _ in range(0, answer + 1):
|
|
||||||
numeric_answer = get_possibility(numeric_answer)
|
|
||||||
# human_readable_answer = make_human_readable(numeric_answer, color_letters)
|
|
||||||
while num_moves < 10 and not turn_over:
|
while num_moves < 10 and not turn_over:
|
||||||
print(f"Move # {num_moves} Guess : ")
|
print(f"Move # {num_moves} Guess : ")
|
||||||
user_command = input("Guess ")
|
user_command = input("Guess ")
|
||||||
if user_command == "BOARD":
|
if user_command == "BOARD":
|
||||||
print_board(guesses) # 2000
|
print_board(guesses) # 2000
|
||||||
elif user_command == "QUIT": # 2500
|
elif user_command == "QUIT": # 2500
|
||||||
human_readable_answer = make_human_readable(
|
print(f"QUITTER! MY COMBINATION WAS: {answer}")
|
||||||
numeric_answer, color_letters
|
|
||||||
)
|
|
||||||
print(f"QUITTER! MY COMBINATION WAS: {human_readable_answer}")
|
|
||||||
print("GOOD BYE")
|
print("GOOD BYE")
|
||||||
quit()
|
quit()
|
||||||
elif len(user_command) != num_positions: # 410
|
elif len(user_command) != num_positions: # 410
|
||||||
@@ -68,9 +63,7 @@ def main() -> None:
|
|||||||
if invalid_letters > "":
|
if invalid_letters > "":
|
||||||
print(f"INVALID GUESS: {invalid_letters}")
|
print(f"INVALID GUESS: {invalid_letters}")
|
||||||
else:
|
else:
|
||||||
guess_results = compare_two_positions(
|
guess_results = compare_two_positions(user_command, answer)
|
||||||
user_command, make_human_readable(numeric_answer, color_letters)
|
|
||||||
)
|
|
||||||
print(f"Results: {guess_results}")
|
print(f"Results: {guess_results}")
|
||||||
if guess_results[1] == num_positions: # correct guess
|
if guess_results[1] == num_positions: # correct guess
|
||||||
turn_over = True
|
turn_over = True
|
||||||
@@ -87,11 +80,7 @@ def main() -> None:
|
|||||||
guesses.append(guess_results)
|
guesses.append(guess_results)
|
||||||
if not turn_over: # RAN OUT OF MOVES
|
if not turn_over: # RAN OUT OF MOVES
|
||||||
print("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!")
|
print("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!")
|
||||||
print(
|
print(f"THE ACTUAL COMBINATION WAS: {answer}")
|
||||||
"THE ACTUAL COMBINATION WAS: {}".format(
|
|
||||||
make_human_readable(numeric_answer, color_letters)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
human_score = human_score + num_moves
|
human_score = human_score + num_moves
|
||||||
print_score(computer_score, human_score)
|
print_score(computer_score, human_score)
|
||||||
|
|
||||||
@@ -107,23 +96,22 @@ def main() -> None:
|
|||||||
input("HIT RETURN WHEN READY: ")
|
input("HIT RETURN WHEN READY: ")
|
||||||
while num_moves < 10 and not turn_over and not inconsistent_information:
|
while num_moves < 10 and not turn_over and not inconsistent_information:
|
||||||
found_guess = False
|
found_guess = False
|
||||||
computer_guess = int(possibilities * random.random())
|
possible_guess = int(possibilities * random.random())
|
||||||
if (
|
if (
|
||||||
all_possibilities[computer_guess] == 1
|
all_possibilities[possible_guess] == 1
|
||||||
): # random guess is possible, use it
|
): # random guess is possible, use it
|
||||||
found_guess = True
|
found_guess = True
|
||||||
guess = computer_guess
|
|
||||||
else:
|
else:
|
||||||
for i in range(computer_guess, possibilities):
|
for i in range(possible_guess + 1, possibilities):
|
||||||
if all_possibilities[i] == 1:
|
if all_possibilities[i] == 1:
|
||||||
found_guess = True
|
found_guess = True
|
||||||
guess = i
|
possible_guess = i
|
||||||
break
|
break
|
||||||
if not found_guess:
|
if not found_guess:
|
||||||
for i in range(0, computer_guess):
|
for i in range(0, possible_guess):
|
||||||
if all_possibilities[i] == 1:
|
if all_possibilities[i] == 1:
|
||||||
found_guess = True
|
found_guess = True
|
||||||
guess = i
|
possible_guess = i
|
||||||
break
|
break
|
||||||
if not found_guess: # inconsistent info from user
|
if not found_guess: # inconsistent info from user
|
||||||
print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.")
|
print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.")
|
||||||
@@ -131,13 +119,8 @@ def main() -> None:
|
|||||||
turn_over = True
|
turn_over = True
|
||||||
inconsistent_information = True
|
inconsistent_information = True
|
||||||
else:
|
else:
|
||||||
numeric_guess = [-1] * num_positions
|
computer_guess = possibility_to_color_code(possible_guess)
|
||||||
for _ in range(0, guess+1):
|
print(f"My guess is: {computer_guess}")
|
||||||
numeric_guess = get_possibility(numeric_guess)
|
|
||||||
human_readable_guess = make_human_readable(
|
|
||||||
numeric_guess, color_letters
|
|
||||||
)
|
|
||||||
print(f"My guess is: {human_readable_guess}")
|
|
||||||
blacks_str, whites_str = input(
|
blacks_str, whites_str = input(
|
||||||
"ENTER BLACKS, WHITES (e.g. 1,2): "
|
"ENTER BLACKS, WHITES (e.g. 1,2): "
|
||||||
).split(",")
|
).split(",")
|
||||||
@@ -153,19 +136,12 @@ def main() -> None:
|
|||||||
for i in range(0, possibilities):
|
for i in range(0, possibilities):
|
||||||
if all_possibilities[i] == 0: # already ruled out
|
if all_possibilities[i] == 0: # already ruled out
|
||||||
continue
|
continue
|
||||||
numeric_possibility = [-1] * num_positions
|
possible_answer = possibility_to_color_code(i)
|
||||||
for _ in range(0, i+1):
|
|
||||||
numeric_possibility = get_possibility(
|
|
||||||
numeric_possibility
|
|
||||||
)
|
|
||||||
human_readable_possibility = make_human_readable(
|
|
||||||
numeric_possibility, color_letters
|
|
||||||
) # 4000
|
|
||||||
comparison = compare_two_positions(
|
comparison = compare_two_positions(
|
||||||
human_readable_possibility, human_readable_guess
|
possible_answer, computer_guess
|
||||||
)
|
)
|
||||||
print(comparison)
|
print(comparison)
|
||||||
if ((blacks != comparison[1]) or (whites != comparison[2])): # type: ignore
|
if (blacks != comparison[1]) or (whites != comparison[2]): # type: ignore
|
||||||
all_possibilities[i] = 0
|
all_possibilities[i] = 0
|
||||||
if not turn_over: # COMPUTER DID NOT GUESS
|
if not turn_over: # COMPUTER DID NOT GUESS
|
||||||
print("I USED UP ALL MY MOVES!")
|
print("I USED UP ALL MY MOVES!")
|
||||||
@@ -197,27 +173,21 @@ def print_board(guesses) -> None:
|
|||||||
print(f"{idx + 1}\t{guess[0]}\t{guess[1]} {guess[2]}")
|
print(f"{idx + 1}\t{guess[0]}\t{guess[1]} {guess[2]}")
|
||||||
|
|
||||||
|
|
||||||
# 3500
|
# Accepts a (decimal) number representing one permutation in the realm of possible
|
||||||
# Easily the place for most optimization, since they generate every possibility
|
# secret codes and returns the color code mapped to that permutation.
|
||||||
# every time when checking for potential solutions
|
# This algorithm is essentially converting a decimal number to a number with a
|
||||||
# From the original article:
|
# base of #num_colors, where each color code letter represents a digit in
|
||||||
# "We did try a version that kept an actual list of all possible combinations
|
# that #num_colors base.
|
||||||
# (as a string array), which was significantly faster than this versionn but
|
def possibility_to_color_code(possibility: int) -> str:
|
||||||
# which ate tremendous amounts of memory."
|
color_code: str = ""
|
||||||
def get_possibility(possibility) -> List[int]:
|
pos: int = num_colors ** num_positions # start with total possibilities
|
||||||
# print(possibility)
|
remainder = possibility
|
||||||
if possibility[0] > -1: # 3530
|
for i in range(num_positions-1, 0, -1): # process all but the last digit
|
||||||
current_position = 0 # Python arrays are zero-indexed
|
pos = pos // num_colors
|
||||||
while True:
|
color_code += color_letters[remainder // pos]
|
||||||
if possibility[current_position] < num_colors - 1: # zero-index again
|
remainder = remainder % pos
|
||||||
possibility[current_position] += 1
|
color_code += color_letters[remainder] # last digit is what remains
|
||||||
return possibility
|
return color_code
|
||||||
else:
|
|
||||||
possibility[current_position] = 0
|
|
||||||
current_position += 1
|
|
||||||
else: # 3524
|
|
||||||
possibility = [0] * num_positions
|
|
||||||
return possibility
|
|
||||||
|
|
||||||
|
|
||||||
# 4500
|
# 4500
|
||||||
@@ -258,14 +228,5 @@ def print_score(computer_score, human_score, is_final_score: bool = False) -> No
|
|||||||
print(f" HUMAN {human_score}")
|
print(f" HUMAN {human_score}")
|
||||||
|
|
||||||
|
|
||||||
# 4000, 5500, 6000 subroutines are all identical
|
|
||||||
def make_human_readable(num: List[int], color_letters) -> str:
|
|
||||||
"""Make the numeric representation of a position human readable."""
|
|
||||||
retval = ""
|
|
||||||
for i in range(0, len(num)):
|
|
||||||
retval = retval + color_letters[int(num[i])]
|
|
||||||
return retval
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user