Zooming in on a map

13

2

Your task is to, given a map as input, zoom it out or in, depending on the scale. Note that the scale given is the scale by which to zoom out, so a scale between 0 and 1 will actually zoom in.

For example, given the following (badly made) map:

..____....
../OOO\...
..\OO/\...
..........

And a scale factor of 2, you should first separate it into 2x2 sections:

.. | __ | __ | .. | ..
.. | /O | OO | \. | ..
----------------------
.. | \O | O/ | \. | ..
.. | .. | .. | .. | ..

And in each section find the most common character:

.__..
.....

Note that there was an ambiguous section:

__
OO

I chose to use _ for this section, but using O would have been perfectly acceptable too.

If, for example, you were given the scale factor of 4, you would split it into 4x4 sections, like so:

..__ | __.. | ..
../O | OO\. | ..
..\O | O/\. | ..
.... | .... | ..

As you can tell, the map doesn't perfectly fit into 4x4 sections, but that's fine, as we can just lower the size of the section at the side.

Also, whenever we need to cut off our maps, we cut off at the bottom or on the right side.

The resulting map would look like so:

...

What an interesting map!

For scale factors below 1, such as 0.5, the process is simpler as we zoom in instead. Take this map:

./O\.
.\O/.

Zooming with a scale of 0.5:

..//OO\\..
..//OO\\..
..\\OO//..
..\\OO//..

Note that whenever your zoom factor is less than 1, the following will always be true: 1/(zoom factor) % 2 == 0. When it is above 1, the only guarantee you have is that it will be a whole number. When it is 1, the map should stay the same.

Examples:

4
/OO\
|OO|
|OO|
\OO/

O


0.25
ABCD

AAAABBBBCCCCDDDD
AAAABBBBCCCCDDDD
AAAABBBBCCCCDDDD
AAAABBBBCCCCDDDD

1
My zoom
should
not change

My zoom
should
not change

You may also take the map as a newline-separated array.

Okx

Posted 2017-05-09T15:04:20.927

Reputation: 15 025

2I think you should've waited some more in the Sandbox. – Erik the Outgolfer – 2017-05-09T15:11:02.673

@JonathonAllan No it wouldn't, on that section there are more . than O. We cut off on the right and bottom side. – Okx – 2017-05-09T15:11:10.620

Ah, by "we cut off at the bottom or on the right side" you mean that the top-left of the map is always the top-left of a section? – Jonathan Allan – 2017-05-09T15:17:50.303

@JonathanAllan Yes. – Okx – 2017-05-09T15:23:08.603

OK, the word "or" is misleading :) – Jonathan Allan – 2017-05-09T15:30:10.620

Is it okay to take exact fractions instead of floating point decimal as scale? – JungHwan Min – 2017-05-09T15:45:55.303

@JungHwanMin You can take 1/2 instead of 0.5. – Okx – 2017-05-09T15:46:33.317

Related. I don't think this is a dup because this zooms in as well as out. – Digital Trauma – 2017-05-09T18:12:59.487

Reminds me of some sprite work I did on some proc-gen spaceships. Because I knew where the "lines" were (vs. the inside vs. the outside of the ship) I was able to preserve detail when zooming in (i.e not get blocky and pixelated). Because of the rule interactions it meant that certain arrangements (namely a 2x2 square of line pixels) would seemingly create detail when zooming in. I'll see if I can dig up some screenshots. – Draco18s no longer trusts SE – 2017-05-10T17:58:31.793

This was very confusing to read because of the terminology. I believe you have swapped the usages of "zoom in" and "zoom out". Making the map bigger should be zooming in. – scatter – 2017-06-29T16:39:17.160

@Christian Please try and edit it to make it more clear. – Okx – 2017-06-29T16:42:51.327

Answers

7

Mathematica, 105 bytes

If[#<1,ArrayFlatten[#2/.n_String:>Table[n,1/#,1/#]],Map[First@*Commonest,#2~Partition~UpTo@{#,#},{2,3}]]&

The input is (scale, array of characters). The scale must be an integer or an exact fraction.

Explanation

If[#<1, ..., ... ]

If the first input is less than 1...

#2/.n_String:>Table[n,1/#,1/#]

Replace all Strings in the second input into a square array, with length 1/(first input)

ArrayFlatten[ ... ]

Flatten the result into a 2D array.

If[#<1, ..., ... ]

If the first input is not less than 1...

#2~Partition~UpTo@{#,#}

Partition the (second input) into partitions whose width/length are at most (first input).

Map[ ..., ... ,{2,3}]

Map onto level 2 and level 3...

First@*Commonest

The composition of the Commonest function (finds the commonest element in a list) and First (take the first element; in case there are multiple commonest elements).

JungHwan Min

Posted 2017-05-09T15:04:20.927

Reputation: 13 290

2

Python, 191 182 180 bytes

lambda m,s,j=''.join,i=int:[j((lambda p:max(p,key=p.count))(j(g[i(x*s):-i(~x*s//1)]for g in m[i(y*s):-i(~y*s//1)]))for x in range(-i(-len(m[0])//s)))for y in range(-i(-len(m)//s))]

Call _(map, scale_factor), where map is an array of lines, and it returns an array of lines.

Though this answer has already been beaten, I want to explain it, as it doesn't special case where the scale factor is less than one.

It makes a h by w matrix, where h = ceiling(map height / scale factor), and w = ceiling(map width / scale factor).

For every index (x, y) in the matrix, do:

  • Take a submatrix from the coordinates int(x * scale factor), int(y * scale factor) to ceil((x + 1) * scale factor), ceil((y + 1) * scale factor).
  • Put the most common character in that submatrix at (x, y).

Try it online!

Try test cases

Artyer

Posted 2017-05-09T15:04:20.927

Reputation: 1 697