1

This is my first post, and I will try to be as detailed as possible.

I am recreating the game "Mastermind", but instead of colors, letters are used. The color "red" would be "R", "yellow" would be "Y", etc...

I must check for errors, and when an error is inputted by the user, the output should be guess = input("Error, try again: ").

ANY ERRORS can NOT be counted as an attempt. There are a total of 8 attempts. I must check for other things as well, but I have already completed that part.

Here is the code I am having trouble with:

if len(guess) == 4 and (guess.upper().count("R") + guess.upper().count("Y") + guess.upper().count("B") +\
    guess.upper().count("G") + guess.upper().count("W") + guess.upper().count("O") == 4):

For the colors RGYBWO, if the user inputs for example: RYGW, can I sum up that up to be == 4?

In simpler terms, can I check that each letter is there and add them up to = 4 ?

If not, I will post the full code.

Senjuti Mahapatra
  • 2,570
  • 4
  • 27
  • 38
  • Is `RRGW` considered a good guess? Or is the user supposed to be guessing unique colors? – ShadowRanger Jun 07 '16 at 03:18
  • Possible duplicate of [In Python, how to check if a string only contains certain characters?](http://stackoverflow.com/questions/1323364/in-python-how-to-check-if-a-string-only-contains-certain-characters) – Mad Physicist Jun 07 '16 at 03:19
  • @MadPhysicist that post will definitely be helpful to the OP but that isn't technically what they asked. – Tadhg McDonald-Jensen Jun 07 '16 at 03:32
  • @TadhgMcDonald-Jensen. I realized that after trying to answer the question. That post is about half the question. Close vote emphatically rescinded. – Mad Physicist Jun 07 '16 at 03:41
  • @MadPhysicist the exact question of "can I sum up that up to be == 4" is only solved by the answers there when that consists of the entire sequence, it could happen where the OP may decide that they want to let the user add dashes or spaces if they please and still run fine but that can't be done with the answers there. – Tadhg McDonald-Jensen Jun 07 '16 at 04:00
  • OP, do you intend to select one of the answers? – Mad Physicist Jun 07 '16 at 14:22

3 Answers3

2

use the sum built in:

uppercase_guess = guess.upper() #no need to call it every time.
if sum(uppercase_guess.count(i) for i in "RGYBWO") == 4:
    ...

Although if you want to check that every character is one of those characters it might be clearer to do:

if ( all((i in "RGYBWO") for i in guess.upper())
    and len(guess) == 4):
    ...
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
2

Your phrasing is not 100% clear, but I think that you are asking if you can check the contents of the input more efficiently. There are a couple of ways of doing it that are shorter and more flexible than what you have now.

You want to check that the input is of length four, and contains no illegal characters. Your code is functionally OK for doing that but not very maintenance friendly. Checking len(guess) == 4 is perfect for the first part. The second has about half a dozen solutions in this question. Here is a summary of the three top ones:

  1. # Initialize this at module level
    allowed = set('rgbyow')
    # This is the check:
    if len(guess) == 4 and set(guess.lower()) < allowed:
        # OK
    
  2. # Initialize this at module level
    allowed = set('rgbyow')
    # This is the check:
    if len(guess) == 4 and all(c in allowed for c in guess.lower()):
        # OK
    
  3. # Initialize this at module level
    import re
    allowed_expr = re.compile('[rgbyowRGBYOW]{4}')
    # This is the check:
    if allowed_expr.match(guess):
        # OK
    
Community
  • 1
  • 1
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Note: #1 may be done more efficiently using `allowed.issuperset(guess.lower())`, which (could) avoid creating a temporary `set`. As it happens, it looks like [CPython's current implementation](https://hg.python.org/cpython/file/de5b85f96266/Objects/setobject.c#l1743) creates a temporary `set` internally, but creating it and throwing it away at the C layer may still be faster, and it's always possible to implement `set` operations like this by streaming the non-`set` past the `set`. – ShadowRanger Jun 07 '16 at 03:40
  • usually the whole point of using `re.compile` is to compile an expression ahead of time, if you need just one match then use `re.match`. Also if you are using `re` anyway why add the `guess.lower()` why not just check for `[rgbyowRGBYOW]{4}` – Tadhg McDonald-Jensen Jun 07 '16 at 03:54
  • Didn't know you could format code snippets in a list this nicely. Learn something new every day. – Mad Physicist Jun 07 '16 at 04:07
  • 1
    @ShadowRanger. For the moment, I am sticking to legibility over optimizing out the comparison against six characters. – Mad Physicist Jun 07 '16 at 04:11
0

Try this:

Since red could be really be "R" or "r" code for both.

allowed = 'RrGgBbYyOoWw' # So, now you accept either case and drop `.upper()`

if len(guess) == 4 and sum([guess.count(i) for i in allowed]):
Merlin
  • 24,552
  • 41
  • 131
  • 206