Master Mind on Python

I made Master Mind on Python!
image

import random

color = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

def gen_colors(code_size):
  code = ""
  for i in range(code_size):
    if i > 25:
      return code
    code += color[i]
  return code

def gen_code(code_size, colors):
  code = ""
  for i in range(code_size):
    code += colors[random.randint(0, len(colors) - 1)]
  return code

def check_guess(guess, code_size, colors):
  if len(guess) != code_size:
    return False
  for i in range(len(guess)):
    if guess[i] not in colors:
      return False
  return True

def score_guess(code, guess):
  correct = 0 # correct is count of right letter in its place
  correct1 = 0 # correct1 is count of right letter out of place
  for i in range(0, len(code)):
    if guess[i] == code[i]:
      correct += 1
    if guess[i] in code and guess[i] != code[i]:
      correct1 += 1
  return tuple([correct, correct1])

def play_cli(code_size, nb_colors):
  attempts = 0
  possible_colors = gen_colors(nb_colors)
  print(f"Possible colors are {possible_colors}")
  print(f"Code is size {code_size}.")
  code = gen_code(code_size, possible_colors)
  while True:
    guess = str(input())
    if guess == "fall":
      print(f"The code is {code}")
      break
    attempts += 1
    if guess == code:
      print(f"Congrats, you won after {attempts} attempts!")
      break
    if check_guess(guess, code_size, possible_colors) == True:
      print(score_guess(code, guess))
    else:
      attempts -= 1
      print("Wrong size or color!")

play_cli(4, 6) should output:

Possible colors are ABCDEF
Code is size 4.

But it has a inaccuracy:

Letā€™s say the random code is FFEE,
We introduce FFFF,

It print:
(2, 2) # 2 letters in place, 2 letters out of place

But I want it to print:
(2, 0) # 2 letters in place

Ahh, this is a game my Mum and I spent many many hours playing, in my childhood! The memories. (Side note: We actually played a variant where the colours had to be unique. It makes the logic more fun IMO.)

So, the logic youā€™re having trouble with is here:

def score_guess(code, guess):
  correct = 0 # correct is count of right letter in its place
  correct1 = 0 # correct1 is count of right letter out of place
  for i in range(0, len(code)):
    if guess[i] == code[i]:
      correct += 1
    if guess[i] in code and guess[i] != code[i]:
      correct1 += 1
  return tuple([correct, correct1])

The thing is really quite simple. The insertion of a single word will do it. If a guess is precisely correct, then it isnā€™t also partly correct. To be precise, a particular iteration through this loop should only be able to increment one of the two scores - if it increments correct, it should not even attempt to increment correct1.

This then allows another simplification: the second condition on the correct1 check will no longer be necessary.

While youā€™re at it, there are a couple of other ways you could do this iteration. The classic alternative to range(len(x)) is to use enumerate, but in this case, what youā€™re really doing is iterating simultaneously over both the code and the guess - that is to say: for c, g in zip(code, guess):

With that, and a few other small changes, hereā€™s how I would write that function:

def score_guess(code, guess):
    correct = misplaced = 0
    for c, g in zip(code, guess):
        if c == g: correct += 1
        elif g in code: misplaced += 1
    return correct, misplaced

Note that constructing a list and then building a tuple from that list is unnecessary; you can simply return the two values with a comma between them, and youā€™ll get a tuple.

Hope that helps!

1 Like

Thank you for the answer, it is short and informative.
But the problem remains:
2024-06-18_20-50-21
Instead of:

Possible colors are ABCDEF
Code is size 4.
FFFF
(2, 0)

Ah, true. I was actually solving the opposite bug; that one still remains.

So, what you need to do is ā€œuse upā€ one of the entries in the code whenever you give a score based on it. There are a few ways you can do this, including maintaining a counter, and turning the code into a list which you mutate as you mark them off.

1 Like

I will try.