Coding Challenge #13: Little white... "friendliness pellets"

Coding Challenge #13

Hello and welcome to another codin - Howdy! I’m FLOWEY. FLOWEY the FLOWER! Hmmm… You came here for a challenge, haven’t’tcha?

That was strange, anyhoo, I hope you like this challenge! It’s definitely not inspired from Undertale.

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

At the start of the game Undertale, you encounter Flowey the flower, who surrounds you with the warming and unharmful friendliness pellets!

ezgif.com-video-to-gif

Write a function surround(str), given a string str, that surrounds str with friendliness pellets - uh, I mean, with 0s. (the surrounding pellets don’t form a circle, more of an ellipse or a round rectangle) (the function can either return a long string, or just print all the lines)

The first line must always have at least one pellet.
The middle line must always be at least 13 characters.
The word to surround must always have a space both in front of it and behind it.
The height of the ellipse/round triangle must be always be 11 characters.

For the other lines in-between these should be the offsets from the left side

Visualization:

surround("Hello World!")
       0000  
     0      0  
   0          0
  0            0
 0              0
 0 Hello World! 0
 0              0
  0            0
   0          0
     0      0
       0000
surround("in this world, its KILL or BE killed")

      00000000000000000000000000000
    0                               0
  0                                   0
 0                                     0
0                                       0
0 In this world, it's KILL or BE killed 0
0                                       0
 0                                     0
  0                                   0
    0                               0
      00000000000000000000000000000
surround("hi there")
      0
    0   0
  0       0
 0         0
0           0
0 hi there  0
0           0
 0         0
  0       0
    0   0
      0

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

Answer!

Alright, this challenge is actually rather easy, but the code is kind of chunky, so follow me. length is the width of the ellipse, how wide it would be. This is a useful piece of info. We use it to know how many spaces we put each time.
For the first line, I’m supposed to place 6 spaces then some amount of pellets (you don’t really have to put another 6 spaces after, but you can). To know the amount of pellets to put, we subtract 12 (6*2) from the width (length variable), and technically that’s how many pellets we need. This is pretty much what we do for all the other lines.
For the next 3 lines, I subtract n (how many spaces I’m supposed to put) + 2 (because each line is gonna have two pellets) from the width, to get how many spaces I need to put in the middle. I wrapped these 3 lines into a neat for loop instead of writing them individually.
For the 3 middle lines, the first and third one are rather simple, just subtract 2 (each one has 2 pellets) from the width. Now the center line is the interesting one, since it has the word put in it. The interesting part is padding the text so it’s in the center. What I need to know is how many spaces to put in front of it, and behind it. If the word’s length is even, then the front and back will have equal amount of spaces, if odd, then the front will have 1 spaces less than the back. So, what I do is subtract the word’s length (#str) + 2 (because the line has two pellets) from the width, that gets me how many spaces I’m supposed to put. Now to decide how many of those spaces to put in the front and back, I subtract by 2 of course. But for odd lengths, this won’t work, we would get a decimal. So what I do is, math.floor the amount of spaces for the front, and math.ceil the amount of spaces for the back. That way the front gets less, and the back gets more. My code is a disaster! But I hope you get it.

local function surround(str) 
    local length = #str+4 < 13 and 13 or #str+4 --since the width has to be at least 13, I check if the word's size will form something less than 13, and I make the wdith 13
    local space = " "
    local pellet = "0"
    print(space:rep(6)..pellet:rep(length-12)..space:rep(6))
    local n = 4
    for i = 1, 3 do
        print(space:rep(n)..pellet..space:rep(length-(n*2+2))..pellet)
        n = math.ceil(n/2)
    end
    print(pellet..space:rep(length-2)..pellet)
    print(pellet..space:rep(math.floor((length-2-#str)/2))..str..space:rep( math.ceil((length-2-#str)/2))..pellet)
    print(pellet..space:rep(length-2)..pellet)
    for i = 1, 3 do
        print(space:rep(n)..pellet..space:rep(length-(n*2+2))..pellet)
        n = n*2
    end
    print(space:rep(6)..pellet:rep(length-12)..space:rep(6))
end
7 Likes

Turned out a bit more verbose than I expected, could probably have unrolled the loop but I find it easier to understand this way:

Code
function surround(s)
	local lens = {6,4,2,1,0,0,0,1,2,4,6}
	local str = ""
	local max_length = math.max(#s + 4, 13)
	for i=1, 11 do
		-- preceding spaces
		str = str .. string.rep(" ", lens[i])
		-- left zeroes
		if i==1 or i==11 then
			str = str .. string.rep("0", max_length - 2*lens[i])
		else
			str = str .. "0"
		end
		-- contents
		if i == 6 then
			str = str .. " " .. s .. string.rep(" ", max_length - #s - 3) -- 3: 0 + 2 spaces
		else
			str = str .. string.rep(" ", max_length - 2*lens[i] - 2)
		end
		-- right zeroes
		if i ~= 1 and i ~= 11 then
			str = str .. "0"
		end
		-- newline
		str = str .. "\n"
	end
	return str
end

print(surround("Hello world!"))
print(surround("In this world, it's KILL or BE killed"))
print(surround("hi there"))

No clue if this works with other inputs (but it should! …hopefully)

2 Likes

Here’s my string.format based code:

code
local formatString = [[
      0%s      
    0  %s 0    
  0    %s   0  
 0     %s    0 
0      %s     0
]]

local function surround(phrase)
	local len = math.max(#phrase, 9)
	local firstHalf = formatString:format(("0"):rep(len - 9), unpack(table.create(4, (" "):rep(len - 9))))
	
	return firstHalf .. "0 " .. phrase .. (" "):rep(1 + len - #phrase) .. "0" .. firstHalf:reverse()
end

Your post didn’t describe how to deal with strings under 9 characters, so I did what your “hi there” example did and just appended any extra spaces. I can rework it pretty easily if you have a preferred method, though.

7 Likes

Happy dev forum anniversary starmaq!! I’m gonna do this challenge just for you :wink:

2 Likes

Here is my attempt. Took me about 15 minutes, I don’t know if that is good or bad.

function srd(str)
	
	
	local s = ' '
	local o = '0'
	local strLen
	local realStr = ''
	if #str >= 13 then
		strLen = #str
		realStr = str
	else
		strLen = #str + (13 - #str)
		realStr = str .. s:rep(13 - #str)
	end
	local initialOs = strLen - 4 - 4
	
	-- Actual print formats
	
	print(s:rep(6) 	.. o:rep(initialOs) .. s:rep(6))
	
	print(s:rep(4) 	.. o .. s:rep(initialOs + 2) .. o .. s:rep(4))
	
	print(s:rep(2) .. o .. s:rep(initialOs + 6) .. o .. s:rep(2))
	
	print(s .. o .. s:rep(initialOs + 8) .. o .. s)
	
	print(o .. s:rep(initialOs + 10) .. o)
	
	print(o .. s .. realStr .. s .. o)
	
	print(o .. s:rep(initialOs + 10) .. o)
	
	print(s .. o .. s:rep(initialOs + 8) .. o .. s)
	
	print(s:rep(2) .. o .. s:rep(initialOs + 6) .. o .. s:rep(2))
	
	print(s:rep(4) 	.. o .. s:rep(initialOs + 2) .. o .. s:rep(4))
	
	print(s:rep(6) 	.. o:rep(initialOs) .. s:rep(6))
	
	print('\n Ok that\'s it for this string. \n')
	
	return
end

srd('Too short')
srd('Let there be regex! And there was regex.')
srd('Not 2 long but not 2 short')

I tested it in studio, but the studio prints the spaces shorter, so it doesn’t look amazing. However, I tested with underscores instead of spaces and it looked perfect.

1 Like

Happy dev forum anniversary starmaq!!

Thanks a lot!

As for your code, nice job. Only two problems I found are, first centering short words, they tend to be in the front.

image

and second, is that the first and last lines should have 1 pellet minimum, but yours has 4!

Nice work though

1 Like