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.
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
cmd | *sh | ruby | chef