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.