Codegolf! a LUA challenge

#1

Hi!

I’ve realised that I only come here when I’m asking for help, which is a little selfish. So, with no further ado, I’d like to invite you to take part in a game of codegolf! Whoever can achieve the outcome with the fewest lines of lua code wins.

The rules?

  • self.levmap is a table with 70 entries used to generate a 7 by 10 grid.
  • if an entry is greater than 0, it is occupied.
  • you need to get the width and height of the full tiles in the grid (self.width, self.height).
  • you need to print the width and height once the sorting is complete.

For example.

if self.levmap =
{0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,0,0,1,1,1,0,
0,0,0,1,1,1,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0,
0,0,0,0,0,0,0}

then
self.width= 3
self.height = 2

Here’s my entry (self taught amateur coder)

	local toppest = 1
	local bottomest = 11
	local leftest = 8
	local rightest = 1
	for k, v in pairs(self.levmap) do 
		local x = ((k-1)%7)+1 --1, 7
		local y = math.ceil(k/7) --1,10
		if v > 0 then
			if x < leftest then
				leftest = x
			end
			if x > rightest then
				rightest = x 
			end
			if y < bottomest then
				bottomest = y
			end
			if y > toppest then
				toppest = y
			end
			self.height = (toppest-bottomest)+1
			self.width =  (rightest-leftest)+1
		end
	end
	if self.levmaps[key+1] == nil then
		print("size acquired! (josh don't forget to calculate tilesize here)",self.width,self.height)
	end
end
3 Likes

#2

after 24 hours I am still in first place.
de-fault! de-fault! de-fault! de-fault!

0 Likes

#3

Here’s another solution:

self.width = 0
local first_row = nil
local last_row = nil
for r=1,9 do
    local row = table.concat(self.levmap, "", 1+(r-1)*7, 1+(r-1)*7+6) -- concatenate each row into a string
    local trimmed_row = row:match("^0*(.-)0*$") -- trim initial and ending 0's
    self.width = math.max(self.width, #trimmed_row) -- width of the row is the length of the remaining string
    if #trimmed_row > 0 and not first_row then
        first_row = r
    end
    if #trimmed_row > 0 and (not last_row or last_row < r) then
        last_row = r
    end
end
self.height = (first_row and last_row) and last_row - first_row + 1 or 0

There must be a better way to figure out the height though…

@88.josh’s solution is more efficient since it doesn’t rely on string manipulation.

1 Like

#4

Hi 88.josh,

you can shorten by using math.max and math.min

If you like you can shorten locals initialization in one line.

You can do the same thing inside the inner loop, but I think is awful :face_vomiting:
(Or is it a Perl code competition?? :rofl:)

Is better to move the result evaluation out of the loops,
and compute x and y only if needed

	local toppest,rightest,bottomest,leftest=1,1,11,8 
	for k, v in pairs(self.levmap) do 
		if v > 0 then
			local x = ((k-1)%7)+1 --1, 7
			local y = math.ceil(k/7) --1,10
			leftest=math.min(x,leftest)
			rightest=math.max(x,rightest)
			bottomest=math.min(y,bottomest)
			toppest=math.max(y,toppest)
		end
	end
	self.height = (toppest-bottomest)+1
	self.width =  (rightest-leftest)+1

If you change your level map into a bidimensional array

self.levmap =
{ {0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,1,1,1,0},
{0,0,0,1,1,1,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0} }

you can avoid computing x and y with remainder and math.ceil, but code length is the same

	local toppest,rightest,bottomest,leftest=1,1,11,8
	for y,row in ipairs(self.level) do
		for x,v in ipairs(row) do
			if v > 0 then
				leftest=math.min(x,leftest)
				rightest=math.max(x,rightest)
				bottomest=math.min(y,bottomest)
				toppest=math.max(y,toppest)
			end
		end
	end
	self.height = (toppest-bottomest)+1
	self.width =  (rightest-leftest)+1

Without my locals init “cheat”, @britzl’s solution is shorter!

I won’t win the prize :sweat_smile:

2 Likes

#5

Results are in!
@lrx first place
@88.josh second place
And @britzl is disqualified for using string manipulation. Cruel, but ultimately the student has become the master, just like in star wars.

2 Likes