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.


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


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"

"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.

  • \$\begingroup\$ Not really, but i couldn't really think about another input format. But I'm willing to change that if it benefits the challenge. \$\endgroup\$
    – racer290
    May 19, 2018 at 12:21
  • \$\begingroup\$ Can there be non square maps? \$\endgroup\$
    – FrownyFrog
    May 19, 2018 at 12:22
  • 4
    \$\begingroup\$ @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.) \$\endgroup\$
    – dzaima
    May 19, 2018 at 12:24
  • 1
    \$\begingroup\$ Can the output be a 2d array of characters? \$\endgroup\$
    – ovs
    May 19, 2018 at 16:14
  • 2
    \$\begingroup\$ Can I submit a function taking the x- and y-coordinates as two separate arguments? \$\endgroup\$ May 19, 2018 at 17:01

14 Answers 14


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
  • 1
    \$\begingroup\$ I guess that output formatting is better than the one I proposed ;) \$\endgroup\$
    – racer290
    May 19, 2018 at 13:02
  • \$\begingroup\$ 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) \$\endgroup\$ Oct 19, 2018 at 11:37
  • \$\begingroup\$ I ran it on TIO without ::empty and it seemed to work(dont know J either) \$\endgroup\$
    – Quintec
    Oct 19, 2018 at 11:56
  • \$\begingroup\$ Actually ::empty seems to handle the “” input case \$\endgroup\$
    – Quintec
    Oct 19, 2018 at 11:57
  • \$\begingroup\$ @MagicOctopusUrn I don’t know a shorter way to output a truly empty box, they are 1 row high by default. \$\endgroup\$
    – FrownyFrog
    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]+[`

Try it online!


Haskell, 127 123 bytes

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)`elem`zip x y]|i<-m x]++"|"|j<-m y]++[l];m x=[1..maximum$0:x]

Try it online!


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
  -- 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


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, 151 140 138 bytes

-2 bytes thanks to Jo King.

Input is 1-indexed.

M=b+['|'+' '*w+'|']*h+b
for x,y in m:M[y]=M[y][:x]+'x'+M[y][x+1:]

Try it online!

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

Charcoal, 37 bytes


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.


Jump to its position.


Mark with a cross.

  • \$\begingroup\$ Seems to fail for empty input: tio.run/… \$\endgroup\$
    – wastl
    May 19, 2018 at 16:45
  • \$\begingroup\$ @wastl Thanks, I've come up with a workaround. \$\endgroup\$
    – Neil
    May 19, 2018 at 17:04
  • \$\begingroup\$ Better workaround: ≔E²⁺²∨⌈Eθ§λι⁰ηB⊟⮌η⊟ηFθ«J⊟⮌ι⊟ιx. \$\endgroup\$
    – Neil
    May 26 at 6:43

Stax, 32 31 24 bytes

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

Run and debug it

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


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
  • 1
    \$\begingroup\$ 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 \$\endgroup\$
    – recursive
    May 21, 2018 at 15:52
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – recursive
    May 21, 2018 at 15:58
  • \$\begingroup\$ @recursive I had been looking for something like surround, but I searched for the wrong keywords \$\endgroup\$
    – wastl
    May 21, 2018 at 16:00
  • \$\begingroup\$ What would you naturally call that operation? I may add it to the docs so the next person can find it. \$\endgroup\$
    – recursive
    May 21, 2018 at 16:02
  • \$\begingroup\$ @recursive I don't remember what it was, and I would naturally call it surround now \$\endgroup\$
    – wastl
    May 21, 2018 at 16:04

R, 133 125 122 bytes

"),rbind("|",`[<-`(matrix(" ",u,max(m[,2])),m,"x"),"|","

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.

coords taken of the format [y,x]

JavaScript (Node.js), 191 184 bytes

`,i++)for(j=0;j<=m;j++)s+=(c[i]||0)[j]||(j%m?i%M?" ":"-":i%M?"|":"+") 
return s}

Try it online!

  • \$\begingroup\$ I think you accidentally swapped the x- and y-coordinates somewhere.. \$\endgroup\$
    – racer290
    May 19, 2018 at 12:55
  • \$\begingroup\$ @racer290 could you be more specific? \$\endgroup\$ May 19, 2018 at 13:01
  • \$\begingroup\$ 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])) \$\endgroup\$
    – racer290
    May 19, 2018 at 13:04
  • \$\begingroup\$ but x is the right paramter as can be seen by the test cases \$\endgroup\$ May 19, 2018 at 13:10
  • 2
    \$\begingroup\$ 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. \$\endgroup\$
    – racer290
    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`



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.


Try it online!

  • \$\begingroup\$ fix bug in bottom row 235 bytes \$\endgroup\$
    – ceilingcat
    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.

  • 1
    \$\begingroup\$ 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 \$\endgroup\$ Oct 19, 2018 at 19:51
  • 1
    \$\begingroup\$ As mentioned by @Emigna in the chat, εZ} can be €à. \$\endgroup\$ Oct 19, 2018 at 22:47
  • \$\begingroup\$ Hate editing this on mobile will wait until near pc. \$\endgroup\$ Oct 21, 2018 at 0:57
  • 1
    \$\begingroup\$ @KevinCruijssen Ýv not Lv, but still a good edit :). \$\endgroup\$ Oct 22, 2018 at 16:36
  • \$\begingroup\$ Ah, you're right. Ýv instead of Lv. My bad. \$\endgroup\$ Oct 22, 2018 at 16:43

Java 10, 238 223 220 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.


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
  • \$\begingroup\$ rwhxy; lcwxlgetw? xw; hylgeth? yh; forwhxxwr. foryyhrxwyh? xwyhcxy? xr. \$\endgroup\$ Oct 19, 2018 at 15:03
  • \$\begingroup\$ @MagicOctopusUrn What are you naming all the variables and get/for for? :S XD \$\endgroup\$ Oct 19, 2018 at 18:29

C (gcc), 229 220 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.


Try it online!

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.