CMD Batch Script Multiplication Table

Microsoft Windows
Post Reply
User avatar
MigrationUser
Posts: 336
Joined: 2021-Jul-12, 1:37 pm
Contact:

CMD Batch Script Multiplication Table

Post by MigrationUser »

12 Oct 2012 16:31
e-j

Thought I'd share a script I threw together recently for kicks. It can multiply up to 31 as is. Beyond that I'd need to change the way the table is stored from a single string variable to one for each row to avoid hitting the cmd.exe variable length limitations.

Image
w-s-a.blogspot.com/2012/10/cmd-batch-script-multiplication-table.html

Always trying to improve my scripting capabilities/efficiency so feel free to post suggestions/comments. My "programming" background is just about nil so please excuse any asinine code in there.

Code: Select all

@ECHO OFF
::Set console properties along with proportions to accommodate max table size
MODE con:cols=126 lines=70
TITLE Multiplication Table :: ejSoft
COLOR 0A
SETLOCAL EnableDelayedExpansion
ECHO +----+----+----+----+----+
ECHO ^|  Multiplication Table  ^|
ECHO ^|   ejSoft v12.10.10.2   ^|
ECHO +----+----+----+----+----+
:_init
::Set starting null values for variables
SET $count=0
SET $output=
SET $border=
SET $endNum=0
ECHO +
::Prompt user to input max multiplier
SET /P $endNum=^|  Enter multiplier range (1 to n) or q to quit: 
ECHO +
IF %$endNum% == q goto:eof
::Validate user input as positive integer greater than zero and less than 31 (peak multiplier before output string becomes too large for CMD)
SET /A $eval=%$endNum%
IF %$eval% NEQ %$endNum% ECHO Invalid^^! && GOTO _init
IF %$endNum% LSS 1 ECHO Invalid^^! && GOTO _init
IF %$endNum% GTR 31 ECHO Value too high^^! && GOTO _init
::Calculate products ($product) from 1 up to user supplied number ($endNum).
::Modulus operator is used to determine when remainder ($mod) of loop counter ($count) divided by max row length ($endNum) equals 0.
::_buildTable sub routine is called to store each new $product into the $output string variable with a preceding pipe character as a "cell wall". Leading padding is added to right-align numbers less than 3 digits within "cells".
::If $mod equals zero, add comma to build CSVs to delimit each row inside output string ($output).
::Top/bottom "table border" is generated each time ($endNm) top FOR loop runs.
FOR /L %%G IN (1,1,%$endNum%) DO (
FOR /L %%1 IN (1,1,%$endNum%) DO (
SET /A $count+=1
SET /A $mod=!$count!%%!$endNum!
SET /A $product=%%G*%%1
CALL :_buildTable
IF !$mod!==0 SET "$output=!$output!,"
)
SET "$border=+---!$border!"
)
::Echo top "table border" with end plus character added.
ECHO %$border%+
::Loop through comma delimited $output string variable to echo each "CSV" as a row.
::Top FOR loop iterates the token/"row" number passed to called _render sub routine. Sub also echos each "row end cell wall" pipe character.
::Echo bottom "table border" with end plus character added.
FOR /L %%A IN (1,1,%$endNum%) DO (
SET $line=%%A
CALL :_render
ECHO %$border%+
)
::Back to start
GOTO _init
:_buildTable
IF !$product! GTR 99 (
SET "$output=!$output!^|!$product!"
goto:eof
)
IF !$product! GTR 9 (
SET "$output=!$output!^| !$product!"
goto:eof
)
SET "$output=!$output!^|  !$product!"
goto:eof
:_render
FOR /F "tokens=%$line% delims=," %%A IN ("!$output!") DO (
ECHO %%A^|
)
----------------------------

#2 15 Oct 2012 11:22
bluesxman


Hi, this alternative I've just put together (mostly) overcomes the variable length problem you mention. Though it does suffer from some other ceilings...

The divider line won't render fully past a multiplier of 1023.
The maximum render width in a CMD window 9999 columns wide is with a multiplier of 1249.
The theoretical maximum multiplier for this is 46340. This will take quite some time to render.

(Though I've not bothered to include much in the way of input validation).

I've included comments to help you see what's going on. Hopefully the methods I've used will help your own coding.

Code: Select all

@echo off

REM delayed expansion makes several of the operations much easier
setlocal enabledelayedexpansion

REM the multiplier can be passed as a command line arguement
set "max=%1"

set /p "max=>: "

if "%max%" EQU "" goto :EOF

call :build.div

for /l %%a in (1,1,%max%) do (
	REM draw the first divider line, and first "|" for the output line
	echo:%div%
	set /p "out=|" <nul
	call :multiply %%a
)

REM draw the final divider
echo:%div%

pause

endlocal

goto :EOF

:multiply

for /l %%b in (1,1,%max%) do (
	REM multiply the passed values and store as VAL
	set /a "val=%1 * %%b"

	REM pad VAL with spaces
	set "val=            !val!"

	REM trim VAL to length LEN
	set "val=!val:~-%len%!"

	REM output current VAL with "|"  separator (without a carriage return at the end!)
	set /p "out=!val!|" < nul

)

echo:

goto :EOF

:build.div

set "cell="
set "div="
set "len=0"

REM generate the highest value, so we can find its length
set /a maxmax=max * max

REM get the length of the highest value as LEN
for /l %%a in (0,1,12) do (
	if "!maxmax:~%%a,1!" NEQ "" set /a "len+=1"
)

REM use LEN to build the horizonal line between cells as CELL
for /l %%a in (1,1,%len%) do set "cell=!cell!-"

REM count to MAX to build DIV from CELL (and + symbols)
set "div=+"
for /l %%a in (1,1,%max%) do set "div=!div!!cell!+"

goto :EOF
Last edited by bluesxman (15 Oct 2012 14:47)

cmd | *sh | ruby | chef
Post Reply