Tiny Mastermind
#1
NOTE: Later down there's an updated version that is more optimized and does away with colons.

I present to you the game Mastermind, in 25 lines of code.  Technically a little more because of
colons, but all the colons here are fine I think.  For tiny little one-statement DO and FOR loops,
I find it's more readable like this; likewise for concatenating a handful of simple results of an
IF statement, to avoid a block IF...END IF.  For much larger programs, it makes understanding
program flow much less convoluted, since my eyes have less nesting hierarchy to navigate.
Also, this code works in QBasic!

Code: (Select All)
do: input "How many possible letters (2-26)? ", code_colors%: loop while code_colors% < 2 or code_colors% > 26
do: input "How many letters long? ", code_length%: loop while code_length% < 1
dim match%(code_length%)
randomize timer
for n = 1 to code_length%: solution$ = solution$ + chr$(int(rnd * code_colors%) + asc("a")): next n
do
  do: input "> ", attempt$: loop until len(attempt$) = code_length%
  black_pegs% = 0: white_pegs% = 0
  for n = 1 to code_length%
      if mid$(attempt$, n, 1) <> mid$(solution$, n, 1) then match%(n) = 0 else match%(n) = n: black_pegs% = black_pegs% + 1
  next n
  for n = 1 to code_length%
      if match%(n) = 0 then
        for n1 = 1 to code_length%
            if n1 <> n and mid$(attempt$, n, 1) = mid$(solution$, n1, 1) then
              for n2 = 1 to code_length%
                  if match%(n2) <> n1 then m = 0 else m = -1: exit for ' Check for pre-existing white peg
              next n2
              if m = 0 then match%(n) = n1: white_pegs% = white_pegs% + 1: exit for
            end if
        next n1
      end if
  next n
  print black_pegs%; "black,"; white_pegs%; "white"
loop while black_pegs% < code_length%


This operates exactly like Mastermind as you know it, except with lowercase letters instead of
colored pegs.  You specify how many letters are possible, and how long the solution is.  So, if
you say 12 possible letters and 4 letters long, the game will use the letters a through l, and
produce solutions such as "glhf" and "dljk."  If you say 2 possible letters and 15 letters long,
it will produce things like "baabbbabaababba."

Guesses must be of the specified length, and must be in all lowercase.  The game will signal
a correct letter in correct position with a "black peg," just like a typical Mastermind set,
and will signal a correct letter that is in the wrong position with a "white peg."  For example,
if the solution is "hall," and you guess "hola," you will get two black pegs for the first h and
the third l, and one white peg for the a, which is not in the second position.  If the solution
is "other," and you guess "trout," you will get three white pegs, not four, since the solution
only has one t.
Reply
#2
I like the tiny game! Works fine
   

But about that line count
   

Search is not helping find Pete's code so here it is instead of link:
Code: (Select All)
Print "Line count analysis...": Print ' 1

Print "Press [1] to parse all colons or [2] the exclude colons after an IF statement.": Print '2

Do
    _Limit 30
    b$ = InKey$
    If Len(b$) Then
        Select Case b$
            Case Chr$(27): System ' 3
            Case "1": myopt = 3: Print "Parsing all significant colons...": Print ' 6
            Case "2": myopt = 4: Print "Parsing all significant colons not used in IF/THEN one line statements.": Print ' 9
        End Select
        If myopt Then Exit Do
    End If
Loop

x$ = _Clipboard$ + Chr$(13)

Do
    ' parse clipboard
    statement$ = UCase$(Mid$(x$, 1, InStr(x$, Chr$(13)) - 1))
    If statement$ = Chr$(10) Then statement$ = ""
    x$ = Mid$(x$, InStr(x$, Chr$(13)) + 1)

    If Len(_Trim$(statement$)) Then
        program_ide_lines = program_ide_lines + 1
        For i = 1 To myopt
            Select Case i
                Case 1: mychr$ = Chr$(34) '10
                Case 2: mychr$ = "'" '11
                Case 3: mychr$ = "REM " '12
                Case 4: mychr$ = " THEN " '13
            End Select

            Select Case i
                Case 1 '  Double polling for enclosed quotes.
                    Do Until InStr(statement$, mychr$) = 0
                        If InStr(statement$, mychr$) Then
                            statement$ = Mid$(statement$, 1, InStr(statement$, mychr$) - 1) + Mid$(statement$, InStr(InStr(statement$, mychr$) + 1, statement$, mychr$) + 1)
                        End If
                    Loop
                Case Else
                    Do Until InStr(statement$, mychr$) = 0
                        If InStr(statement$, mychr$) Then
                            statement$ = Mid$(statement$, 1, InStr(statement$, mychr$) - 1)
                        End If
                    Loop
            End Select
        Next
        If Right$(RTrim$(statement$), 1) = ":" Then statement$ = Mid$(RTrim$(statement$), 1, Len(RTrim$(statement$)) - 1) ' ??

        Rem PRINT statement$,

        ' count colons

        seed% = 0: linecnt = linecnt + 1: real_line_cnt = real_line_cnt + 1 '  15
        Do Until InStr(seed%, statement$, ":") = 0 ' ??
            seed% = InStr(seed%, statement$, ":") + 1 ' ??
            real_line_cnt = real_line_cnt + 1
        Loop
    Else
        program_ide_lines = program_ide_lines + 1
    End If
Loop Until x$ = ""
Print "Program IDE lines ="; program_ide_lines; "  Line count ="; linecnt; "  Real line count ="; real_line_cnt


' 66 lines  9 blank lines  = 57 + 15 colons = 72
b = b + ...
Reply
#3
Okay, not only did I conform to your definition of a line, I did so while saving 11 lines.  So this is now Mastermind in 27 lines, but now you also can't argue otherwise AND several things were optimized.  More lines can be saved if I give up on QBasic compatibility and incorporate the _CONTINUE statement.  Please note the following changes carefully, as user input and feedback has changed:

- No do loop to make sure player is not an idiot.  If you say you want 30 different letters, get ready for punctuation.  If you do something even crazier, you may crash the game.  Ditto for the length check on each attempt; if it doesn't match the solution's length, something bad may happen.  Maybe your milk in the fridge will spoil.

- Starting parameters set by the player are contained in the same INPUT, so you have to enter both at the same time, separated by a comma. (I should add that this is the ONLY time I have ever found a practical use for this quirk of INPUT, it's always just been a nuisance.)

- Conditionals that contained colons have been repackaged into two duplicate conditional lines, to avoid a block IF.  In doing this, I noticed a couple ways the largest hierarchy could be pruned.

- The feedback is no longer peg-counting numerical variables, now it's a single string, and I avoid giving away extra information by appending "B" (for black peg) to the start, and "W" (white) to the end of the string.  This doesn't save lines by my definition, but by using one variable instead of two, does save a colon. This did make it too awkward to keep the victory/end-program condition on the final LOOP, without adding more lines. So now you just win when you get enough black pegs, the program won't end.

Code: (Select All)
input "How many possible letters, how many letters long? ", code_colors%, code_length%
dim match%(code_length%)
randomize timer
for n = 1 to code_length%
  solution$ = solution$ + chr$(int(rnd * code_colors%) + asc("a"))
next n
do
  input "> ", attempt$
  pegs$ = ""
  for n = 1 to code_length%
      if mid$(attempt$, n, 1) = mid$(solution$, n, 1) then match%(n) = n else match%(n) = 0
      if mid$(attempt$, n, 1) = mid$(solution$, n, 1) then pegs$ = "B" + pegs$
  next n
  for n = 1 to code_length%
      for n1 = 1 to code_length%
        if match%(n) = 0 and n1 <> n and mid$(attempt$, n, 1) = mid$(solution$, n1, 1) then
            m = 0
            for n2 = 1 to code_length%
              if match%(n2) = n1 then m = -1
            next n2
            if m = 0 then match%(n) = n1
            if m = 0 then pegs$ = pegs$ + "W"
        end if
      next n1
  next n
  print pegs$
loop
Reply
#4
Nice, I would probably set the number of letters and the length of code string and save more lines even idiot proofing the length of guess string, just like you get in the board game. But I guess that goes against the spirit of programming games with all kinds of options.
b = b + ...
Reply
#5
I never understood the need to have as few lines of code as possible for any task. Colons were considered part of the problem of coding with interpreted BASIC. Leave them to Python I say.

LOL that's why once in Purebasic forum there was a contest for the most impressive program with the least lines of code, precisely because that's how the demo version of the compiler was set up. They even wrote a program that checked another source code to make sure it qualified for the contest. It was still fairly easy to trick, since they were so full of macros. Rolleyes

A bunch of raytracing examples and weak text-mode adventures, such as "Stupid-noid" but I've written that before and many more Pong-like things in SCREEN 0, which was a bit harder for the ones using that compiler.
Reply
#6
"Need?"  No, this was just a fun challenge for myself.  I have a version of Mastermind that's longer and more fun to play, but I was bored at work with too much downtime as usual, and wondered how short I could make it while still keeping the gameplay intact.


bplus, I suppose you could save one more line of code by removing the first INPUT statement, and replacing all instances of those two variables with hard numbers.  I just found it very boring to play 6, 4 traditional games very quickly, so ended up playing with more letters and longer codes, and got better at the game overall.  Even solved a 40-long code using every possible letter of the alphabet.
Reply




Users browsing this thread: 5 Guest(s)