13
\$\begingroup\$

We all know run-length decoding: A list of character-length pairs expands to a string of that many characters, so A1B4C2 expands to ABBBBCC. But what if we stretch this concept to 2 dimensions?

Instead of character-length pairs, in this challenge you will be given character-length-direction triples. For example, using N/S/E/W to indicate direction, the input A4E B5S C3W D3N E1W should yield the output

AAAAB   
    B
 E  B
 D  B
 D  B
 DCCC

You can take input in any reasonable format (such as a list of (char, length, N/E/S/W) like shown here, or perhaps (0/1/2/3, length, char)).

The input will not overlap itself, so A5E B3W or A5E B4S C4W D4N is invalid input.

The input will also not expand past the left or top edges of the string, only the bottom and right edges will be expanded.

The character will always be within the printable ASCII range.

Consistent trailing or leading whitespace that does not affect the presentation of the output is fine.

This is , so the shortest submission per language, measured in bytes, wins.

Here are a couple cases to test your entry against:

A4E B5S C3W D3N E1W
AAAAB   
    B
 E  B
 D  B
 D  B
 DCCC

A4E B5S C3W D3N -2E -1N  2W |1S
AAAAB   
 |  B
 ---B
 D  B
 D  B
 DCCC

.3S  2E ,3N  2E .5S
.   . 
. , .  
. , .  
  , .   
    .

>6E v3S <6W ^2N >5E v1S <5W
>>>>>>v 
>>>>>vv
^<<<<<v
^<<<<<<

And here's an example implementation in JavaScript.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Can the directions be taken as a certain set of constants replacing NESW, eg. 0/2/4/6? \$\endgroup\$
    – math scat
    Oct 29 at 7:21
  • 1
    \$\begingroup\$ @mathscat yes, that’s what I was going for. But don’t abuse it and say that e.g. you’re using “x++” for E and “y++” for S \$\endgroup\$
    – noodle man
    Oct 29 at 12:27
  • \$\begingroup\$ Is the next challenge to encode the output?? \$\endgroup\$ Nov 1 at 0:42
  • 1
    \$\begingroup\$ @MarkStewart I’m not sure how that would work, an arbitrary string could be encoded like this in a variety of ways \$\endgroup\$
    – noodle man
    Nov 1 at 2:07

10 Answers 10

8
\$\begingroup\$

Python, 120 bytes

def f(A):
 G=[];X=Y=0
 for c,n,(x,y)in A:
  for _ in" "*n:G+=[[]];G[Y]+=[_]*(X-~len(G[Y]));G[Y][X]=c;X+=x;Y+=y
 return G

Attempt This Online!

\$\endgroup\$
7
  • 2
    \$\begingroup\$ X=0;Y=0 -> X=Y=0 and if len(G)<=Y:G+=[[]] -> G+=(len(G)<=Y)*[[]] \$\endgroup\$
    – noodle man
    Oct 28 at 15:46
  • \$\begingroup\$ 134 bytes \$\endgroup\$
    – noodle man
    Oct 28 at 15:58
  • \$\begingroup\$ @noodleman oh neat, thanks! \$\endgroup\$
    – hyper-neutrino
    Oct 28 at 18:07
  • \$\begingroup\$ 122 bytes by opting to have a lot of extra whitespace \$\endgroup\$
    – noodle man
    Nov 1 at 15:57
  • \$\begingroup\$ @noodleman I considered that but I didn't know if that counted as consistent whitespace lol, thanks for clarifying that \$\endgroup\$
    – hyper-neutrino
    Nov 2 at 6:50
7
\$\begingroup\$

Charcoal, 14 bytes

WS✳§ι⁰קι¹I✂ι²

Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated triples using a leading UDLR instead of a trailing NSEW. Explanation:

WS

Loop over each triple.

✳§ι⁰

Output in the direction given by the first character.

קι¹I✂ι²

Output the required character repeated by the length.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Right language for the job \$\endgroup\$
    – noodle man
    Oct 28 at 15:13
  • 1
    \$\begingroup\$ If you use the version of Charcoal on ATO you can alternatively use 2640 instead of UDLR. \$\endgroup\$
    – Neil
    Oct 28 at 15:14
  • 2
    \$\begingroup\$ And it should go without saying that Charcoal has no problem with inputs that cause overlapping or negative coordinates. \$\endgroup\$
    – Neil
    Oct 28 at 19:19
5
\$\begingroup\$

Vyxal, 13 bytes

ṫ⅛ƛy›Y;¾J⟑÷ø∧

Try it Online!

Vyxal does have a built-in canvas (fork of 05AB1E's canvas element), but it partially overwrites the drawn characters, so the input has to be modified. Takes in input as a list of [char, length, direction (0/2/4/6)].

ṫ⅛ƛy›Y;¾J⟑÷ø∧
ṫ⅛              # Push tail to global array
  ƛ   ;         # For all other elements ...
   y›Y          # Uninterleave, increment, interleave (increment the middle)
       ¾J       # Push global array (wraps tail in list), join with rest
         ⟑      # Map through list
          ÷ø∧   # Draw modified input to canvas
\$\endgroup\$
4
\$\begingroup\$

Perl 5, 156 bytes

sub f{($o,$p,$c,$n,$d,@r)=@_;@_%3?$n?do{$$o[$p]=$c;f($o,$p+1+{N,-99,S,97,W,-2}->{$d},--$n?($c,$n,$d):(),@r)}:"@$o"=~s/.{98}/$&\n/gr:f([(' ')x1e4],$"='',@_)}

Try it online!

\$\endgroup\$
4
\$\begingroup\$

J, 42 bytes

1 :'#&u@[[`]`(u:@32$~1+>./@])}[:}:0+/\@,#'

Attempt This Online!

A J adverb, which modifies the list of characters to produce a verb that takes the counts as a left arg and the directions as the right arg, as complex numbers in list form.

  • [:}:0+/\@,# Duplicate each direction by the counts, add 0 0 as a starting point, scan sum, and remove last.
  • #&u@[ Also duplicate the characters by the counts.
  • u:@32$~1+>./@] Create a canvas of spaces of the appropriate size.
  • [`]`...)} Update the canvas at the points computed by the scan sum, using the duplicated characters.
\$\endgroup\$
2
\$\begingroup\$

BQN, 29 bytes

{/⟜𝕗{𝕨⌾(𝕩⊸⊑)""↑˜1+⌈´𝕩}·+`⊸-/}

Try it here.

Defines a 1-modifier which takes the lengths as left argument, the directions (as a list of ⟨dx,dy⟩ pairs) as right argument, and the characters as a list (string) in the role of the function 𝔽 being modified.

Explanation:

The basic idea is to replicate both the characters and the directions by the lengths, do a prefix sum on the directions to get the list of indices corresponding to each character, and then use structural under to index into a blank array and place the characters at their corresponding indices.

{/⟜𝕗{𝕨⌾(𝕩⊸⊑)""↑˜1+⌈´𝕩}·+`⊸-/} #
                           /  # The directions replicated by lengths
                       +`⊸-   # subtracted from its own prefix sum (shifts right so starts with 0‿0)
                     }·       # becomes right argument 𝕩 to inner function.
 /⟜𝕗                          # The characters replicated by lengths
    {                         # becomes left argument 𝕨 to inner function.
                  ⌈´𝕩         # Get the maximum x,y values from the indices,
                1+            # add 1 to get the shape of the output,
            ""↑˜              # and take from empty string to get the blank character array.
      ⌾(𝕩⊸⊑)                  # Pick out the indices in the array
     𝕨                        # and place the characters.
\$\endgroup\$
2
\$\begingroup\$

AWK, 131 bytes

{for(;$2--;y+=/S$/-/N$/){g[+x,+y]=$1;x>X&&X=x;y>Y&&Y=y;x+=/E$/-/W$/}}END{for(y=-1;y++<Y;print"")for(x=0;x<=X;)printf"%1s",g[x++,y]}

Try it online!

\$\endgroup\$
0
2
\$\begingroup\$

Scala 3, 207 166 149 bytes

Port of @hyper-neutrino♦'s Python answer in Scala.

Saved so many bytes thanks to the comment of @noodle man and @Kjetil S


Golfed version. Attempt This Online!

a=>{var(g,i,j)=(Seq[Seq[Char]](),0,0);for((c,n,(x,y))<-a;_<-0to n-1){g=g:+List[Char]();g=g.updated(j,g(j).padTo(1+i,' ').updated(i,c));i+=x;j+=y;};g}

Ungolfed version. Attempt This Online!

object Main {
  def f(A: List[(Char, Int, (Int, Int))]): List[List[Char]] = {
    var G = List[List[Char]]()
    var X = 0
    var Y = 0
    for ((c, n, (x, y)) <- A) {
      for (_ <- 0 until n) {
        if (G.length <= Y) G = G :+ List[Char]()
        while (G(Y).length <= X) G = G.updated(Y, G(Y) :+ ' ')
        G = G.updated(Y, G(Y).updated(X, c))
        X += x
        Y += y
      }
    }
    G
  }

  def main(args: Array[String]): Unit = {
    val directionMap = Map(
      "E" -> (1, 0),
      "W" -> (-1, 0),
      "S" -> (0, 1),
      "N" -> (0, -1)
    )
    val instructions = List("A4E", "B5S", "C3W", "D3N", "E1W")
    val grid = f(for (x <- instructions) yield (x(0), x.slice(1, x.length - 1).toInt, directionMap(x.last.toString)))
    for (row <- grid) println(row.mkString)
  }
}
\$\endgroup\$
3
  • \$\begingroup\$ I’ve never used Scala before but I found a padTo method which brings this down to 171 bytes with some extra white space removed: a=>{var g=List[List[Char]]() var i=0 var j=0 for((c,n,(x,y))<-a;_<-0until n){if(g.length<=j)g=g:+List[Char]() g=g.updated(j,g(j).padTo(1+i,' ').updated(i,c)) i+=x j+=y} g} (ATO link too long to fit in this comment) \$\endgroup\$
    – noodle man
    Oct 29 at 13:04
  • \$\begingroup\$ You can shave off 13 chars with var(g,i,j)=(List[List[Char]](),0,0) and replacing all List with Seq and .length with .size \$\endgroup\$
    – Kjetil S
    Oct 29 at 23:31
  • \$\begingroup\$ 150 \$\endgroup\$
    – noodle man
    Nov 1 at 16:02
1
\$\begingroup\$

JavaScript (Node.js), 119 116 bytes

A=>A.map(([c,n,[x,y]])=>{for(_=0;_<n;_++){G[Y]=[...(G[Y]??[]).join``.padEnd(X)];G[Y][X]=c;X+=x;Y+=y}},G=[],X=Y=0)&&G

Attempt This Online!

This is a golfed version of the example implementation I provided. It takes the input as a list of [char, length, [dx, dy]].

Explanation:

A.map(([c,n,[x,y]])=>{ ... },G=[],X=Y=0)&&G

This first assigns G (a 2d array of characters) to an empty list and X and Y both to 0. It returns G after first running the following on each character c, length n, dx x, and dy y:

for(_=0;_<n;_++){ ... }

Run n times:

G[Y]=[...(G[Y]??[]).join``.padEnd(X)];

Pad the Y'th list in G to length X with spaces.

G[Y][X]=c;

Set the X'th character of the Y'th list in G to c.

X+=x;Y+=y

Add x to X and y to Y.

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 7 6 bytes

ā¤Ê+ŠΛ

-1 byte thanks to @CommandMaster

Inputs as three separated lists of the same length: \$lengths,directions,characters\$, where the \$directions\$ are 0246 for NESW respectively.

Try it online.

If the input as a list of triplets is mandatory, it's 8 bytes instead:

ø`ā¤Ê+rΛ

Inputs as a list of triplets \$[direction,char,length]\$, where the \$directions\$ are again 0246 for NESW respectively.

Try it online.

Explanation:

ā        # Implicitly push the first input-list of lengths, and then
         # push a list in the range [1,list-length], without popping the list
 ¤       # Push its last item (the list-length) without popping the list
  Ê      # NOT-equals check on each value, so we'll have a list of [1,1,...,1,0]
   +     # Add the values at the same positions of the top two lists together
    Š    # Triple-swap to push the list of characters and directions from the third and
         # second inputs implicitly
     Λ   # Use the Canvas builtin with these three lists as arguments
         # (after which the result is output immediately)
ø        # Zip/transpose; swapping rows/columns of the implicit input-list of triplets
 `       # Pop and push all three lists separately to the stack
  ā¤Ê+   # Same as above to change the top list of lengths
      r  # Reverse the order of the three lists on the stack
       Λ # Use the Canvas builtin with these three lists as arguments
         # (after which the result is output immediately)

See this 05AB1E tip of mine to understand how the Canvas builtin works, and why we increase the lengths (except for the last one) by 1 first.

\$\endgroup\$
1

Your Answer

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

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