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)
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
sum = sum + add
print(string.rep(" ", n-#tostring(add))..add)
end
end
print(string.rep("-", n))
print(string.rep(" ", n-#(tostring(sum)))..sum)
end
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
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.
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
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
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.
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.
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 addends = {}
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 width = math.floor(math.log(addends[#addends], 10)) + 3
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,
string.rep(formatNumber, #addends - 1), formatOp,
separator,
string.format(formatNumber, product):sub(1, -2)
)
return string.format(formatString, table.unpack(addends))
end
I have no idea where to put :sub(1, -2) in terms of organization…
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
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)