Batch MasterMind

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Batch MasterMind

#1 Post by dbenham » 31 Dec 2014 20:37

NOTE: The most recent version can be found at viewtopic.php?p=39024#p39024

I saw coopster23's post that talked about developing a Mastermind like game, and it brought back memories of playing that board game as a kid.

I think it is a perfect game for implementation as a batch file, and I couldn't resist developing my own. I was surprised how tricky it was to score each turn. It took at least 3 algorithm iterations before I got it right.

This first version uses Super Mastermind rules: 12 guesses for a 5 digit code consisting of any combination of digits 12345678 (instead of 8 colors).

Code: Select all

:: BatchMasterMind.bat
::
:: Version History
:: 1.0  2014-12-31
::
:: Written by Dave Benham and Originally posted at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=6153
::
@echo off
setlocal enableDelayedExpansion

:: GameConfiguration
set "symbolCnt=8"
set "symbols=12345678"
set "matchPosSymbol=X"
set "matchSymSymbol=O"
set "noMatchSymbol=_"
set "maskSymbol=-"
set "maxGuesses=12"
set "codeLen=5"

:: Initialize
set /a codeStop=codelen-1
set "noMatch="
set "mask="
for /l %%N in (1 1 %codeLen%) do (
  set "noMatch=!noMatch!%noMatchSymbol%"
  set "mask=!mask!!maskSymbol!"
)

:: Show Help
cls
echo(
echo You have %maxGuesses% guesses to deduce the %codeLen% character code
echo consisting of any combination of the following symbols:
echo !symbols!
echo(
echo There may be duplicate symbols in the code.
echo(
echo The number of !matchPosSymbol! characters tells you how many symbols
echo match and are in the correct position.
echo(
echo The number of !matchSymSymbol! characters tells you how many symbols
echo match but are in the wrong position.
echo(
pause

:play

:: GetCode
set "code="
for /l %%N in (0 1 %codeStop%) do (
  set /a "n=!random!%%symbolCnt"
  for %%A in (!n!) do set "code=!code!!symbols:~%%A,1!"
)

:: ClearTurns
for /l %%N in (1 1 %maxGuesses%) do if %%N lss 10 (
  set "turn[%%N]=  %%N"
) else (
  set "turn[%%N]= %%N"
)

:: Turn Loop
for /l %%T in (%maxGuesses% -1 1) do (

  call :showBoard mask
  call :getGuess

  %= Compute Score =%
  for /l %%A in (0 1 %codeStop%) do (
    set "guess[%%A]=!guess:~%%A,1!"
    set "code[%%A]=!code:~%%A,1!"
  )
  set "matchPos="
  for /l %%A in (0 1 %codeStop%) do if !guess[%%A]! equ !code[%%A]! (
    set "matchPos=!matchPos!!matchPosSymbol!"
    set "guess[%%A]="
    set "code[%%A]="
  )
  set "matchSym="
  for /l %%A in (0 1 %codeStop%) do for /l %%B in (0 1 %codeStop%) do if defined guess[%%A] if !guess[%%A]! equ !code[%%B]! (
    set "matchSym=!matchSym!!matchSymSymbol!"
    set "guess[%%A]="
    set "code[%%B]="
  )
  set "score=!matchPos!!matchSym!!noMatch!"
  set "score=!score:~0,%codeLen%!"

  %= Define Turn =%
  set "turn[%%T]=!turn[%%T]!   !guess!  !score!"

  %= Check for winner =%
  if !guess! equ !code! goto :endGame
)


:endGame
call :showBoard code
if !guess! equ !code! (echo You WIN^^!) else (echo You LOSE^^!)
echo(
set "again="
set /p "again=Play again [YN]? "
if /i "%again%" equ "Y" goto :play
exit /b


:getGuess
set "guess="
set /p "guess=Guess "
if not defined guess goto :getGuess
for /f "delims=%symbols% eol=%symbols:~0,1%" %%A in ("%guess%") do goto :getGuess
if "!guess:~%codeLen%!" neq "" goto :getGuess
if "!guess:~%codeStop%!" equ "" goto :getGuess
exit /b


:showBoard  target
cls
echo(
echo       !%1!  [!symbols!]
echo(
for /l %%N in (%maxGuesses% -1 1) do echo !turn[%%N]!
echo(
exit /b


Dave Benham
Last edited by dbenham on 02 Jan 2015 10:59, edited 1 time in total.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Batch MasterMind

#2 Post by foxidrive » 01 Jan 2015 06:05

:)

FWIW I had this squirreled away:

Code: Select all

:: MasterMind
:: Bruce Howells 04/1998 from the Fidonet Batpower conference
:: with some cosmetic tweaks
:: tested in MSdos V6.22 and Windows 98SE
@echo off
if (%1)==() set gt=
if (%1)==() cls
if (%gt%)==() goto Start
goto %gt%
:Compare
for %%x in (co gt t vn cp $ $$ $$$ $$$$) do set %%x=
:ChkColPos
:: Test Colour & Position
if (%1)==(%2) set cp=%cp%P
set vn=%vn%$
if not (%1)==(%2) set %vn%=%1
if not (%1)==(%2) set t=%t% %2
shift
shift
if not (%1)==() goto ChkColPos
if (%t%)==() goto Status
:: Test colours of Failed Codes
set gt=ChkColour
:: Rerun program
%me% %t%
:ChkColour
set t=
if (%$%)==(%1) set t=$
if (%$$%)==(%1) set t=$$
if (%$$$%)==(%1) set t=$$$
if (%$$$$%)==(%1) set t=$$$$
if not (%t%)==() set co=%co%C
if not (%t%)==() set %t%=
shift
if not (%1)==() goto ChkColour
:Status
for %%x in (gt hc t vn $ $$ $$$ $$$$ # ## ### ####) do set %%x=
:: 1 tr. space
if not (%cp%)==() set t= |::
echo "──>"  %cp%%t%%co%
if (%cp%)==(PPPP) goto Found
if (%q%)==(qqqqqqqqqq) goto EndGame
:ResetR
set r=::
:AskColr
set gt=
choice  /c123456C /n
echo   ["a";"a"p
for %%x in (1 2 3 4 5 6 7 8) do if errorlevel %%x set t=%%x
if (%t%)==(8) goto EndGame
if (%t%%i%)==(7) goto AskColr
if (%t%)==(7) set r=
%r% for %%x in (%#% %##% %###%) do echo    
%r% for %%x in (hc i) do set %%x=
%r% goto ResetR
set i=%i%#
echo [39;4%t%m %t% 
set %i%=%t%
set hc=%hc%%t%
if not (%i%)==(####) goto AskColr
set q=%q%q
set i=
set t=
:: Rerun in compare mode
set gt=Compare
%me% %@% %#% %@@% %##% %@@@% %###% %@@@@% %####%
:Found
:: 3 tr. spaces
echo  o You found the code o 
goto Another
:EndGame
:: 2 tr. spaces
echo Code was [39;4%@%m %@% [4%@@%m %@@% [4%@@@%m %@@@% [4%@@@@%m %@@@@%   ["a";"a"p
if (%t%)==(8) goto Quit
:Another
:: 3 tr. spaces
echo Another game? Y/N
CHOICE  /cyn /n
if errorlevel 3 goto Quit
if errorlevel 2 goto Quit
:Start
if (%me%)==() set me=%0
set r=::
for %%x in (@ @@ @@@ @@@@ # ## ### ####) do set %%x=
for %%x in (cc co cp gt hc i t) do set %%x=
echo @PROMPT %me% $t>mmtemp1.bat
%COMSPEC% /C mmtemp1.bat>mmtemp2.bat
set gt=TimeNow
mmtemp2
:TimeNow
set gt=Parse
set t=%1
echo ; | choice /c:=%t%;= %me% >mmtemp1.bat
mmtemp1.bat
:Parse
del mmtemp?.bat
:: Skip over hours etc
for %%x in (1 2 3 4) do shift
for %%x in (cc gt hc i q) do set %%x=
:SetCode
set i=%i%@
set t=%1
if (%t%)==(9) set t=6
if (%t%)==(8) set t=4
if (%t%)==(7) set t=3
if (%t%)==(0) set t=6
set %i%=%t%
set cc=%cc%%t%
shift
for %%x in (: . ] /?) do if (%1)==(%%x) shift
if not (%i%)==(@@@@) if not (%1)==() goto SetCode
for %%x in (hc i t) do set %%x=
echo ╔════════════════════════╗
:: next line has 24 trailing spaces
for %%x in (1 2 3 4 5 6 7 8 9 A B C D E F G) do echo ║                        ║
echo Ã────────────────────────Â
echo Ã────────────────────────Â
echo ╚════════════════════════╝Guess!    Cancel   Esc[1;37;40
echo  MICROCODE by Bruse
echo Key  1  2  3  4  5  6 
echo 
set gt=AskColr
%me% (dummy)
:Quit
:: 16 tr. spaces
echo                        ║
for %%x in (@ @@ @@@ @@@@ # ## ### ####) do set %%x=
for %%x in (cc co cp gt hc i me q r t) do set %%x=

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch MasterMind

#3 Post by dbenham » 01 Jan 2015 09:57

@foxidrive - That is an old DOS version with at least two issues that prevent it from running on my Win 7 64 bit machine:

1) It uses the old CHOICE syntax - those lines would need to be reworked for the new syntax.
2) It utilizes ANSI escape sequences, and ANSI.SYS does not work on 64 bit machines. Perhaps ansicon or Aacini's AnsiSys.exe can help.


Dave Benham

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Batch MasterMind

#4 Post by foxidrive » 01 Jan 2015 22:28

dbenham wrote:@foxidrive - That is an old DOS version


Yes, it is!
I'm not competing with yours, it's only of historic interest on the same topic.

I like the idea that you have created one for modern machines...

npocmaka_
Posts: 512
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: Batch MasterMind

#5 Post by npocmaka_ » 02 Jan 2015 07:24

It just continue asking me for numbers:

Image

Is there something I've missed?

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Batch MasterMind

#6 Post by foxidrive » 02 Jan 2015 07:32

Enter

11111
22222
33333

etc.

It does need some validation of the right number of characters, Dave.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch MasterMind

#7 Post by dbenham » 02 Jan 2015 09:44

foxidrive wrote:It does need some validation of the right number of characters, Dave.

The behavior you saw is my validation :!:
The game won't continue until you enter a string with the correct length consisting of only valid symbols.

Code: Select all


      -----  [12345678]

 12   11223  XXO--
 11   44556  OO---
 10
  9
  8
  7
  6
  5
  4
  3
  2
  1

Guess 113
Guess abcde
Guess 11364

After pressing <Enter> for the 11364 entry, I get:

Code: Select all


      -----  [12345678]

 12   11223  XXO--
 11   44556  OO---
 10   11364  XXO--
  9
  8
  7
  6
  5
  4
  3
  2
  1

Guess

I think all I need is an error message for an invalid guess.

Dave Benham

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch MasterMind

#8 Post by dbenham » 02 Jan 2015 10:56

Here is my next, and probably last release: - Version 2.0. I believe any other changes would be cosmetic, unless someone finds a bug.

Version 2 has a crude menu to select either original Mastermind or Super Mastermind rules, or any custom rules of your choosing.
I've also added an error message if an invalid guess is entered.

BatchMastermind.bat version 2.0

Code: Select all

:: BatchMasterMind.bat
::
:: Version History
:: 1.0  2014-12-31  - Original release
:: 2.0  2015-01-02  - Added menu for different rule variations
::                  - Added error message for invalid guess
::
:: Written by Dave Benham and Originally posted at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=6153
::
@echo off
setlocal enableDelayedExpansion

:mainMenu
cls
echo(
echo(M - Mastermind       (code length 4, 6 symbols, 10 guesses)
echo(S - Super Mastermind (code length 5, 8 symbols, 12 guesses)
echo(C - Custom
echo(Q - Quit
echo(
<nul set /p "=> "
call :getKey MSCQ key
if /i !key! equ Q (
  echo Q
  echo(
  exit/b
) else if /i !key! equ M (
  set "symbols=123456"
  set "maxGuesses=10"
  set "codeLen=4"
  set "dups=Y"
) else if /i !key! equ S (
  set "symbols=12345678"
  set "maxGuesses=12"
  set "codeLen=5"
  set "dups=Y"
) else %= !key! equ C =% (
  call :custom
)

:: Initialize
set "matchPosSymbol=X"
set "matchSymSymbol=O"
set "noMatchSymbol=-"
set "maskSymbol=-"
call :strlen symbols symbolCnt
set /a codeStop=codelen-1
set "noMatch="
set "mask="
for /l %%N in (1 1 %codeLen%) do (
  set "noMatch=!noMatch!%noMatchSymbol%"
  set "mask=!mask!!maskSymbol!"
)

:: Show Help
cls
echo(
echo You have %maxGuesses% guesses to deduce the %codeLen% character code
echo consisting of any combination of the following symbols:
echo(
echo   !symbols!
echo(
if /i !dups! equ Y (
  echo Duplicate symbols are allowed in the code.
) else (
  echo Duplicate symbols are NOT allowed in the code.
)
echo(
echo The number of !matchPosSymbol! characters tells you how many symbols
echo match and are in the correct position.
echo(
echo The number of !matchSymSymbol! characters tells you how many symbols
echo match but are in the wrong position.
echo(
pause

:play

:: GetCode
set "list=!symbols!"
set "len=%symbolCnt%"
set "code="
for /l %%N in (0 1 %codeStop%) do (
  set /a "n=!random!%%len"
  for %%A in (!n!) do (
    set "code=!code!!list:~%%A,1!"
    if /i !dups! equ N (
      set /a "n+=1, len-=1"
      for %%B in (!n!) do set "list=!list:~0,%%A!!list:~%%B!"
    )
  )
)

:: ClearTurns
for /l %%N in (1 1 %maxGuesses%) do if %%N lss 10 (
  set "turn[%%N]=  %%N"
) else (
  set "turn[%%N]= %%N"
)

:: Turn Loop
for /l %%T in (%maxGuesses% -1 1) do (

  call :showBoard mask
  call :getGuess

  %= Compute Score =%
  for /l %%A in (0 1 %codeStop%) do (
    set "guess[%%A]=!guess:~%%A,1!"
    set "code[%%A]=!code:~%%A,1!"
  )
  set "matchPos="
  for /l %%A in (0 1 %codeStop%) do if !guess[%%A]! equ !code[%%A]! (
    set "matchPos=!matchPos!!matchPosSymbol!"
    set "guess[%%A]="
    set "code[%%A]="
  )
  set "matchSym="
  for /l %%A in (0 1 %codeStop%) do for /l %%B in (0 1 %codeStop%) do if defined guess[%%A] if !guess[%%A]! equ !code[%%B]! (
    set "matchSym=!matchSym!!matchSymSymbol!"
    set "guess[%%A]="
    set "code[%%B]="
  )
  set "score=!matchPos!!matchSym!!noMatch!"
  set "score=!score:~0,%codeLen%!"

  %= Define Turn =%
  set "turn[%%T]=!turn[%%T]!   !guess!  !score!"

  %= Check for winner =%
  if !guess! equ !code! goto :endGame
)


:endGame
call :showBoard code
if !guess! equ !code! (echo You WIN^^!) else (echo You LOSE^^!)
echo(
<nul set /p "again=Play again [YN]? "
call :getKey YN key
if /i !key! equ Y goto :play
goto :mainMenu


:badGuess
echo Invalid guess - Must have length %codeLen% with valid symbols only

:getGuess
set "guess="
set /p "guess=Guess "
if not defined guess goto :badGuess
for /f "delims=%symbols% eol=%symbols:~0,1%" %%A in ("%guess%") do goto :badGuess
if "!guess:~%codeLen%!" neq "" goto :badGuess
if "!guess:~%codeStop%!" equ "" goto :badGuess
exit /b


:showBoard  target
cls
echo(
echo       !%1!  [!symbols!]
echo(
for /l %%N in (%maxGuesses% -1 1) do echo !turn[%%N]!
echo(
exit /b


:strlen  StrVar  RtnVar
setlocal enableDelayedExpansion
set "s=!%~1!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
  if "!s:~%%P,1!" NEQ "" (
      set /a "len+=%%P"
      set "s=!s:~%%P!"
  )
)
endlocal & set "%~2=%len%"
exit /b


:custom
cls
echo(

:getSymbols
set "symbols="
set /p "symbols=Symbols = "
if not defined symbols goto :getSymbols

:getCodeLen
set "codeLen="
set /p "codeLen=Code length = "
2>nul set /a codeLen=codeLen || goto :getCodeLen
if %codeLen% lss 1 goto :getCodeLen

<nul set /p "=Allow duplicate symbols in code? [YN] "
call :getKey YN dups
echo !dups!

:getMaxGuesses
set "maxGuesses="
set /p "maxguesses=Max guesses = "
2>nul set /a maxGuesses=maxGuesses || goto :getMaxGuesses
if %codelen% lss 1 goto :getMaxGuesses
exit /b


:getKey  validList  rtnVar
setlocal
set "valid=%~1"
set "key="
for /f "delims=" %%A in ('xcopy /w "%~f0" "%~f0" 2^>nul') do (
  if not defined key set "key=%%A"
)
set "key=!key:~-1!"
if "!key!" equ "=" goto :getKey
for /f delims^=^ eol^= %%C in ("!key!") do if "!valid:%%C=!" neq "!valid!" (
  endlocal
  set "%~2=%%C"
  exit /b
)
goto :getKey


Dave Benham

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Batch MasterMind

#9 Post by foxidrive » 02 Jan 2015 11:16

dbenham wrote:I think all I need is an error message for an invalid guess.

Dave Benham


IIRC Aacini wrote an input routine that can mask the required characters - and also perform the function when the correct number of characters are entered.

That would be neat
- enter 5 characters (cannot enter incorrect ones) (with editing)?
- when 5 characters are entered then display the result and await the next 5 characters.

Just bringing up ideas...

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Batch MasterMind

#10 Post by Aacini » 04 Jan 2015 06:54

Well, I wrote my own version of MasterMind game. Why? Dave explained the reason very well: "I think it is a perfect game for implementation as a batch file, and I couldn't resist developing my own". Don't matter if there are several working versions of the game already developed, it is a sort of necessity to see how a program that I wrote myself run... :wink:

Anyway, I think my version offers a very good playing experience and it is the perfect program to use a modified version of my ReadFormattedLine subroutine (as foxidrive suggested).

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Master Mind game, Batch file version
rem Antonio Perez Ayala

set "thisFile=%~F0"
set quote="
set "fmt=#_23456789"
set "digit= 0 1 2 3 4 5 6 7 8 9 "
set "show=ABCDEFGHIJKLMNOPQRSTUVWXYZ³: "
for /F %%a in ('copy /Z "%thisFile%" NUL') do set "CR=%%a"
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a" & set "SP=.%%a "

color 1F
:begin
cls
echo/
echo    MasterMind is a code-breaking game. The code is comprised of ^<Code length^>
echo    positions each of one contain a digit from 1 up to ^<Digits^> value.
echo/
echo    You have ^<Guesses^> turns to deduce the code. After each turn the number of
echo    "X" characters indicate how many digits match in the correct position, and
echo    the number of "O" characters how many digits match in a wrong position.
echo/
echo Press Enter key to start the game, or BackSpace to change values.
set /P "=Code length: 4   Digits from one to: 6   Guesses: 10" < NUL
set "values=4   Digits from one to: 6   Guesses: 10"

:readValues
   set "key="
   for /F "delims=" %%a in ('xcopy /W "%thisFile%" "%thisFile%" 2^>NUL') do if not defined key set "key=%%a"
   if "!key:~-1!" equ "!CR!" goto getValues
if "!key:~-1!" neq "!BS!" goto readValues
set /P "=!SP!!CR!" < NUL
call :ReadLine values="Code length: " "#   Digits from one to: #   Guesses: #_"

:getValues
for /F "delims==" %%a in ('set code 2^>NUL') do set "%%a="
for /F "tokens=1,6,8" %%a in ("%values%") do set "codeLen=%%a" & set "digits=%%b" & set "guesses=%%c"
set "fields="
set "frame="
for /L %%i in (1,1,%codeLen%) do (
   set /A "n=!random! %% digits + 1"
   set "code=!code!!n!"
   set /A "code[!n!]+=1!
   set "fields=!fields!  %digits%  ³"
   set "frame=!frame!ÄÄÄÄÄÂ"
)
set "frame=%frame:~0,-1%"
echo/
echo/
REM ECHO   CODE: %CODE%
echo        Ú%frame%¿
set "frame=%frame:Â=Å%"
set /A codeLenM1=codeLen-1
for /L %%t in (%guesses%,-1,1) do (
   if %%t lss 10 (set "turn= %%t") else set "turn=%%t"
   call :ReadLine values="!SP!!turn! -  ³" "%fields%"
   set "guess=!values:³=!"
   set "guess=!guess: =!"
   set "matchPos="
   set "matchDigit="
   for /F "tokens=2 delims=[" %%a in ('set code[') do set "code2[%%a"
   for /L %%i in (0,1,%codeLenM1%) do for /F %%g in ("!guess:~%%i,1!") do (
      if "%%g" equ "!code:~%%i,1!" (
         set "matchPos=!matchPos!X"
         if !code2[%%g]! gtr 0 (set /A code2[%%g]-=1) else set "matchDigit=!matchDigit:~1!"
      ) else if "!code2[%%g]!" gtr "0" (
         set "matchDigit=!matchDigit!O"
         set /A "code2[%%g]-=1"
      )
   )
   set "output=!matchPos!!matchDigit!---------"
   echo    !output:~0,%codeLen%!
   if !guess! equ !code! goto endGame
   if %%t gtr 1 echo        Ã%frame%´
)

:endGame
echo        À%frame:Å=Á%Ù
echo/
if %guess% equ %code% (echo You WIN^^!) else echo You lose, the code was: %code%
echo/
set /P "=Play again [YN]? " < NUL
set "key="
for /F "delims=" %%a in ('xcopy /W "%thisFile%" "%thisFile%" 2^>NUL') do if not defined key set "key=%%a"
if /I "!key:~-1!" equ "Y" goto begin

echo/
color
goto :EOF


:ReadLine var="message" "mask"

setlocal EnableDelayedExpansion
set "var=%1"
set "message=%~2"
set "mask=%~3"
< NUL (
   set /P "=%message%"
   for /L %%i in (0,1,60) do for /F "delims=" %%a in ("!mask:~%%i,1!") do (
      if "!fmt:%%a=!" neq "%fmt%" (
         set /P "=Û"
      ) else if "%%a" neq " " (
         set /P "=%%a"
      ) else (
         set /P "=!SP!"
      )
   )
   set /P "=!SP!!CR!%message%"
)
set "input="
set /A i=0, key=0
goto checkFormat

:nextKey
   set "key="
   for /F "delims=" %%a in ('xcopy /W "%thisFile%" "%thisFile%" 2^>NUL') do if not defined key set "key=%%a"
   if "!key:~-1!" neq "!CR!" goto getKey
      if "%format%" equ "" goto endRead
      if "%format%" equ "_" goto endRead
      goto nextKey
   :getKey
   set "key=!key:~-1!"
   if "!key!" equ "!BS!" (
      if %i% gtr 0 (
         if "%format%" equ "" (
            set /P "=!SP!!BS!!BS!Û!BS!" < NUL
         ) else (
            set /P "=Û!BS!!BS!Û!BS!" < NUL
         )
         set "input=%input:~0,-1%"
         set /A i-=1
         if !i! equ 0 set key=0
      )
      goto checkFormat
   )
   if "%format%" equ "" goto nextKey
   if "!key!" equ "=" goto nextKey
   if "!key!" equ "!quote!" goto nextKey
   if "!digit: %key% =!" equ "%digit%" goto nextKey
   if "!digit: %format% =!" neq "%digit%" (
      if %key% equ 0 goto nextKey
      if %key% gtr %format% goto nextKey
   )
   set /P "=%key%" < NUL
   set "input=%input%%key%"

   :nextFormat
   set /A i+=1
   :checkFormat
   set "format=!mask:~%i%,1!"
   if "%format%" equ "" goto nextKey
   if "!show:%format%=!" neq "%show%" (
      if "!key!" equ "!BS!" (
         if "%format%" neq " " (
            set /P "=%format%!BS!!BS!Û!BS!" < NUL
         ) else (
            set /P "=!SP!!BS!!BS!Û!BS!" < NUL
         )
         set "input=%input:~0,-1%"
         set /A i-=1
         if !i! equ 0 set key=0
         goto checkFormat
      ) else (
         if "%format%" neq " " (
            set /P "=%format%" < NUL
         ) else (
            set /P "=!SP!" < NUL
         )
         set "input=%input%%format%"
         goto nextFormat
      )
   )
   if "%input:~-1%!key!" equ " !BS!" (
      set /P "=Û!BS!!BS!" < NUL
      set "input=%input:~0,-1%"
      set /A i-=1
      goto checkFormat
   )

goto nextKey
:endRead
endlocal & set "%var%=%input%"
exit /B

Antonio

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Batch MasterMind

#11 Post by foxidrive » 04 Jan 2015 08:03

It works well Antonio. :)

An enhancement that would be useful is to enable the Escape key to abort the game at any key input.

I altered the part below, if you think any part of it is useful.

Code: Select all

:begin
cls
set codelength=4
set digits=6
set guesses=10

echo/
echo                 MasterMind is a code-breaking game.
echo/
echo    With the current settings the code-to-break is comprised of ^< %codelength% ^> numbers,
echo    each of which contains a numeral from 1 to ^< %Digits% ^>.
echo/
echo    You have ^< %Guesses% ^> turns to crack the code. After each turn the number of
echo    ^< X ^> characters indicates how many digits match in the correct position, and
echo    the number of ^< O ^> characters indicates how many match in an incorrect position.
echo/
echo Press the Enter key to start the game, or BackSpace to change the values.
set /P "=Code length: %codelength%   Digits from one to: %digits%   Guesses: 10" < NUL
set "values=%codelength%   Digits from one to: %digits%   Guesses: %guesses%"

:readValues

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch MasterMind

#12 Post by dbenham » 04 Jan 2015 08:57

Nicely done Antonio. I like your turn scoring algorithm better than mine - more direct and efficient. Your UI also works well.

However, The main reason I did not use your readFormattedLine is because of the way I like to formulate my guess as I play.

I don't always formulate my guess from left to right. I may decide I want to place a 6 in the far right, but not sure yet about the other digits. So I would toggle over-strike mode on and then enter <space><space><space>6. Then, whenever I decide on a new digit, I can use the arrow keys to get there and enter it. I can freely modify any position I want without losing other positions.

I didn't see an obvious way to have readFormattedLine support that feature.


Dave Benham

T3RRY
Posts: 243
Joined: 06 May 2020 10:14

Re: Batch MasterMind

#13 Post by T3RRY » 19 Jun 2020 11:55

Trawling through the annals of Batch History, I thought I'd add a little version of my own.

Introducing MasterMind the Macro

Code: Select all

@Echo off & TITLE Mastermind [1-8] [Q]uit
    (Set \n=^^^
%= Newline Var - Do not modify =%
)
::: { Creates variable /AE = Ascii-27 escape code.
::: - http://www.dostips.com/forum/viewtopic.php?t=1733
::: - https://stackoverflow.com/a/34923514/12343998
:::
::: - /AE (Alt 146) can be used  with and without DelayedExpansion.
    Setlocal
    For /F "tokens=2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
        Endlocal
        Set "/AE=%%a"
    )
::: }
	Set Mastermind=For %%n in (1 2) Do If %%n==2 (%\n%
    For /F "Tokens=1,2,3,4 Delims={}" %%G in ("!INPUT!") Do (%\n%
	^<Nul Set /P "=Guess %%J: "%\n%
	Set "Guess#=%%J"%\n%
        Set "%%G="%\n%
        For /L %%# in (1 1 %%I) Do (%\n%
            For /F "Delims=" %%C In ('Choice /N /C:%%H') Do (%\n%
		If /I "%%C" == "Q" Exit /B 0%\n%
                ^<Nul Set /P "=!C#[%%C]!%%C%/AE%[0m"%\n%
                Set "%%G=!%%G!%%C"%\n%
            )%\n%
        )%\n%
	Set "Guess=!%%G!"%\n%
    )%\n%
	Set /A EXmatch=0,PAmatch=0%\n%
        For /L %%c in (0 1 4) Do (%\n%
	    For /L %%d in (0 1 4) Do If Not %%c==%%d If Not "!Code:~%%d,1!" == "!Guess:~%%d,1!" If Not "!Code:~%%c,1!" == "!Guess:~%%c,1!" (If "!Code:~%%d,1!" == "!Guess:~%%c,1!" Set /A PAmatch+=1)%\n%
	    If "!Code:~%%c,1!" == "!Guess:~%%c,1!" (Set /A EXmatch+=1)%\n%
	)%\n%
	Set "GuessMatch=_____"%\n%
	For /L %%e in (1 1 !EXmatch!) Do Set "GuessMatch=X!GuessMatch:~,-1!"%\n%
	For /L %%f in (1 1 !PAmatch!) Do Set "GuessMatch=O!GuessMatch:~,-1!"%\n%
	^<Nul Set /P "=. !GuessMatch!"%\n%
	Echo/%\n%
	IF /I "!GuessMatch!" == "XXXXX" (Echo/you won ^& Pause ^& Goto :Game)%\n%
	If "!Guess#!" == "12" (Echo/you lost ^& Echo/Code was: !Code! ^& Pause ^& Endlocal ^& Goto :Game)%\n%
) Else Set INPUT=
::: [End Macro Definition]
:Game
	CLS & Setlocal EnableDelayedExpansion
	Set /A Red=31,Yellow=33,Green=32,Blue=34,Gray=90,Pink=91,Magenta=95,Cyan=36,CI#=0
	For %%A in (Red,Yellow,Green,Blue,Pink,Gray,Magenta,Cyan) do (
		Set "%%A=%/AE%[!%%A!m"
		Set /A "CI#+=1"
		Set "C#[!CI#!]=!%%A!"
	)
	Set Code=
	For /L %%# in (1 1 5) Do (
		Set /A RND=!Random! %% 8 + 1
		Set "Code=!Code!!RND!"
	)
	For /L %%# In (1 1 12) Do %Mastermind%{Guess[%%#]}{12345678q}{5}{%%#}
Downside of the input mode is once a numbers entered for a guess, It's locked in.

Post Reply