18
\$\begingroup\$

aka. implement an easier version of 05ab1e's canvas element.

Description

The canvas element is used to draw ASCII lines on the screen.
The (easier version of the) canvas element takes a list of integers and returns a multi-line string (or a list of strings). The integers map to the following directions:

7   0   1
  ↖ ↑ ↗
6 ← X → 2
  ↙ ↓ ↘
5   4   3

0: upwards
1: top-right
2: right
3: bottom-right
4: downwards
5: bottom-left
6: left
7: top-left

If given eg. [6, 4, 2], it outputs this:

###
#
###

Explanation Image

  1. Start with one hash already drawn (X)
  2. Draw two hashes towards the left (direction 6)
  3. Draw two hashes downwards (direction 4)
  4. Draw two hashes towards the right (direction 2)

Rules

  • Default Loopholes apply
  • Multiple integers or a list of integers will be given as the input
  • Output must be a string, a list of strings, or a matrix of characters (like a binary matrix)
  • You will not receive directions with intersecting lines
  • You can replace # with any other constant character, but you'll always have to draw 2 hashes per direction and start with a hash
  • Excess whitespace is allowed
  • The shortest code, as this is , wins

Examples

In: [1, 5, 3, 7, 5, 1, 7, 3]
Out:
#   #
 # # 
  #  
 # # 
#   #

In: [2, 2, 2, 2, 4, 4, 7, 7]
Out:
#########
     #  #
      # #
       ##
        #

In: [1, 2, 3, 6, 6, 2, 4, 2, 2, 4, 2, 6, 4, 2, 1, 3, 2, 6, 7, 5, 6, 6, 4, 0, 6, 4, 0, 6, 0, 6, 2, 0, 2]
Out:
  ###            
 #   #           
# #####          
    #            
  #######        
  #     #        
###     ### #    
  #     #  # #   
  #########   ###
    # #          
    # #          

```
\$\endgroup\$
6
  • \$\begingroup\$ Sandbox \$\endgroup\$
    – math scat
    Commented Jun 5, 2022 at 19:25
  • 2
    \$\begingroup\$ How strict are the whitespace rules? Is trailing whitespace required, and is excess whitespace allowed? \$\endgroup\$ Commented Jun 5, 2022 at 21:50
  • 1
    \$\begingroup\$ Also you should consider adding an example that draws a cat. \$\endgroup\$
    – Jonah
    Commented Jun 5, 2022 at 23:00
  • 1
    \$\begingroup\$ @ConorO'Brien excess whitespace is allowed, I'll edit it \$\endgroup\$
    – math scat
    Commented Jun 6, 2022 at 5:09
  • \$\begingroup\$ What's the winning criterion? The questions seems to be silent about it. \$\endgroup\$ Commented Jun 23, 2022 at 18:17

8 Answers 8

14
\$\begingroup\$

Vyxal, 4 bytes

×3ø^

Try it Online!

05AB1E, 3 bytes

3$Λ

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ lol yeah I expected this one \$\endgroup\$
    – math scat
    Commented Jun 5, 2022 at 19:02
11
\$\begingroup\$

Charcoal, 9 bytes

FA✳ι##‖↘#

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

FA

Loop over the directions.

✳ι##

Print two #s in that direction.

‖↘

Reflect to switch from Charcoal to 05AB1E coordinates. This is because Charcoal's coordinate system has 0 as right and 2 as up etc.

#

Print the final #.

Boring built-in version:

GH✳✳⁻²A³#

Try it online! Link is to verbose version of code Unfortunately the version of Charcoal on TIO has a bug in its deverbosifier meaning that it parses Directions() as Direction(s). I could use a capital S... or you could just Attempt This Online! Link is to verbose version of code. Note that the PolygonHollow line drawing code takes the lengths of the lines rather than the number of additional #s to draw.

\$\endgroup\$
10
\$\begingroup\$

Ruby, 106 bytes

->d{m=2*x=y=d.size*2;c=[]
[-5,*d].map{|k|2.times{(c[y+=k==6?0:k%7<=>2]||=[0]*m)[x+=k<1?0:4<=>k]=1}};c-[p]}

Try it online! Returns a binary matrix (1 for #, 0 for ). A semicolon replaced for a newline for readability's sake (and the same byte count). Produces a lot of leading/trailing spaces in each row (most of the time).

I'm sure there's some more bytes to be shaved but I can't currently see what they are.

Direction to coordinate formula

I'm not sure if this is the shortest, but I imagine this approach is shorter than an approach by complex exponentiation. For a given direction \$k\$, we want to produce the delta directions \$dx\$ and \$dy\$ to "nudge" our central coordinate along. We can see that, through some formula manipulation, we can do just that:

\begin{array} {|c|c|} \hline k & dx & dy & k<1 & 4\Leftrightarrow k& & k=6 & k\bmod7 & k\bmod7\Leftrightarrow2 \\ \hline 0 & 0 & -1 & T & 1 & \mathbf{0} & F & 0 & -1 & \mathbf{-1} \\ \hline 1 & 1 & -1 & F & 1 & \mathbf{1} & F & 1 & -1 & \mathbf{-1} \\ \hline 2 & 1 & 0 & F & 1 & \mathbf{1} & F & 2 & 0 & \mathbf{0} \\ \hline 3 & 1 & 1 & F & 1 & \mathbf{1} & F & 3 & 1 & \mathbf{1} \\ \hline 4 & 0 & 1 & F & 0 & \mathbf{0} & F & 4 & 1 & \mathbf{1} \\ \hline 5 & -1 & 1 & F & -1 & \mathbf{-1} & F & 5 & 1 & \mathbf{1} \\ \hline 6 & -1 & 0 & F & -1 & \mathbf{-1} & T & 6 & 1 & \mathbf{0} \\ \hline 7 & -1 & -1 & F & -1 & \mathbf{-1} & F & 0 & -1 & \mathbf{-1} \\ \hline -5 & & & T & 1 & \mathbf{0} & F & 2 & 0 & \mathbf{0} \\ \hline \end{array}

Bolded cells above indicate taking the previous expression, but instead choosing zero if the previous condition holds. In code, we update our coordinates as thus:

x += k < 1  ? 0 : 4 <=> k
y += k == 6 ? 0 : k % 7 <=> 2

Important to note is that \$-5\$, as well as any other number \$c<1\$ for which \$c\equiv 2\mod 7\$, produces a 0 in both coordinates, and is useful as a placeholder to mean "no action", and hence a useful initialization instruction.

Commented code

-> d {
  # x and y are initially set to d.size * 2, guaranteeing us sufficient room
  # so that our calculations will not step outside of bounds.
  # m is our minimum width for padding purposes for such a bound, and extends
  # the distance from 0 to x or y in each direction, that is, 2x or 2y
  m = 2 * x = y = d.size * 2
  c = []
  # to account for the initial cell, we prepend -5 to the input (see above table)
  [-5, *d].map { |k|
    # since each line is two characters long, we update each cell individually
    2.times {
      # update y, as per above
      y += k == 6 ? 0 : k % 7 <=> 2
      # get the current row, defaulting to an appropriate row of 0s
      row = c[y] ||= [0] * m
      # update x, as per above
      x += k < 1 ? 0 : 4 <=> k
      # update (x,y) in the output array
      row[x] = 1
    }
  }
  # remove all nil rows from the output array
  c - [p]
}
\$\endgroup\$
2
  • \$\begingroup\$ Is something wrong with the submission, @downvoter? or were there too many numbers in this post :P \$\endgroup\$ Commented Jun 6, 2022 at 22:28
  • \$\begingroup\$ @downvoter ̷I̷'̷m̷ ̷p̷e̷r̷s̷o̷n̷a̷l̷l̷y̷ ̷o̷f̷f̷e̷n̷d̷e̷d̷ ̷b̷y̷ ̷t̷h̷i̷s̷ \$\endgroup\$
    – math scat
    Commented Jun 7, 2022 at 16:36
9
\$\begingroup\$

Jelly,  25  22 bytes

Saved three bytes using the allowance of excess whitespace (this also fixed a bug that meant an input with only left and/or right movements would have printed incorrectly since no space or newline characters were being introduced in such cases).

ı2½*Nx2ŻÆiNṠ+\+L$ŒṬo⁶Y

A full program that accepts the list of instructions and prints the result using 1 as the character.

Try it online!

How?

Jelly has no canvas drawing built-ins, so instead this builds a matrix of zeros and ones, with ones at visited locations and prints it with spaces in place of zeros joined with newline characters.

ı2½*Nx2ŻÆiNṠ+\+L$ŒṬo⁶Y - Main Link: list of integers from [0,7]:
ı2                     - 2i (twice the square root of -1)
  ½                    - square root
    N                  - negate the input (vectorises)
   *                   - exponentiate (vectorises)
     x2                - repeat each element twice
       Ż               - prefix with a zero
        Æi             - convert each to [real, imaginary] parts
          N            - negate (vectorises)
           Ṡ           - sign (vectorises)
             \         - cumulative reduce by:
            +          -   addition (vectorises)
                $      - last two links as a monad:
               L       -   length
              +        -   add (vectorises)
                 ŒṬ    - matrix with 1s at the indicated [row, column]s
                   o⁶  - logical OR with space character
                     Y - join with newline characters
                       - implicit, smashing print

Note: ı2 is a hack - ı should work but there are floating-point errors - for example, ı½*-2 gives 2.220446049250313e-16-1j rather than 0-1j.

\$\endgroup\$
3
  • \$\begingroup\$ woah that's big \$\endgroup\$
    – math scat
    Commented Jun 6, 2022 at 5:10
  • \$\begingroup\$ @mathcat yep, hence why this kind of thing is built-in in so many golfing languages! Slightly shorter now due to the excess whitespace allowance though. \$\endgroup\$ Commented Jun 6, 2022 at 13:47
  • 3
    \$\begingroup\$ Heh, and I was thinking "Wow, for a language without a builtin, that's super short" ;) \$\endgroup\$
    – DLosc
    Commented Jun 6, 2022 at 21:40
8
\$\begingroup\$

BQN, 79 77 71 67 58 53 51 bytes

Saved 5 bytes thanks to att

' '+(¬⊸-↑↑⟜1)∘⋈˜∘¬⟜-∘≠{𝕨(𝕨∨⌽)´-𝕩}4(⊢×○×-)2/8|-⟜2⊸⋈¨

Try it at BQN online

Explanation

New approach!

8|-⟜2⊸⋈¨

Turn each number in the initial list of directions into a list containing two numbers, the first number shifted two directions counterclockwise (i.e. minus 2, mod 8). These will become the y and x deltas, respectively.

2/

Repeat each direction twice.

4(⊢×○×-)

Turn the directions into deltas. We want to implement the following function:

  • 0 or 4 -> 0
  • 1, 2, or 3 -> 1
  • 5, 6, or 7 -> -1

We almost get the desired result if we subtract the input from 4 and take the sign. The only problem is that 0 becomes 1, which we can fix by multiplying by the sign of the input: sign(4-x) * sign(x), in C-like pseudocode. In BQN, ×○× is a dyadic function that takes the sign of each argument and multiplies them; (⊢×○×-) is a dyadic train that passes its right argument and the difference of its arguments to ×○×; and so if we give it 4 as its left argument and a direction number as its right argument, it will return the desired delta. Since all of the functions used here are pervasive, we can apply them to a list of lists of numbers and get a list of lists of results.

(¬⊸-↑↑⟜1)∘⋈˜∘¬⟜-∘≠

Call the length of the original list \$N\$. (The length of the list of deltas is \$2N\$ because we repeated each move twice.) Construct a \$4N+1\$ by \$4N+1\$ array that is filled with 0s but with a 1 in the exact center.

{𝕨(𝕨∨⌽)´-𝕩}

Negate each delta and right-fold the list of deltas using the following procedure: Start with the \$4N+1\$ array constructed above. At each step, rotate the partial result by the current delta, and then logical OR with another copy of the \$4N+1\$ array. The result is a \$4N+1\$ by \$4N+1\$ array of 0s and 1s.

' '+

Add a space character, converting the 0s to spaces and the 1s to !s.

\$\endgroup\$
8
  • \$\begingroup\$ I noticed you 1 byte shorter than mine originally and fought for the reduction I got... I'm not sure I can get under 67 though, but I'll make it my mission to try :P \$\endgroup\$ Commented Jun 8, 2022 at 8:21
  • \$\begingroup\$ you can remove the in ' '⊸+ \$\endgroup\$
    – Razetime
    Commented Jun 8, 2022 at 12:09
  • \$\begingroup\$ @DomHastings I see you got under 67. However, I just found a new approach and got down to 58... ;) \$\endgroup\$
    – DLosc
    Commented Jun 8, 2022 at 18:35
  • 1
    \$\begingroup\$ can shorten the initial array generation further with (¬⊸-↑↑⟜1)∘≍˜∘¬⟜-∘≠ \$\endgroup\$
    – att
    Commented Jun 8, 2022 at 19:54
  • 1
    \$\begingroup\$ another -2 bytes \$\endgroup\$
    – att
    Commented Jun 8, 2022 at 22:57
3
\$\begingroup\$

Perl 5 + -pl043F, 63 bytes

$_=". "[email protected]/./(<#{DA,A,,B,BD,{B,,A}DD}>)[$&]x2/ger;s/\w/.[$&/g

Try it online!

Explanation

The solution utilises ANSI escape sequences to move the cursor to the required position based on the input commands. First $_ is reset to @F (a list containing each character of the input, which, when interpreted as a scalar, returns the length of the list) repetitions of \f (form-feed followed by space) to move the cursor to a position to allow enough space for the output (hopefully...), concatenated with the original input s///ubstituting each digit (.) with its index into the glob list (<#{DA,A,,B,BD,{B,,A}DD}>). This results in a string like: #A#A#BDD#BDD#B#B#DDA#DDA#BDD#BDD#A#A#DDA#DDA#B#B# where the letters correspond to the ANSI escape sequence to move either left, up or down. These letters are then replaced with the correct ANSI escape sequences in the final s///ubstitution.

Bonus "cat" drawing.

\$\endgroup\$
3
  • \$\begingroup\$ Ooh nice, Perl! \$\endgroup\$
    – math scat
    Commented Jun 6, 2022 at 19:34
  • \$\begingroup\$ @mathcat Bonus cat: Try it online! Maybe it looks a little more like an owl... \$\endgroup\$ Commented Jun 6, 2022 at 19:51
  • \$\begingroup\$ wow, looks nice! \$\endgroup\$
    – math scat
    Commented Jun 7, 2022 at 7:13
1
\$\begingroup\$

C (gcc): 218 210 bytes

Edit: Thanks to ceilingcat for shortening the code to 210 bytes.

p=297,C[800]={[297]=3},d,j=800;f(D,n){d^D?:(C[p+=n]=C[p+=n]=3);}main(c,v)char**v;{for(;d=*v[--c]-48,c;f(0,-40))f(7,-41),f(6,-1),f(5,39),f(4,40),f(3,41),f(2,1),f(1,-39);for(;j--;j%40?:puts(""))putchar(C[j]+32);}

Try it online (with explanation)

Explanation:


// Thanks to ceilingcat for shortening the code to 210 bytes

// 'C[800]' is the 2D canvas ('C[20][40]') flattened out to 1D and contains the
// offset of the ASCII character code from 32 (e.g. '#' character code is 35
// but would be stored as 3). This is because initializing an array with any
// other value than 0 is not cheap (space-wise) and in this case it's better to
// just add 32 whenever needed.
// 'p' should point to the middle of the canvas (might be wrong :P).
p=297,C[800]={[297]=3},d,j=800;
// This moves the cursor and draws 2 '#'s in the specified direction 'D'.
f(D,n){d^D?:(C[p+=n]=C[p+=n]=3);}
main(c,v)char**v;{
        // Converts command line arguments to an 'int' and draws on the canvas.
        for(;d=*v[--c]-48,c;f(0,-40))f(7,-41),f(6,-1),f(5,39),f(4,40),f(3,41),f(2,1),f(1,-39);
        // Print the canvas.
        for(;j--;j%40?:puts(""))putchar(C[j]+32);
}
\$\endgroup\$
1
  • \$\begingroup\$ nice, C!~~~~~~~ \$\endgroup\$
    – math scat
    Commented Jun 6, 2022 at 16:05
1
\$\begingroup\$

Python 3, 125 bytes

from turtle import*
mode("logo")
def f(l,w=write):
 reset();ht();pu();w("#")
 for d in l:seth(d*45);fd(9);w("#");fd(9);w("#")   
\$\endgroup\$
4
  • \$\begingroup\$ Hmm yeah okay I'll let this count :P \$\endgroup\$
    – math scat
    Commented Jun 6, 2022 at 19:30
  • \$\begingroup\$ @mathcat Was quite surprised nobody had already done this! :D \$\endgroup\$
    – Noodle9
    Commented Jun 6, 2022 at 19:47
  • \$\begingroup\$ What's the point of a TIO link if it doesn't have the module installed? \$\endgroup\$
    – Neil
    Commented Jun 9, 2022 at 19:21
  • \$\begingroup\$ @Neil None what so ever, removed. \$\endgroup\$
    – Noodle9
    Commented Jun 9, 2022 at 23:45

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.