Batch file - Pick a card - batch-file

I created a batch file that selects a random playing card using the variable %random%. the batch script keeps looping until %random% is between 1 and 13, and does it again for the suit. I then convert the variables that are set as numbers into text, so the batch file would say something like this: Four of Hearts, or King of Spades. The only problem is, it takes forever! If you open CMD.exe and type in
Echo %random%
and do that until the number is between 1 and four, you will be there FOREVER. Even if you put it into a batch file and use a loop, It still takes about twenty seconds. Is there a way to cut down the time, by perhaps narrowing down the search BEFORE the random number generation? I'm really not sure. In case it helps, or you can't understand me, here's the code:
#echo off
:loop
cls
echo generating card...
set num=%random%
if /i %num% GTR 13 goto loop
if /i %num% LSS 1 goto loop
goto next
:next
set suit=%random%
if /i %suit% GTR 4 goto next
if /i %suit% LSS 1 goto next
goto next2
:next2
if %num%==11 set num=jack
if %num%==12 set num=queen
if %num%==13 set num=king
goto next3
:next3
if %suit%==1 set suiter=Hearts
if %suit%==2 set suiter=Diamonds
if %suit%==3 set suiter=Clubs
if %suit%==4 set suiter=Spades
goto ech
:ech
echo %num% of %suiter%
echo.
echo.
echo.
echo press any key to choose again
pause >nul
goto loop

You can use a little math to get a number between 1 and 13 on the first try:
set /a num=13*%random%/32768+1
and the same thing for 1 and 4
set /a suit=4*%random%/32768+1
See How to use random in BATCH script? - very similar to what you're asking

You can completely eliminate the search using a simple remainder operation, thus limiting the generated random numbers to be in the range [1,13] and [1,4]. This will also simplify the code much. You can achieve this using the 'set /a' command which can be used for arithmetic.
Just change your script to read:
#echo off
:loop
cls
echo generating card...
set /a num=%random% %% 13 + 1
set /a suit=%random% %% 4 + 1
if %num%==11 set num=jack
if %num%==12 set num=queen
if %num%==13 set num=king
if %suit%==1 set suiter=Hearts
if %suit%==2 set suiter=Diamonds
if %suit%==3 set suiter=Clubs
if %suit%==4 set suiter=Spades
goto ech
:ech
echo %num% of %suiter%
echo.
echo.
echo.
echo press any key to choose again
pause >nul
goto loop
Good luck!

Related

Unknown glitch in batch

I need help with an unknown issue in a recent batch file executed on Windows 10.
Proper function:
I am trying to make a math quiz which generates two numbers, a basic operand (+-x/), finds the answer, then checks it against an answer from a user. Additionally, the program is made to track certain information after a user has put in their answer. (Question number, the problem and answer, and the users response.)
My issue:
In certain scenarios the program will display the problem/answer in the "game" window rather than writing the problem/answer in the text file as intended.
The command is:
echo [Q]%m%>>"C:\Users\%username%\Desktop\%fname%.txt"
It is comment marked in the code below.
What I've done to fix the issue?
After testing for a descent while I discovered the issue seemed to revolve around the portion where it tries to move a problem/answer combo with division as the operation. This helped, but the issue started randomly popping up throughout future attempts to debug.
While I feel it is a bit frowned upon to ask two things at once I have two more issues.
Why does an operation like %a%%b%%c%=%d% (a,c,d being numbers and b being a /) break a certain command in my code consistently and how can I fix it?
Why does the same issue still randomly appear even if I erase all traces of division / which seems to cause my issue in the first place.
Here is the batch file:
::Initialization
#echo off
set /a prb=3
set file=Stat
set sss=s.
if %prb%==1 set tst=.
echo.
echo Welcome to math fire, you will get randomly generated
echo multiplication, addition, and subtraction problems. You
echo will go through a specified number before the game ends
echo and this window closes. You will be tracked in a file on
echo your desktop. You will have %prb% problem%sss%
echo.
pause
CLS
echo Get ready
timeout 5
set start=%time%
CLS
set /a num=1
set /a good=0
set /a bad=0
::===========================Set up beggining of stat file.
echo =-=-=-=-=-=>>"C:\Users\%username%\Desktop\%fname%.txt"
echo ===Start===>>"C:\Users\%username%\Desktop\%fname%.txt"
echo =-=-=-=-=-=>>"C:\Users\%username%\Desktop\%fname%.txt"
echo.>>"C:\Users\%username%\Desktop\%fname%.txt"
::===================================Main Body============
::[A] Num1 [B] Operator [C] Num2 [D] Answer [E] The problem [M] Problem and answer
:main
set /a a=%random% %% 30 + 1
::To remove the division section I changed the 4 below to 3
set /a b=%random% %% 4 + 1
set /a c=%random% %% 20 + 1
if %b%==1 set b=+
if %b%==2 set b=-
if %b%==3 set b=*
if %b%==4 set b=/
set /a d=%a%%b%%c%
set e=%a%%b%%c%
echo.
echo =============================%e%=?
echo.
timeout 1
set /p ans=+++++++++++++++++++++++++++++Answer:
set m=%e%=%d%
echo ===%num%===>>"C:\Users\%username%\Desktop\%fname%.txt"
::The following line is the glitching code
echo [Q]%m%>>"C:\Users\%username%\Desktop\%fname%.txt"
echo [A]%ans%>>"C:\Users\%username%\Desktop\%fname%.txt"
echo.>>"C:\Users\%username%\Desktop\%fname%.txt"
if %ans%==%d% goto p
CLS
echo.
echo -----------------------------Incorrect
set /a bad=%bad%+1
goto re
:p
CLS
echo.
echo -----------------------------Correct
set /a good=%good%+1
goto re
:re
if %num%==%prb% goto end
set /a num=%num%+1
goto main
:end
echo ===========>>"C:\Users\%username%\Desktop\%fname%.txt"
echo.>>"C:\Users\%username%\Desktop\%fname%.txt"
echo [Start]%start%>>"C:\Users\%username%\Desktop\%fname%.txt"
echo [-End-]%time%>>"C:\Users\%username%\Desktop\%fname%.txt"
echo [Right]%good%>>"C:\Users\%username%\Desktop\%fname%.txt"
echo [Wrong]%bad%>>"C:\Users\%username%\Desktop\%fname%.txt"
echo.>>"C:\Users\%username%\Desktop\%fname%.txt"
echo =-=-=-=-=-=>>"C:\Users\%username%\Desktop\%fname%.txt"
echo ===-End-===>>"C:\Users\%username%\Desktop\%fname%.txt"
echo =-=-=-=-=-=>>"C:\Users\%username%\Desktop\%fname%.txt"
echo.>>"C:\Users\%username%\Desktop\%fname%.txt"
CLS
echo.
echo.
echo.
echo Congrats, check your desktop for your play info.
echo.
echo.
echo.
pause
exit
Use the syntax
>>"%filename1%" echo [Q]%m%
(my testfiles are allotted in variables)
Noting that m will contain a string such as 13/14=0
The character just before a redirector redirects the logical device number. You can get around this by moving the redirction to the start of the command or inserting a space before the redirector or using
>>"%filename1%" (
echo [Q]%m%
echo something else
echo more text
)
or
(
echo [Q]%m%
echo something else
echo more text
)>>"%filename1%"
which does the same thing - gather the output of the echoes and redirect the sum-output to the file.
Oh, BTW - batch does integer mathematics, so 13/4=3 - no decimals.

Using Multiple GTR, LEQ, etc "if" statements in Batch

I have a batch file that asks the user to input a specific number. If the number is in between a given set of numbers, it goes to that label. However, say the user puts 100 it goes right to :smallsip
All in all, I'm trying to make it so that if the user types a number within a specific range (I.E 30-99) it goes to a specific label. Any suggestions?
:getadrink
cls
echo How many sips will Jackie Chan drink?
set /p numberofsips=Type Number of Sips Here:
if %numberofsips% LSS 0 goto waitwhat
if %numberofsips% GEQ 1 goto smallsip
if %numberofsips% GEQ 10 goto plenty
if %numberofsips% GEQ 30 goto toomuch
if %numberofsips% GEQ 100 goto waytoomuch
:waitwhat
cls
echo what
pause
:smallsip
cls
echo small sips
pause
:plenty
cls
echo plenty
pause
:toomuch
cls
echo too much!
pause
:waytoomuch
cls
echo WAY TOO MUCH
pause
P.S. I've been lurking around numerous posts on here, getting help for something I'm creating with Batch. Yes, I know batch is outdated, but I just seem to like it as I have discovered it about 2 months ago.
The if statements in your code work correctly, but your logic is wrong. For instance, when you type a number 50, the condition %numberofsips% GEQ 1 is already met, so the following if statements will never be reached. To solve this, simply reverse their order.
Another problem is, that you fall into fall into code which you do not want to be executed. For example, when the portion :smallsip has finished (and you confirmed the pause), execution continues at :plenty unintentionally. To avoid that, you will need a goto to jump somewhere else or an exit /B to leave the batch script.
Here is a fixed code:
:getadrink
cls
echo How many sips will Jackie Chan drink?
:askforsips
set numberofsips=0
set /p numberofsips=Type Number of Sips Here:
if %numberofsips% GEQ 100 goto waytoomuch
if %numberofsips% GEQ 30 goto toomuch
if %numberofsips% GEQ 10 goto plenty
if %numberofsips% GEQ 1 goto smallsip
goto waitwhat
:waitwhat
cls
echo what?
pause
goto askforsips
:smallsip
cls
echo small sips
pause
exit /B
:plenty
cls
echo plenty
pause
exit /B
:toomuch
cls
echo too much!
pause
goto askforsips
:waytoomuch
cls
echo WAY TOO MUCH
pause
goto askforsips
These are the things that I changed:
the order of if queries is reversed;
the if %numberofsips% LSS 0 query is removed, so :waitwhat is executed if the entered value is zero or less; in your code, :waitwhat was also executed in case the value was zero as none of the conditions were met; the final (lonely) goto waitwhat is not required here, but it is more obvious what happens;
a new label :askforsips is introduced to allow another user input in case an invalid value (zero or less) was given;
variable numberofsips is now reset before the user prompt, because set /P keeps the former value if the user just presses ENTER;
every section from :waitwhat down to :waytoomuch is terminated explicitly, either by goto askforsips or by exit /B;

My text based game script is not working

I am making a text based rpg and the script is not working. It has something to do with the stamina. I also have a quest that is dependent on you having a certain amount of gold and that script is not working as well. I will include pictures.
:harvest
cls
echo Press 1) to harvest
set /p input17=enter:
if %input17%==1 set /a wheat= %wheat% + 5
if %input17%==1 set /a carrots= %carrots% +4
if %input17%==1 set /a stamina= %stamina% - 25 (this line)
if %stamina% < 0 goto nostamina (this line)
echo.
echo You get some wheat and some carrots.
echo.
echo check your inventory for accurate numbers.
echo.
echo Press 1) to go back.
pause >nul
goto insidehouse
:insidehouse
cls
echo You are now inside of your house.
echo.
echo Press 1) to harvest.
echo Press 2) to sell all crops.
echo Press 3) to go into your inventory.
echo Press 4) to sleep eight hours.
echo Press 5) to check for quests.
set /p input16=enter:
if %input16% EQU 1 goto harvest
if %input16% EQU 2 goto market
if %input16% EQU 3 goto Inventory1
if %input16% EQU 4 goto sleep
if %input16% EQU 5 (and) if %gold% LSS 0 goto shopping (this line)
You haven't provided much code to work with so, I can only guess at a solution.
My best guess is that you are atempting to update a variable from inside a for loop. If this is the case you need to add this line to the top of your batch file: setlocal enabledelayedexpansion. You will also need to access the affected variables like this !var! instead of this %var%.
setlocal enabledelayedexpansion causes expansion of variables to delayed in your batch file. What this will mean in the context of your program is that variables can be updated from within a for loop.

Batch roguelike errors

I am trying to make a batch roguelike but I am running in to three main problems. First of all my message system is not working. Second there is a glitch where if i try to move somewhere where I can't the choice statement keeps writing the W, S, A, and D's at the bottom. Third and most importantly there is a very annoying flashing of the screen. I tried to minimize the time it takes to load but to no avail. Here is my code:
#echo off
setlocal enableextensions
mode con: cols=54 lines=30
set num=1
set nextVar=1
set oldVar=103
set message=a
cls
echo Loading...
:startup
if not %num%==1001 (
set b%num%=.
set /a num = %num% + 1
goto startup
)
cls
set b103=#
goto update
:update
choice /c wsad /n /m ""
if %errorlevel%==1 set /a nextVar = %oldVar% - 50
if %errorlevel%==2 set /a nextVar = %oldVar% + 50
if %errorlevel%==3 set /a nextVar = %oldVar% - 1
if %errorlevel%==4 set /a nextVar = %oldVar% + 1
if defined b%nextVar% (
set b%nextVar%=#
set b%oldVar%=.
set oldVar=%nextVar%
set message="a"
goto display
)
set message="You can not move there."
goto update
:display
set ln1=%b1%%b2%%b3%...
set ln2=%b51%%b52%%b53%...
set ln3=%b101%%b102%...
...
...
...
set ln8=%b351%%b352%...
set ln18=%b851%%b852%%b853%
set ln19=%b901%%b902%%b903%%b904%...
set ln20=%b951%%b952%%b953%%b954%%b955%%b956%...%b1000%
cls
if not "%message%"=="a" (
echo %message%
goto next
)
echo.
:next
echo.
echo %ln1%
echo %ln2%
echo %ln3%
echo %ln4%
echo %ln5%
echo %ln6%
echo %ln7%
echo %ln8%
echo %ln9%
echo %ln10%
echo %ln11%
echo %ln12%
echo %ln13%
echo %ln14%
echo %ln15%
echo %ln16%
echo %ln17%
echo %ln18%
echo %ln19%
echo %ln20%
echo.
goto update
I had to ... some sections to save space. If anyone can solve these problems in particularity the screen flashing that would be super helpful. Also if anyone has ideas on generation NetHack like dungeons that would also be appreciated. Thank you.
So problems 1 and 2 are related.
First of all my message system is not working. Second there is a glitch where if i try to move somewhere where I can't the choice statement keeps writing the W, S, A, and D's at the bottom.
Change the error goto statement for the update section. You want to go to the display section so the screen is redrawn (removing the old used choice prompt) and the error message is displayed.
set message="You can not move there."
goto display
Problem 3 is a bit more difficult due to the nature of batch.
Third and most importantly there is a very annoying flashing of the screen.
The flashing is caused primarily because of one command. The cls command. Instead of just redrawing the screen it is first causing the screen to turn black before the new output is drawn causing the flicker.
Step 1: Remove the cls command. This means that you will have to output 30 lines each time to fill the screen.
Reducing the flicker even more will require a bigger overhaul on your script. Instead of echoing each line use the natural ability of the command window to wrap lines to draw the whole screen. This will reduce the amount of echo calls to a couple. Your canvas is set to 54 x 30 so that equals 1620 characters to fill the whole screen at one time.
Step 2: Output the entire screen with a single or as few calls as possible to prevent drawing/scrolling delay and use the natural line wrapping ability of the console window.
Here is an example I put together to illustrate this second step. Let me know if you have any questions.
#echo off
( if "%~1"=="" start "" /HIGH %0 1 & exit /b 1 )
setlocal enabledelayedexpansion
mode con: cols=80 lines=25
set "mark=0"
set "switch=0"
:next
if %mark% geq 920 set "mark=0" & if %switch% equ 0 ( set "switch=1" ) else set "switch=0"
set top=........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
set bot=........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
if %switch% equ 0 set top=!top:~0,%mark%!^|!top:~%mark%!
if %switch% equ 1 set bot=!bot:~0,%mark%!^|!bot:~%mark%!
goto display
:display
echo %mark%
set /p "=%top:~0,920%" <nul
set /p "=%bot:~0,920%" <nul
ping 192.0.2.2 -n 1 -w 200 >nul
set /a mark+=1
goto next
Step 3: An additional step that helps would be to increase the processes priority level. I have also added this to my example script above on the second line.

Creating a geometrically decaying pause loop

So I am working on creating a batch file game analogious to a "Memory" game. (ie where the player is presented a list of objects for a short time, then asked to repeat the pattern)
My problem comes in how to decrease the time the pattern is exposed to the player as the round # increases.
Here is my current code:
#echo off
set /a y=50
set /a x=1000
:foo
set /a y=%y% + %y%
set /a x= %x% - %y%
echo %y%
echo %x%
ping -n 10 -w %x% 127.0.0.1 > nul
goto foo
When run, the above code does present x and y values that change as expected, however the wait time is always the same. Why is this and how can I fix it?
Thank you for your time.
Firstly why dont you use sleep? It would work fine (type sleep /? for more info)
However, here is another way of doing this with for /l loops
#echo off
setlocal enabledelayedexpansion
set score=0
title Memory Test : Current Score = !score!
for /l %%a in (0,1,20) do (
Rem In the above sequence, increase 20 to the amount of times you want the test to be performed
set number[%%a] = !random!!random!
echo Number: !number[%%a]!
set /a wait=21-%%a
set /a wait=!wait!*1000/4
sleep -m !wait!
cls
set /p "input=What was the last number youy saw? "
if !number[%%a]! equ "!input!" (
set /a score=!score!+1
Echo Correct !
title Memory Test : Current Score = !score!
)else(
Echo Incorrect! Coreect Answer = !number[%%a]!
)
)
echo Calculating score...
pause
cls
echo.
if %score% leq 14 set msg="Nice Try! But you can do better!"
if %score% geq 15 set msg="Good Job! Your on your way to the top!"
if %score% equ 20 set msg="Your So Close! Almost a perfect socre!"
if %score% equ 21 set msg="You got a perfect score! Woderful!"
Echo %score%/21 : %msg%
echo.
pause
And that should work fine. Note you can change how long the test goes for, but for the first game they'll have a bit more then 5 seconds to study the question, and in the last round a quarter of a second!
Mona
In order for the ping/wait trick to work, the ip address must not exist. 127.0.0.1 is your own computer, so it has no opportunity to timeout since the ping response is successful and immediate.
Instead, choose an ip address that doesn't exist. E.g. 10.20.30.40 (assuming that doesn't exist.)
You can adjust the 10 in this to give approximately second resolution. Is that sufficient for your code?
ping -n 10 127.0.0.1 > nul
This is another option for later windows.
timeout /t 10 >nul

Resources