# Coding Challenge #12: Draw the multiplication

## Coding Challenge #12

Hello! Welcome back to another challenge. I am still looking for people to help me out and make challenges as well! So if you’re interested, help me out!

As usual, same requirements:

• Has to be written in Lua 5.1 (the version Roblox uses)
• The program has to be compatible with Roblox Studio, meaning you can’t use features vanilla Lua has but Luau has disabled
• You can’t use httpservice to cheat the challenge

Given two positive integers, write a function a `draw(a, b)` that draws the way you would write the multiplication of `a` and `b` by hand. (This function will print the thing instead of returning it)

Goodluck! You can find a list of all the challenges here or a github version here.

``````local function draw(a, b)
local n = math.clamp(#tostring(a*b), 2, math.huge) --this is in case b was less than 3, because the --- line always has to be 3-long
--n would just be the length of the final result
print(string.rep(" ", n-#tostring(a))..a) --string.rep(" ", n-#tostring(a)) this is calculating how many spaces to put before a
print("x"..string.rep(" ", n-#(" "..b))..b) --"x"..string.rep(" ", n-#(" "..b)) calculates how many spaces before b, including the x sign
print(string.rep("-", n)) --the --- line
local sum = 0 --this is the end result
for i = #tostring(b), 1, -1 do
if not(string.sub(b, i, i) == "0") then --if the current digit is 0 we just discard the current line
local add = a*string.sub(b,i,i)*10^(#tostring(b)-i) --this is the current number, a*string.sub(b,i,i) is multiplying the current digit with a, 10^(#tostring(b)-i) decides how many zeros it has
end
end
print(string.rep("-", n))
print(string.rep(" ", n-#(tostring(sum)))..sum)
end
``````
10 Likes

This looks pretty hard, I can’t wait to try it out. Hopefully I’ll solve it, but I rarely do, not smart enough.

1 Like

I can’t wait to try this out! Thanks so much!

1 Like

You didn’t specifiy whether the integers were positive or negative, and your answer errors for me when I pass a negative number.

Here is my approach (which uses a lot less string manipulation):

``````local function CharacterAmount(Num)
local CharAmount = math.log(math.abs(Num),10)
if CharAmount%1 ~= 0 then
CharAmount = math.ceil(CharAmount)
else
CharAmount += 1
end
if Num < 0 then
CharAmount += 1
end
return math.max(CharAmount,1)
end
local function draw(a,b)
local Result = a*b
local CharAmountB = CharacterAmount(b)
local CharLimit = math.max(CharacterAmount(a),CharAmountB,CharacterAmount(Result))+2
local CharFormat = string.format("%%%ii",CharLimit)
print(string.format(CharFormat,a))
print(string.format(string.format("x%%%ii",CharLimit-1),b))
local Seperator = string.rep("-",CharLimit)
print(Seperator)
if a ~= 0 and b ~= 0 then
for i=1,b > 0 and CharAmountB or CharAmountB-1 do
local Pow = 10^(i-1)
local Char = math.fmod(math.floor(b/Pow),10)
if Char ~= 0 then
print(string.format(CharFormat,a*Char*Pow))
end
end
print(Seperator)
end
print(string.format(CharFormat,Result))
end
``````
4 Likes

Here’s my approach:

code
``````local finalFormat, partialFormat = [[%s%d
×%s%d
%s%s
%s
%d]], [[

%s%s]]

return function(multiplicand, multiplier)
local product = multiplicand * multiplier
local sign = math.sign(product)

local absMultiplicand, absMultiplier = math.abs(multiplicand), math.abs(multiplier)

local multiplicandString, multiplierString, productString = tostring(multiplicand), tostring(multiplier), tostring(product)
local absMultiplierString = tostring(absMultiplier)

local plicandLength, plierLength, absPlierLength, productLength = #multiplicandString, #multiplierString, #absMultiplierString, #productString -- not typing that out would be nice lol

local partialProduct = [[]]

for i = absPlierLength, 1, -1 do
local digit = absMultiplierString:sub(i, i)

local temp = digit * absMultiplier * sign .. ([[0]]):rep(absPlierLength - i)

if 0 ~= tonumber(temp) then
partialProduct ..= (partialFormat):format(([[ ]]):rep(productLength - #tostring(temp)), temp)
end
end

local divider = ([[-]]):rep(productLength)

local final = finalFormat:format(([[ ]]):rep(productLength - plicandLength), multiplicand, ([[ ]]):rep(productLength - (plierLength + 1)), multiplier, divider, partialProduct, divider, product)

return final
end
``````

Most of my time was spent trying to right align numbers and get the right number of dashes to have everything line up. I think I’ve got it, though. Not the prettiest code for the job, certainly, but it works.

Edit: Should work with negatives now, thanks Halalaluya.

5 Likes
``````local function draw(a,b)
local myA = tostring(a)
local myB = tostring(b)
if a < b then
myA = tostring(b)
myB = tostring(a)
end
print("         "..myA)
print("x".."         "..myB)
print("____________")
for i = #tostring(b), 1, -1 do
print("         "..tostring(string.sub(tostring(b), i, i + 1)) * a)
end
end
``````

(Its a bit offset but it works.)

2 Likes

I guess I’ll share my approach, too

My approach
``````local function draw(a, b)
local products = {}
for i = 1, tostring(b):len() do
local multiplier = math.floor(b % (10 ^ i) / (10 ^ (i - 1))) * (10 ^ (i - 1))
if multiplier * a ~= 0 then
table.insert(products, a * multiplier)
end
end
local lineLength, sum = math.max(tostring(a):len(), tostring(b):len() + 2), 0
for _, product in ipairs(products) do
sum = sum + product
lineLength = math.max(tostring(product):len(), lineLength)
end
lineLength = math.max(lineLength, tostring(sum):len())
-- Now there's just printing everything
local function format(str) -- New print function
return string.rep(" ", lineLength - str:len()) .. str
end
print(format(tostring(a)) .. "\nx" .. string.rep(" ", lineLength - tostring(b):len() - 1) .. tostring(b))
print(string.rep('-', lineLength))
for _, product in ipairs(products) do
print(format(tostring(product)))
end
print(string.rep('-', lineLength))
print(format(tostring(sum)))
end
``````
2 Likes

Here is my solution:

``````function idk(top, bottom)
local maxLen = string.len(tostring(top * bottom))
print(string.rep('_', maxLen - string.len(top)) .. tostring(top))
print('X' .. string.rep('_', (maxLen - string.len(bottom)) - 1) .. tostring(bottom))
--	print(maxLen)
--	print(string.len('X' .. string.rep('_', (maxLen - string.len(bottom)) - 2) .. tostring(bottom)))
print(string.rep('..', maxLen))
local botStr = tostring(bottom)
local products = {}
local numZeros = 0
for x = string.len(botStr), 1, -1 do
local digit = tonumber(string.sub(botStr, x,x))
local multiplySlotNum = tonumber((tostring(digit) .. string.rep('0', numZeros)))
table.insert(products, (multiplySlotNum * top))
local space = maxLen - string.len((multiplySlotNum * top))
if (multiplySlotNum * top) ~= 0 then
print(string.rep('_', space) .. (multiplySlotNum * top))
else

end
numZeros += 1
end
print(string.rep('_', maxLen))
local sum = 0
for x = 1, #products do
sum += products[x]
end
print(sum .. '\n' .. ' New Stuff \n')
end

idk(23958233, 5830)
idk(78, 14086)
``````

I’m not sure if I cheated by just multiplying the current digit added with 0 by the top, but my printed result looks the same as yours. I’m surprised I managed to do this, but really happy as well.

3 Likes
``````function draw_math (x, z)
-- Variable Setup; Convert args to strings
local product, line_len, line
x, z, product = tostring(x), tostring(z), tostring(x*z)

-- Length function to align text on right; const line string
line_len = math.max(2+#z, #product)
line = ('-'):rep(line_len)
local function right(str) return ( (' '):rep(line_len)..str):sub(-line_len) end

-- Output
print(right(x), '\n'.. right('x '..z), '\n'.. line)
for i=#z, 1, -1 do
local z_i = string.byte(z, i)-48
if math.clamp(z_i, 1, 9)~=z_i then
continue
end
print(  right( (z_i*x)..(' '):rep(#z-(i)) )  )
end
print(line,'\n'..right(product) ..'\n')
end
``````

Yeah I don’t remember adding a 0 to the right after every smaller multiplication. I just left a blank space.

1 Like

I only used number manipulation in my attempt, using `math.log(x, 10)` to get the number’s length and voodoo magic `string.format` to right-justify everything:

code
``````local function draw(a, b)

-- finding the numbers
local bDigits = math.log(b, 10)
for i = 0, bDigits do
local digit = math.floor(b / 10^i) % 10
if digit ~= 0 then
table.insert(addends, a * digit * 10^i)
end
end
local product = a * b

-- formatting
local formatNumber = string.format("%%%dd\n", width)
local formatOp = string.format(" %%%dd\n", width - 2)
local separator = string.rep("-", width) .. "\n"

local formatString = string.format("%s*%s%s%s+%s%s%s",
string.format(formatNumber, a),
string.format(formatOp, b),
separator,
separator,
string.format(formatNumber, product):sub(1, -2)
)

end
``````

I have no idea where to put `:sub(1, -2)` in terms of organization…

It looks pretty clean in my opinion

Edit: oops, didn’t mean to reply to you goldenstein

Burns my corneas to look at, but hey, I’d like to see someone compactify this challenge further than I did (without minifying the code).

``````function draw(a, b)
local aStr, bStr = '' .. a, '' .. b
local bar = ('-'):rep(math.max(#('' .. a*b), math.max(#aStr, #bStr) + 2))
local count, sign = -1, math.sign(b)
print(('% d\nx% d\n%s\n%s%s\n% d')
:gsub(' ', #bar):format(a, b, bar, bStr:reverse():gsub('%d', function(num)
count = count + 1
local result = a * num * sign * 10^count
return result > 0 and ('%' .. #bar .. 'd'):format(result) .. '\n' or ''
end), bar, a*b):gsub('x ', 'x'))
end
``````
2 Likes

Here’s my solution 1 year later

``````function rjust(s,l,p)
return string.rep(p or " ",l-#s)..s
end

function draw(n,m)
local barlength = #tostring(n*m)+1

local a = rjust(tostring(n),barlength)
local b = "x"..rjust(tostring(m),barlength-1)

print(a)
print(b)
print(string.rep("-",barlength))

for i = 1,#tostring(m) do
local x = tostring(n*tonumber(string.sub(tostring(m),#tostring(m)-(i-1),#tostring(m)-(i-1))))
if tonumber(x) ~= 0 then
print(rjust(x,barlength-#string.rep("0",i-1))..string.rep("0",i-1))
end
end
print(string.rep("-",barlength))
print(rjust(tostring(n*m),barlength))
end

draw(5,4)
``````