# Treasure Map Drawing Bot

You're organizing a treasure hunt for your friends. To conduct things more easily, you want to draw a map of all locations where you hid the precious objects.

## Input

Any form of input denoting a list of points consisting of (nonnegative) x- and y-coordinate, 0 0 being the upper left corner is permitted (Note: You may also use 1-based indexing in your answer, please comment on that if you do). Example:

1 2
3 0
0 1


## Challenge

Your function or program should be able to construct a map denoting every given location with an x where the mark is found in row y + 1 and column x + 1 in the output. Unmarked locations are represented with a  . The map also consists of a frame where the corners are +s, the vertical lines are |s and the horizontal lines are -s. Your solution should output the smallest possible frame. Map for the input example given above:

+----+
|   x|
|x   |
| x  |
+----+


## Possible Test Cases

"0 0"
=>
+-+
|x|
+-+


"0 10
5 5
10 0"
=>
+-----------+
|          x|
|           |
|           |
|           |
|           |
|     x     |
|           |
|           |
|           |
|           |
|x          |
+-----------+


""
=>
++
++


"0 0
0 2
2 0"
=>
+---+
|x x|
|   |
|x  |
+---+


Of course, this is , meaning that the solution with the lowest byte count wins! Explanations of your solution are encouraged.

• Not really, but i couldn't really think about another input format. But I'm willing to change that if it benefits the challenge. May 19, 2018 at 12:21
• Can there be non square maps? May 19, 2018 at 12:22
• @racer290 I'd suggest just saying something like the input is a list of locations (e.g. nested list, list of tuples, space & newline separated, separate inputs, ect.) May 19, 2018 at 12:24
• Can the output be a 2d array of characters?
– ovs
May 19, 2018 at 16:14
• Can I submit a function taking the x- and y-coordinates as two separate arguments? May 19, 2018 at 17:01

# J, 37 34 bytes

0<@|:' x'{~((i.@]e.#.~)1+>./) ::#:


Try it online!

                       1+>./          maximum for each coordinate + 1
i.@]                     make an array with these dimensions filled with 0..x*y
/* if the input is empty,
1+>./ is negative infinity
and i.@] throws an error  */
#.~                mixed base conversion of input
e.                   replace the elements of i.@]
with 1 if it's present in the
converted input, 0 otherwise
(                ) ::      if there's an error do the other thing instead
#:    "to binary", for empty input this returns a 0x0 matrix
0<@|:' x'{~                           index into character string, transpose and put in a box

• I guess that output formatting is better than the one I proposed ;) May 19, 2018 at 13:02
• Why is the ::empty so verbose? What's it do? Why can't it be simplified to 1 byte or so? (I have no knowledge of J) Oct 19, 2018 at 11:37
• I ran it on TIO without ::empty and it seemed to work(dont know J either) Oct 19, 2018 at 11:56
• Actually ::empty seems to handle the “” input case Oct 19, 2018 at 11:57
• @MagicOctopusUrn I don’t know a shorter way to output a truly empty box, they are 1 row high by default. Oct 19, 2018 at 12:19

# JavaScript (ES6), 150 bytes

Takes input as a list of 1-indexed coordinates in [x,y] format. Returns a string.

a=>(g=w=>y<h?' |-+x'[4*a.some(a=>a+''==[x,y])|2*(-~y%h<2)|++x%w<2]+[
[x=x<w?x:+!++y]]+g(w):'')((M=i=>Math.max(2,...a.map(a=>a[i]+2)))(x=y=0),h=M(1))


Try it online!

This defines the operator (!) which takes a list of x-coordinates and a list of the corresponding y-coordinates:

x!y|l<-'+':('-'<$m x)++"+"=unlines$l:['|':[last$' ':['x'|(i,j)elemzip x y]|i<-m x]++"|"|j<-m y]++[l];m x=[1..maximum$0:x]


Try it online!

### Ungolfed/Explanation

The helper function m expects a list and returns indices (1-based) up to the maximum, if the list is empty it returns []:

m x | null x    = []
| otherwise = [1 .. maximum x]


The actual operator (!) is just a list-comprehension, traversing all the coordinates and choosing a or x character, which gets joined with newlines:

x ! y
-- construct the top and bottom line
| l <- "+" ++ replicate (maximum (0:x)) '-' ++ "+"
-- join the list-comprehension with new-lines
= unlines \$
-- prepend the top line
[l]
-- the actual map:
-- begin the line with | and add the correct chars for each coordinate
++ [ "|" ++ [ if (i,j) elem zip x y then 'x' else ' '
-- "loop" over all x-coordinates
| i <- m x
]
-- end the line with a |
++ "|"
-- "loop" over all y-coordinates
| j <- m y
]
-- append the bottom line
++ [l]


# Canvas, 22 bytes

ø╶｛X；┤╋｝ｌ|＊ｅＬ┤-×+ｅ：└∔∔


Try it here!

Takes 1-indexed inputs.

Finally decided to fix a bug that's been annoying me for ages and golfed this down to 21 bytes.

Explanation (half-ASCII-fied for monospace):

ø╶{X;┤╋}l|*eL┤-×+e:└++  full program, implicitly outputting ToS at the end
ø                       push an empty Canvas - the map
╶{    }                for each array in the input array
X                      push "X"
;┤                    and push the two coordinates separately on the stack
╋                   and overlap the "X" there in the map
l               get the vertical length of the map
|*             repeat "|" vertically that many times
e            encase the map in two of those vertical bars
L           get the horizontal length of the map
┤          subtract 2 (leave place for the "+"es)
-×        repeat "-" that many times
+e      encase that line in "+"es
:└    push a copy of that below the map
++  and join the 3 items vertically


# Python 2, 151140 138 bytes

-2 bytes thanks to Jo King.

Input is 1-indexed.

m=input()
w,h=map(max,zip((0,0),*m))
b=['+'+'-'*w+'+']
M=b+['|'+' '*w+'|']*h+b
for x,y in m:M[y]=M[y][:x]+'x'+M[y][x+1:]
print'\n'.join(M)


Try it online!

• I suspect that you're using 1-based indexing, please leave a note on that in your answer as stated in the challenge. May 19, 2018 at 12:54

# Charcoal, 37 bytes

≔Ｅ²⁺²⌈Ｅθ§λιηＢ⊟⮌η⊟ηＦθ«Ｊ⊟⮌ι⊟ιx


Try it online! Link is to verbose version of code. 1-indexed. Explanation:

¿¬ＬθＵＲ²+«


Special-case empty input by drawing a 2x2 rectangle of +s.

≔Ｅ²⁺²⌈Ｅθ§λιη


Transpose the input, take the maximum of each column (now row) and add 2 to get the box size in Charcoal co-ordinates.

Ｂ⊟⮌η⊟η


Draw the box.

Ｆθ«


Loop over each co-ordinate.

Ｊ⊟⮌ι⊟ι


x


Mark with a cross.

• Seems to fail for empty input: tio.run/… May 19, 2018 at 16:45
• @wastl Thanks, I've come up with a workaround.
– Neil
May 19, 2018 at 17:04

# Stax, 3231 24 bytes

╩╠ee%╙æM■↓^⌐╧ΩΓ¡c¥èf¢○ [


Run and debug it

Takes 0-based indices as array of [y, x] pairs.

Explanation:

zs'X&|<cM%'-*'+|S]s{'||Smn++m Unpacked program, implicit input
zs                            Tuck empty array under input
'X                          Push "X"
&                         Assign element at all indices (create map)
As the indexing arrays are an array of arrays, treat them as a path to navigate a multidimensional array.
Extend array if needed.
|<                       Left-align all to the length of the longest.
cM%                    Copy, transpose, length (width)
'-*                 Repeat "-"
'+|S             Surround with "+"
]s           Make a singleton and tuck it below the map
{    m     Map:
'||S        Surround with "|"
n++  Surround with the above/below border (built above)
m Map:
Implicit output

• Nicely done. You can get a little more mileage out of the |S surround instruction, and a trailing shorthand map. (m) Surround takes a and b from the stack and produces b+a+b. And you can use m instead of the final |J to iterate over the rows and produce output. For example May 21, 2018 at 15:52
• One more thing: you can replace z]n+H% with cM%. This is the piece that gets the map width, but has a special case for empty maps. If you transpose the map before measuring it, the special case goes away. May 21, 2018 at 15:58
• @recursive I had been looking for something like surround, but I searched for the wrong keywords May 21, 2018 at 16:00
• What would you naturally call that operation? I may add it to the docs so the next person can find it. May 21, 2018 at 16:02
• @recursive I don't remember what it was, and I would naturally call it surround now May 21, 2018 at 16:04

# R, 133 125 122 bytes

function(m)cat(z<-c("+",rep("-",u<-max(m[,1])),"+","
"),rbind("|",[<-(matrix(" ",u,max(m[,2])),m,"x"),"|","
"),z,sep="")


Try it online!

1-indexed. Takes a matrix as argument. Saved 8 bytes thanks to digEmAll, 3 thanks to Giuseppe! Explanation (earlier version of code):

function(m){                           #x and y are the 1st and 2nd col of m
s=matrix(32,u<-max(m[,1]),max(m[,2]))  #s (treasure map) has dim max(x), max(y)
s[m]=120                               #place the X's on the map
cat(                                   #print:
z<-c("+",rep("-",u),"+","\n"),     #the top line
intToUtf8(rbind(124,s,124,13)),    #the map
z,                                 #the bottom line.
sep="")
}

• If you use normal chars instead of utf8 codes you save 8 characters : tio.run/##ZU7NDoIwDL7zFEu9tKEzDONF4UkMhzmGchgYNhKC@uwIaozRpG36/… May 21, 2018 at 16:59
• 122 bytes by using [<- directly to remove the braces. May 22, 2018 at 13:32
• @Giuseppe indeed! I knew there had to be a way. May 22, 2018 at 14:09

coords taken of the format [y,x]

# JavaScript (Node.js), 191 184 bytes

c=f=a=>{a.map(([y,x])=>(c[M<++y?M=y:y]=c[y]||[])[m<++x?m=x:x]="x",M=m=0)
m++
M++
s=""
for(i=0;i<=M;s+=
,i++)for(j=0;j<=m;j++)s+=(c[i]||0)[j]||(j%m?i%M?" ":"-":i%M?"|":"+")
return s}


Try it online!

• I think you accidentally swapped the x- and y-coordinates somewhere.. May 19, 2018 at 12:55
• @racer290 could you be more specific? May 19, 2018 at 13:01
• Trying your solution, I found that changing the x coordinate in the test cases led to a change in the vertical direction of the coordinate. I guess the bug is in the first row (a.map(([y,x])) May 19, 2018 at 13:04
• but x is the right paramter as can be seen by the test cases May 19, 2018 at 13:10
• So in your solution you take the y coordinate first? I think it'd be better to leave a note on that in your answer then. May 19, 2018 at 13:15

# JavaScript, 180 bytes

F =

s=>s.map(([x,y])=>(t[y]=t[Y<y?Y=y:y]||[])[X<x?X=x:x]='x',t=[X=Y=0])&&[...t,0].map((_,y)=>[...Array(X+2)].map((_,x)=>[(t[y]||0)[x]||' ',...'-|+'][!(y%~Y)+2*!(x%~X)]).join).join

console.log(F([[1,11],[6,6],[11,1]]))

# C (gcc), 246 234 bytes

Thanks to ceilingcat for the suggestion.

Zero-indexed. The function takes a list of co-ordinates and buffer, finds the maximum x and y values, fills the buffer with spaces, generates the frame, and then plots the 'x's.

f(int*a,char*c){int*b=a,x,y=x=-1,i=0;for(;~*b;*++b>y?y=*b:0,++b)*b>x?x=*b:0;for(x+=4,y+=3,memset(c,32,x*y);++i<x;c[i]=c[y*x-i]=45);for(i=0;i<y;c[x*++i-1]=10*(i<=y))c[x*i]=c[x*i+x-2]=i&&y/i?124:43;for(b=a;~*b;b+=2)c[*b+1-~b[1]*x]='x';}


Try it online!

• fix bug in bottom row 235 bytes Jan 1, 2019 at 22:28

# 05AB1E, 44 42 bytes

ζεZ}>UX'-×'+.ø©,F'|NVXF¹YN‚.å„ xè}'|J,}®,


Try it online!

 ζεZ}>                                     # Push the max of X and Y to the stack +1.
UX                                   # Store the max X.
'-×'+.ø©,                          # Print the top border.
F                     }   # From 0 to Y...
'|                       # Push left border.
NV                     # Store current Y in Y.
XF          }        # From 0 to X...
¹                  # Push input.
YN‚               # Group current X and Y.
.å             # Exists in original input ? 1 : 0
„ xè         # Exists ? 'X' : ' '
'|J,    # Right border, join, print.
®, # Print bottom border.


X and Y may be reversed, didn't know if that mattered at all.

I think I have this in less bytes, but we'll see... Nope.

ζεZ}>D'-×'+.øUð×'|.øs.D)X.ø©svy>s®sUXès'xsǝXǝ}

• It's not much, but you can save 1 byte by changing the first F to Lv, remove NV and change Y to y. 41 bytes Oct 19, 2018 at 19:51
• As mentioned by @Emigna in the chat, εZ} can be €à. Oct 19, 2018 at 22:47
• Hate editing this on mobile will wait until near pc. Oct 21, 2018 at 0:57
• @KevinCruijssen Ýv not Lv, but still a good edit :). Oct 22, 2018 at 16:36
• Ah, you're right. Ýv instead of Lv. My bad. Oct 22, 2018 at 16:43

# Java 10, 238223220 219 bytes

c->{var r="";int w=0,h=0,x,y;for(var l:c){w=(x=l.get(0))>w?x:w;h=(y=l.get(1))>h?y:h;}for(w++,h-=x=-1;x++<w;r+="\n")for(y=-1;y++<h;)r+=x%w+y%h<1?"+":x%w<1?"-":y%h<1?"|":(c+r).contains("["+x+", "+y+"]")?"x":" ";return r;}


-3 bytes thanks to @ceilingcat.

1-indexed coordinates.

Try it online.

Explanation:

c->{                      // Method with 2D Lists as parameter and String return-type
var r="";               //  Result-String, starting empty
int w=0,h=0,            //  Width and height, starting at 0
x,y;                //  Temp x,y coordinates
for(var l:c){           //  Loop over the Inner Lists containing the coordinates
w=(x=l.get(0))>w?x:w; //   Determine width based on max x-coordinate
h=(y=l.get(1))>h?y:h;}//   Determine height based on max y-coordinate
for(w++,h-=             //  Increase both the width and height by 1
x=-1;x++<w;         //  Loop x in the range [0, width]:
r+="\n")            //    After every iteration: append a new-line to the result
for(y=-1;y++<h;)      //   Inner loop y in the range [0, height]:
r+=                 //    Append the following character to the result-String:
x%w+y%h<1?       //    If it's one of the corners:
"+"             //     Append "+"
:x%w<1?          //    Else-if it's the top or bottom row:
"-"             //     Append "-"
:y%h<1?          //    Else-if it's the right or left column:
"|"             //     Append "|"
:(c+r).contains("["+x+", "+y+"]")?
//    Else-if the current x,y is part of the input-coordinates:
"x"             //     Append "x"
:                //    Else:
" ";            //     Append " "
return r;}              //  Return the result-String

• rwhxy; lcwxlgetw? xw; hylgeth? yh; forwhxxwr. foryyhrxwyh? xwyhcxy? xr. Oct 19, 2018 at 15:03
• @MagicOctopusUrn What are you naming all the variables and get/for for? :S XD Oct 19, 2018 at 18:29

# C (gcc), 229220 216 bytes

-9 bytes thanks to ceilingcat.

Zero-indexed. Takes coordinates as list of numbers, where even numbers are X and odd numbers are Y.

X,Y,i,j,k,x,z;f(l,n)int*l;{for(X=Y=0,i=n*=2;i--;X=fmax(l[i],X))Y=fmax(l[i--],Y);n&&X++-Y++;for(--i;i++<Y;puts(""))for(j=-1;j<=X;z=i<0|i==Y,putchar(j++<0|j>X?z?43:'|':x?z?45:32:'x'))for(x=k=n;k--;)x*=l[k--]-i|l[k]-j;}


Try it online!

• @ceilingcat Cheers! Oct 19, 2018 at 9:16
• Suggest for(n&&X++-Y++;i<=Y;i+=puts("")) instead of n&&X++-Y++;for(--i;i++<Y;puts("")) Jan 1, 2019 at 21:37