Draw my downslashes

60

2

As a programmer, you've probably heard of forward slashes and backward slashes. But have you heard of downslashes? That's when you take a bunch of slashes, connect their ends and draw them going down.

For today's challenge, you must write a program or function that takes a string consisting purely of slashes, and outputs all of those slashes drawn downwards in a line connecting them. This will be a lot more clear if you see an example. Given the string \\\//\/\\, you should output:

\
 \
  \
  /
 /
 \
 /
 \
  \

Here are some clarifications:

  • There must be one slash per line.

  • The first line will have 0 leading spaces.

  • For each pair of slashes:

    • If they are different from each other, they will be drawn in the same column. For example, \/ will give:

      \
      /
      
    • If they are the same character, the lower one is in the direction pointed to, that is moving to the right for a backslash, and moving to the left for a forward slash. So \\// will give

      \
       \
       /
      /
      
  • Each line may have extra trailing whitespace as long as this doesn't change the visual appearance of the output. Up to one trailing and leading newline is also acceptable. Extra leading spaces are not permitted!

In order to keep this simpler, you can assume that the string will never contain too many forward slashes. In other words, no prefix of the input will contain more forward slashes than backslashes, so an input like \\//// or // will never be given. This also means that every input will start with a backslash.

If your input is taken as a string literal, you may escape the backslashes if this is necessary. You will also never need to handle an input that is empty, or contains characters other than a slash.

You may output by any reasonable format.

As usual, this is a challenge, so try to make the shortest solution possible, even if you pick a language where this is rather difficult. Bonus points for explaining any interesting techniques you used to take bytes off!

Examples

#Input
\\\\\\\\\\\

#Output
\
 \
  \
   \
    \
     \
      \
       \
        \
         \
          \

#Input
\\\//\\/\//\\///

#Output
\
 \
  \
  /
 /
 \
  \
  /
  \
  /
 /
 \
  \
  /
 /
/


#Input
\/\/\/

#Output
\
/
\
/
\
/

James

Posted 2017-09-13T22:04:41.563

Reputation: 54 537

9The backslashes make for an annoying amount of escaping lol... – totallyhuman – 2017-09-13T22:28:56.093

Is the formfeed/backslash method of moving the cursor around given in my answer permissible for this question?

– Digital Trauma – 2017-09-14T01:15:58.700

Answers

21

GNU Sed, 20

s|\\|&^L|g
s|/|^H/^L^H|g

Note that ^L and ^H are literal formfeed and backspace characters (0x12 and 0x8).

This answer works by moving the cursor around using backspace and formfeed characters. The slashes/backslashes are not left-padded with spaces - Not sure of this disqualifies this answer. This doesn't work in TIO, but it looks fine under common terminals such as xterm and gnome-terminal.

Recreate this sed script as follows:

base64 -d <<< c3xcXHwmDHxnCnN8L3wILwwIfGc= > downslash.sed

Run it as follows:

$ echo '\\\//\/\\' | sed -f downslash.sed
\ 
 \ 
  \ 
  /
 /
 \ 
 /
 \ 
  \ 

$ 

Explanation:

s|\\|&^L|g     # move cursor down after every "\"
s|/|^H/^L^H|g  # move cursor left before every "/", then after, down and left again

Digital Trauma

Posted 2017-09-13T22:04:41.563

Reputation: 64 644

14

Python 2, 55 54 51 57 53 bytes

-3 bytes (and a bug fix) thanks to Felipe Nardi Batista

i=0
for c in input():i-=c<'<'*i;print' '*i+c;i+=c>'<'

Try it online!

Rod

Posted 2017-09-13T22:04:41.563

Reputation: 17 588

56 bytes – Mr. Xcoder – 2017-09-14T13:03:48.513

14

Charcoal, 13 12 11 bytes

FS¿⁼ι/↓¶/↘ι

Try it online! Link is to verbose version of code. Supports extra //s. Explanation:

 S              Input string
F               Loop over each character
  ¿             If
    ι           Current character
   ⁼            Equals
     /          Literal /
      ↓¶        Move left
      ↓ /       Print a / downwards
         ↘ι     Else it's a \ so print that down and right

Neil

Posted 2017-09-13T22:04:41.563

Reputation: 95 035

I think ↓¶ = "Move left" in the description isn't right. – Jonathan Allan – 2017-09-14T00:50:07.543

@JonathanAllan That's right (newline printed down = move left), although it would probably be clearer to say "print \n/ down" – ASCII-only – 2017-09-14T06:47:12.597

I didn't say print \n/ down because I felt that it was more helpful to describe the effect of the code rather than its literal translation. – Neil – 2017-09-14T07:43:48.600

1

(Tongue in cheek: Describing the effect = MyCode - Do the spec). I get it now though the effect is to move left; might be worth saying "Move left (by printing a newline with a downward printing direction)".

– Jonathan Allan – 2017-09-14T16:55:42.937

Most concise and self-explanatory of all! – j4hangir – 2017-09-16T21:48:00.027

10

///, 119 bytes

/// has no input commands, so input must be embedded in the program. For this one, the input string is simply appended, with no escaping needed.

/=/\/\///M/
|%%=N/%|||=C/BA=\/\\/\/C\\=C\\/CbC=B\A\=CfC=AB=/A/%Mxy=B/|z%N|x|y% %N%x|y%%% |fzN%M%b|zN|M|%
=|/AB\\=%/|=AC

How it works

  • In the following, an input of \\/\// will be appended to the program for demonstration.
  • is used to represent newlines in inline code.

Abbreviations

The beginning /=/\/\///M/␤|%%=N/%|||=C/BA= of the program contains substitutions for golfing abbreviations.

  • = expands to //, M to ␤|%%, N to %||| and C to BA.
  • After this the current program becomes

    /\/\\/\/BA\\//BA\\/BAbBA//B\A\//BAfBA//AB///A/%
    |%%xy//B/|z%%||||x|y% %%|||%x|y%%% |fz%|||%
    |%%%b|z%||||
    |%%|%
    //|/AB\\//%/|//ABA\\/\//
    

Input recoding

The next stage transforms the appended input string into a more usable form. Since it consists entirely of ///'s two command characters, this takes some care to avoid mangling the base program.

  • The first substantial substitution, /\/\\/\/BA\\/, replaces the string /\ with /BA\.
    • The base program does not contain /\ at this time, so this substitution doesn't affect it.
    • However, this splits up the appended input string into sequences of \s followed by sequences of /s, which together with the ABA at the end of the base program makes it possible to iterate through it with the following substitutions.
    • Including the ABA prefix before it, the example input string now becomes ABA\\/BA\//.
  • The next substitution, /BA\\/BAbBA/, replaces BA\ by BAbBA.
    • Because /// substitutions are repeated until they no longer match, this iterates through all the \s of the input string, which with prefix now becomes ABAbBAbBA/BAbBA//
  • Similarly, /B\A\//BAfBA/ changes BA/ to BAfBA, iterating through the /s.
    • The escaping \ in this substitution is needed since otherwise it would be mangled by the previous one.
    • The input has now turned into ABAbBAbBAfBABAbBAfBAfBA.
  • Next /AB// removes some superfluous parts of the encoding, turning it into AbBAbBAfBAbBAfBAfBA.
    • This also removes an AB from the /|/AB\\/ substitution later in the program, which was needed to protect it from the above /\ manipulation.
    • At this point every \ in the original input string has become AbB, and every / has become AfB. (b and f stand for backward and forward.) There's a stray A at the end.
  • The next two substitutions replace all the As and Bs with program fragments to run in the final stage. In the replacement strings, %s and |s encode what will become /s and \s respectively. This has two benefits:
    • Unlike / and \, the %s and |s don't need escaping to be copied.
    • The replacement strings avoid containing the substring /\, which would otherwise have been mangled by the previous manipulations.
  • After this, the substitution /|/\\/ (formerly /|/AB\\/) now decodes the |s, after which the following /%/|// has become /%/\// and decodes the %s.

Program structure at final stage

At this point, the base program has run all its substitutions, and all that remains is the program-encoding of the input string.

  • Each input character has become a subprogram

    /
    \//xy*\z//\\\\x\y/ //\\\/x\y/// \fz/\\\/
    \///b\z/\\\\
    \//\/
    

    (trailing newline), where * represents either f for an original /, or b for an original \.

  • There is also an incomplete substitution command /␤\//xy at the end of the program, which will have no effect except to provide a necessary / for the substitutions of the previous subprogram.

Shared substring

Before the final iteration through the subprograms starts, there is a substring crossing the boundary after each character's subprogram of the form \/␤/.

  • These substrings are used as a shared global state. All the remaining substitutions in the program will manipulate them identically and in parallel, such that at the end of each input character's subprogram its copy of this shared substring (except the final /, which anchors the substitutions) will be run to print the line for that character.
  • The initial version of the substring represents printing a line containing just /, which is the right imaginary "previous line" to cause the first input character to be printed at the beginning of its line.
  • In general, during the printing steps, the shared substring consists of a number of spaces, \\ or \/, a newline, and a following /.

Running a character subprogram

Several of the following substitutions contain extra \s inside to prevent them from being matched and mangled by each other (including other copies in other subprograms). Achieving this is also the reason why both of x and y are needed.

  • The first substitution in a character subprogram, /␤\//xyf\z/ or /␤\//xyb\z/, causes the ␤/ at the end of the shared substring to become xyfz or xybz, immediately following the \/ or \\.
  • The substitution /\\\\x\y/ / replaces \\xy by a space, and the substitution /\\\/x\y// replaces \/xy by nothing.
    • They apply when the previous input character printed was a \ or /, respectively.
    • The shared substring now contains the appropriate number of spaces for printing a \ next, followed by fz or bz.
  • The substitution / \fz/\\\/␤\// replaces ​ fz by \/␤/, and /b\z/\\\\␤\// replaces bz by \\␤/.
    • They apply when the current input character is / or \, respectively.
    • The first one eats an extra space to place / correctly.
      • If this space is missing (i.e. input violating the prefix condition), the following substitutions get misinterpreted, printing a lot of junk and usually hitting a ///, which is an infinite loop.
    • Each adds the correct command to print its own character, and reinstates the original ␤/ at the end of the shared substring.
  • The character subprogram has now reached its copy of the shared substring, which is ready to print its line.

After the last character subprogram has run, what remains of the program is /␤\//xy. Since this is an incomplete substitution with missing final /, the program skips it and halts normally.

Ørjan Johansen

Posted 2017-09-13T22:04:41.563

Reputation: 6 914

1The right language for the job! Lol – James – 2018-02-18T19:23:35.200

6

Jelly, 14 bytes

=”\ðḤ’+\_⁸⁶ẋżY

A full program printing the result.

Try it online!

How?

=”\ðḤ’+\_⁸⁶ẋżY - Link: list of characters, s    e.g. "\\\//\\/"
 ”\            - literal '\'                         '\'
=              - equal? (call this e)                [1, 1, 1, 0, 0, 1, 1, 0]
   ð           - new dyadic chain f(e, s)
    Ḥ          - double                              [2, 2, 2, 0, 0, 2, 2, 0]
     ’         - decrement                           [1, 1, 1,-1,-1, 1, 1,-1]
      +\       - cumulative reduce with addition     [1, 2, 3, 2, 1, 2, 3, 2]
         ⁸     - chain's left argument, e            [1, 1, 1, 0, 0, 1, 1, 0]
        _      - subtract (# of leading spaces)      [0, 1, 2, 2, 1, 1, 2, 2]
          ⁶    - literal ' '                         ''
           ẋ   - repeat                              [""," ","  "," "," "," ","  ","  "]
            ż  - zip with s                          [["",'\'],[" ",'\'],["  ",'\'],["  ",'/'],[" ",'/'],[" ",'\'],["  ",'\'],["  ",'/']]
             Y - join with newlines                  ["",'\','\n'," ",'\','\n',"  ",'\','\n',"  ",'/','\n'," ",'/','\n'," ",'\','\n',"  ",'\','\n',"  ",'/']
               - implicit print - this smashes the lists (shown as "..." above) and the characters (shown as '...' above) together.

Jonathan Allan

Posted 2017-09-13T22:04:41.563

Reputation: 67 804

6

Haskell, 49 bytes

scanl(\x c->drop(sum[1|'/'<-c:x])(' '<$x)++[c])[]

Try it online!

dianne

Posted 2017-09-13T22:04:41.563

Reputation: 1 049

5

MATL, 23 19 18 bytes

1 byte off thanks to @Sanchises

fGqoEq1yd~h*YsGZ?c

Input is a string enclosed in single quotes.

Try it online! Or verify test cases: 1, 2, 3.

Explanation

Consider input '\\\//\/\\' as an example.

f      % Implicit input. Array of indices of nonzeros. Since all chars in the input
       % have nonzero code point, this gives [1 2 ... n] where n is input length
       % STACK: [1 2 3 4 5 6 7 8 9]
G      % Push input again
       % STACK: [1 2 3 4 5 6 7 8 9], '\\\//\/\\'
qo     % Subtract 1 from (the code-point) of each char and then compute modulo 2.
       % This transforms '\' into 1 and '/' into 0
       % STACK: [1 2 3 4 5 6 7 8 9], [1 1 1 0 0 1 0 1 1]
Eq     % Double, subtract 1. This transforms 0 into -1
       % STACK: [1 2 3 4 5 6 7 8 9], [1 1 1 -1 -1 1 -1 1 1]
1y     % Push 1 and duplicate from below
       % STACK: [1 2 3 4 5 6 7 8 9], [1 1 1 -1 -1 1 -1 1 1], 1, [1 1 1 -1 -1 1 -1 1 1]
d~     % Consecutive differences, logical negation: gives 1 if consecutive entries
       % are equal, 0 otherwise
       % STACK: [1 2 3 4 5 6 7 8 9], [1 1 1 -1 -1 1 -1 1 1], 1, [1 1 0 1 0 0 0 1]
h      % Horizontally concatenate
       % STACK: [1 2 3 4 5 6 7 8 9], [1 1 1 -1 -1 1 -1 1 1], [1 1 1 0 1 0 0 0 1]
*      % Element-wise multiplication
       % STACK: [1 2 3 4 5 6 7 8 9], [1 1 1 0 -1 0 0 0 1]
Ys     % Cumulative sum
       % STACK: [1 2 3 4 5 6 7 8 9], [1 2 3 3 2 2 2 2 3]
G      % Push input again
       % STACK: [1 2 3 4 5 6 7 8 9], [1 2 3 3 2 2 2 2 3], '\\\//\/\\'
Z?     % Build sparse matrix with those row indices, column indices, and values
       % STACK: [92  0  0;
                  0 92  0;
                  0  0 92;
                  0  0 47;
                  0 47  0;
                  0 92  0;
                  0 47  0;
                  0 92  0;
                  0  0 92]
c      % Convert to char. Char 0 is shown as space. Implicitly display
       % STACK: ['\  ';
                 ' \ ';
                 '  \';
                 '  /';
                 ' / ';
                 ' \ ';
                 ' / ';
                 ' \ ';
                 '  \']

Luis Mendo

Posted 2017-09-13T22:04:41.563

Reputation: 87 464

One byte off by a slightly different algorithm to get your indices: Try it online!

– Sanchises – 2017-09-15T21:29:26.577

@Sanchises Thanks for your very appropriate edits! – Luis Mendo – 2017-09-15T21:31:00.913

5

JavaScript (ES8), 66 59 63 bytes

7 bytes saved thanks to Justin Mariner
+4 bytes to fix /\\/\\/ (noticed by Neil)

f=([a,...z],b=a<'0')=>a?a.padStart(b+=k=a>'/')+`
`+f(z,b-!k):''

Try it online!

user72349

Posted 2017-09-13T22:04:41.563

Reputation:

5

Perl 5, 44 bytes

42 bytes of code + 2 for -F flag

say$"x($s+=$\eq$_&&$#i**m|/|).($\=$_)for@F

Try it online!

Xcali

Posted 2017-09-13T22:04:41.563

Reputation: 7 671

5

C# (.NET Core), 74 88 82 78 77 76 + 18 bytes

-1 byte thanks to Kevin Cruijssen

s=>s.Select((x,i)=>$"{x}".PadLeft((x-s[0])/45-~s.Take(i).Sum(y=>y<92?-1:1)))

Outputs a collection of strings, one for each line. Byte count also includes:

using System.Linq;

Try it online!

Explanation for 77 byte answer:

s =>                              // Take input, a string
    s.Select((x, i) =>            // Replace every character with:
        $"{x}"                    //     The character as string
        .PadLeft(                 //     Pad with this many spaces:
            s.Take(i)             //         Take characters, in the input string, preceding current one
            .Sum(y =>             //         Sum them by:
                y < 92 ? -1 : 1   //             If it's a \ add 1, if / subtract 1
            )
            + (x - s[0]) / 45 + 1 //         If first slash is a / add one more space, if current slash is a \ add one more space (I got this through power of MATHS!)
                                  //         How I arrived at this function:
                                  //         + x / 48        If current slash is a \ add one more space
                                  //         - s[0] / 48 + 1 If the first slash is a / add one more space
        )
    )

Grzegorz Puławski

Posted 2017-09-13T22:04:41.563

Reputation: 781

3Doesn't work for /\\/\\/. – Neil – 2017-09-14T09:58:13.623

@Neil thank you for pointing that out! Fixed. – Grzegorz Puławski – 2017-09-14T10:06:02.003

1I know it's been a while, but you can save a byte by changing s.Take(i).Sum(y=>y<92?-1:1)+(x-s[0])/45+1 to (x-s[0])/45-~s.Take(i).Sum(y=>y<92?-1:1) – Kevin Cruijssen – 2018-02-09T13:33:33.613

Nice one @KevinCruijssen ! – Grzegorz Puławski – 2018-02-12T09:57:17.620

4

05AB1E, 14 bytes

ÇÈx<ηOs-W-ISú»

Try it online!

Explanation

Ç                # convert input string to a list of ascii codes
 È               # check each for evenness
  x              # push a doubled copy
   <             # decrement
    η            # compute prefixes
     O           # sum each prefix
      s          # swap the unaltered copy of evenness to the top
       -         # subtract from the prefix-sum list
        W-       # subtract the minimum value
          IS     # push input split to a list of chars
            ú    # pad each with the number of spaces computed
             »   # join on newline

Emigna

Posted 2017-09-13T22:04:41.563

Reputation: 50 798

1Doesn't work for /\\/\\/. – Neil – 2017-09-14T09:57:48.257

Ç¥.¥0<.SηOv¹Nèy<ú, sobbing in binary – Magic Octopus Urn – 2017-09-15T18:21:48.463

3

Retina, 47 bytes

^|\\
 $&
+m`^( *)( /|\\)(/| \\)
$1$2¶$1$3
m`^ 

Try it online! Link includes test cases. Explanation:

^|\\
 $&

Add a space at the beginning of each line and before each \.

+m`^( *)( /|\\)(/| \\)
$1$2¶$1$3

Consider the first two characters of the string. If the first is a / then the indent needs to be decremented; this is achieved by including the preceding space in the capture (which always exists because the first stage added it); if the second is a \\ then it needs to be incremented; this is achieved by including the space that the first stage added in the capture. Having given the second character the correct indent, the stage is repeated for the second and third character etc.

m`^ 

Remove the extra indent.

I've written a 94-byte version which (like my Charcoal answer) allows any combination of slashes: Try it online! Explanation:

.$
¶$.`$* $&

Get the ball rolling by taking the last slash and indenting it to the same position on its own line.

/
 /

Prefix spaces to all forward slashes so that they can be captured.

+`^(.*)( /|\\)¶( *)( \\|/)
$1¶$3$2¶$3$4

Repeatedly take the last slash of the input and align it on its own line with the slash on the line below.

+ms`^(?<!^[\\/].*) (?!.*^[\\/])

Delete any left-over indentation.

G`.

Delete the now empty input.

Neil

Posted 2017-09-13T22:04:41.563

Reputation: 95 035

3

C (GCC), 137 134 97 bytes

Try it online!

• 3 bytes thanks ATaco

• 37 bytes thanks to Digital Trauma & ThePirateBay

i,d;f(char*s){char c=s[i],n=s[++i];if(c){printf("%*c%c\n",d+1,c);(c-n)?d:(c==47)?--d:++d;f(s);}}

Nothing too fancy just a simple recursive function that takes a string and prints out the slashes, note that the input needs to escape the backslashes first.

Usage

f("\\\\\\//\\/\\\\",0,0);

Ungolfed

This is for the old answer, view the try it online link for updated one!

f(char *s, i, d) {
    char c=s[i], n=s[++i];
    if(!c) return;
    for(int j=0; j<d; j++) printf(" ");
    printf("%c\n",c);
    f(s, i, (c!=n)?d:(c=='/')?d-1:d+1);
}

Output

enter image description here

Asleepace

Posted 2017-09-13T22:04:41.563

Reputation: 311

You can replace c=='\0' with !c for the same effect. – ATaco – 2017-09-14T03:57:28.327

Awesome thanks just updated the solution! – Asleepace – 2017-09-14T04:46:51.333

Can you use printf("%*s%c", n, "", c) to print the the char c with n leading spaces? – Digital Trauma – 2017-09-14T05:29:47.560

I'm pretty sure you can save few bytes by replacing (c!=n) with c-n and rearranging ternary expressions. Same with (c=='/'). Also, you can replace '/' with literal number 47. I think it is 7 bytes in total. – None – 2017-09-14T06:50:25.217

The function signature is invalid – ASCII-only – 2017-09-14T06:52:45.077

178 bytes – ASCII-only – 2017-09-14T07:26:09.287

@ThePirateBay Can you help me golf it :P – ASCII-only – 2017-09-14T07:33:19.407

78 bytes, fancier output – ASCII-only – 2017-09-14T07:36:46.040

@ASCII-only. 72 bytes. Always use - instead of ==. Here is even better situation, because we can do bit hacking.

– None – 2017-09-14T07:46:55.897

@ThePirateBay Oh true lol – ASCII-only – 2017-09-14T07:55:41.470

@ThePirateBay & Digitial Trauma thanks I updated my answer! – Asleepace – 2017-09-14T18:27:52.563

@ASCII-only My C answer is only 60 bytes :) – orlp – 2017-09-14T22:40:37.807

3

Java 8, 121 118 110 109 102 bytes

a->{String r="";int s=0,p=0,i;for(char c:a){for(i=s+=p+(p=c-63)>>5;i-->0;r+=" ");r+=c+"\n";}return r;}

-7 bytes thanks to @Nevay's bit-wise magic. :)

Explanation:

Try it here.

a->{                    // Method with char-array parameter and String return-type
  String r="";          //  Return-String
  int s=0,              //  Amount of spaces
      p=0,              //  Previous characters (starting at 0)
      i;                //  Index-integer
  for(char c:a){        //  Loop over the input
    for(i=s+=p+(p=c-63)>>5;
                        //   If the current does not equals the previous character
                        //    Leave `s` the same
                        //   Else-if it's a '\':
                        //    Increase `s` by 1
                        //   Else (it's a '/'):
                        //    Decrease `s` by 1
                        //   And set the previous character to the current in the process
        i-->0;r+=" ");  //   Append `r` with `s` amount of spaces               
    r+=c+"\n";          //   Append the character + a new-line to the result
  }                     //  End of loop
  return r;             //  Return result-String
}                       // End of method

Kevin Cruijssen

Posted 2017-09-13T22:04:41.563

Reputation: 67 575

1102 bytes: a->{String r="";int s=0,p=0,i;for(char c:a){for(i=s+=p+(p=c-63)>>5;i-->0;r+=" ");r+=c+"\n";}return r;} – Nevay – 2017-09-14T10:31:04.197

@Nevay Thanks. I knew it could be shortened with some bitwise operations, but couldn't figure it out. Mainly because I forgot about trying the effects of >>/>>>/<<... I had only checked some things with &/|/~/^..>.> – Kevin Cruijssen – 2017-09-14T11:45:08.673

3

R, 122 121 bytes

-1 byte thanks to Giuseppe

x=el(strsplit(scan(,""),""));n=seq(x);y=x>"/";for(i in n)cat(rep(" ",diffinv(y[n[-1]-1]+y[n[-1]]-1)[i]),x[i],"\n",sep="")

Try it online!

With extra whitespace:

x = el(strsplit(scan(,""),""))
n = seq(x)
y = x>"/"
for(i in n) {
  cat(rep(" ", diffinv(y[n[-1]-1]+y[n[-1]]-1)[i]), x[i], "\n", sep="")
}

Explanation: This answer is based on the observation that the number of leading spaces changes each line by -1, plus the number of / in the previous and current lines.

If we have N slashes, the variable y is a vector of length N, with 1 for each position with \, 0 otherwise. Therefore, to get the change in number of leading spaces per line, we calculate y[1:(N-1)] + y[2:N] - 1. The function diffinv converts these differences into a sequence, starting with 0. The rest is just a matter of assembling each line as the required number of trailing spaces, followed by the relevant slash and a newline.

user2390246

Posted 2017-09-13T22:04:41.563

Reputation: 1 391

1

huh. I took a quite different approach for 119 bytes which makes me wonder if we could combine our approaches. (nice use of diffinv ;) Also you can set y=x>")" for -1 byte

– Giuseppe – 2017-09-14T14:07:18.633

@Giuseppe You should post that as a separate answer, it's a different enough approach. Yours is a nice way of avoiding having to do strsplit, which is always a killer. You can also make use of the famous diffinv! – user2390246 – 2017-09-14T14:13:22.323

1Also I think if you put library(methods) in the header (which should be OK w/o penalty since that package is part base R), you can use el. Also, diffinv turned out to be just as long as cumsum! :) – Giuseppe – 2017-09-14T14:34:34.280

Yes, I was just realising that too, it doesn't quite work in that context – user2390246 – 2017-09-14T14:40:37.770

well, I came up with a workaround, but yeah, that *S screws things up.

– Giuseppe – 2017-09-14T14:41:32.100

3

Brain-Flak, 175 bytes (174 chars + 1 flag)

Run with -c flag.

{(({})<(())>){({}[()]<([{}])>)}{}(({}<>{}<><({}<>)((()()()()()){})>)<{({}[()]<((((()()()()){}){}){})>)}>{})<>}<>{}{({}<>)(({})(())){({}[()]<([{}]())>)}{}{<>{}<>(<{}>)}{}<>}<>

Try it online!

Explanation

{ for each char in the input...
  (({})<(())>){({}[()]<([{}])>)}{} push 1/-1 for backslash/slash
  ((
   {}<>{}<> add the 1/-1 to a running total
   <
    ({}<>) move slash/backslash to other stack
    ((()()()()()){}) newline
   >
  )<{({}[()]<((((()()()()){}){}){})>)}>{}) spaces
  <>
}<>{} end for
reverse data order, removing one space before backslash
{({}<>)(({})(())){({}[()]<([{}]())>)}{}{<>{}<>(<{}>)}{}<>}<>

MegaTom

Posted 2017-09-13T22:04:41.563

Reputation: 3 787

I always upvote brain-flak. :D – James – 2017-09-14T19:33:10.420

3

Ruby, 80 76 bytes

-4 bytes thanks to manatwork

puts"\\";$*[i=0].chars.each_cons 2{|b,c|puts" "*(b==c ?b==?/?i-=1:i+=1:i)+c}

Try it online!

Explanation:

puts "\\"           # Output the first backslash
$*[i=0].            # Get the first argument and set i to 0
chars.              # Go through every individual character,
each_cons 2 { |b,c| # In pairs to compare easily
                    #
    puts " " *      # Decide how many padding spaces to use based on the value
                    # of i. The expression inside the parenthesis will return
                    # i but before that, it will increment/decrement i based
                    # on what the previous character was.
                        #
    ( b==c ?            # if b == c
        b==?/ ?         #   if b == "/" (Going to the left)
            i-=1        #       return decremented i
            :           #   else        (Going to the right)
            i+=1        #       return incremented i
        :               # else
        i) +            #   return i
                    #
                c   # Finally, write the second of the characters that we're
}                   # iterating through.

Pazzaz

Posted 2017-09-13T22:04:41.563

Reputation: 141

1Which Ruby version? The 2.3.3 I have demands parenthesis around parameter when code block follows: .each_cons(2){…}. In change you can save by replacing .each_char.chars. – manatwork – 2017-09-14T19:59:55.930

@manatwork My ruby version is 2.4.1. Thanks for the suggestion about chars, I didn't know about that one. – Pazzaz – 2017-09-14T20:13:56.840

You can save another two bytes by moving i+= to the beginning of the nested ternary expression, and ending it with -1:1:0. – benj2240 – 2018-02-13T20:31:27.537

3

C, 60 bytes

i;f(char*s){for(i=1;*s;s++)printf("%*c\n",*s%2?--i:i++,*s);}

Try it online!

orlp

Posted 2017-09-13T22:04:41.563

Reputation: 37 067

-1 no TIO link :P – ASCII-only – 2017-09-14T23:38:42.103

TIO – ASCII-only – 2017-09-14T23:45:08.773

@ASCII-only you're welcome – Stan Strum – 2017-09-25T02:48:31.647

2

Lua, 96 bytes

c=0 for s in(...):gmatch(".")do c=c+(p==s and(s=="/"and-1or 1)or 0)p=s print((" "):rep(c)..s)end

Try it online!

Shortest one I could come up with in Lua. Input is taken from the command line.

This does use a few tricks:

  1. (...):gmatch(
    This should be the shortest form of getting a single string into a Lua program from the command line. The ... expression in Lua captures any excess parameters to a function that aren't specified in the function declaration and is used for varargs. Since the main body of a Lua program gets called as a function with the command line arguments as its parameters, the command line arguments will end up in ....
    The parentheses around it turn the potentially multi-valued ... expression into a single-valued expression. Consider this (somewhat surprising) example:
    function multipleReturnValues()
        return "abc", "def"
    end
    print(  multipleReturnValues()  ) --This prints: abc    def
    print( (multipleReturnValues()) ) --This prints: abc
  2. The Lua parser does not need any line terminators, or even whitespace between statements, as long as the two statements' tokens can be clearly separated and there's only one interpretation of the text that's valid Lua code.
  3. Abusing and/or for "if x then value1 else value2" logic.
    Lua's and operator returns its first argument if it is falsy; otherwise, it returns its second argument. The or operator returns its first argument if it is truthy; otherwise, the second argument.
  4. pdoesn't need any initialization.
    p==s always has to be false in the first run of the loop, regardless of the input. Not setting p to any value before entering the loop (leaving it nil) will make that happen and save bytes, too.

Can anyone golf this (in Lua)?

Jonathan S.

Posted 2017-09-13T22:04:41.563

Reputation: 423

I was able to save two bytes by using gsub instead of using gmatch. c=0(...):gsub(".",function(s)c=c+(p==s and(s=="/"and-1or 1)or 0)p=s print((" "):rep(c)..s)end) – QuertyKeyboard – 2017-09-14T21:03:31.290

Well, not that it matters. You could've easily saved two bytes by changing gmatch(".") to gmatch"." like you did in your next answer. – QuertyKeyboard – 2017-09-14T21:23:56.747

@QuertyKeyboard That's weird... I actually used gsub exactly like this in the first version of this code, but then switched to gmatch instead because it somehow turned out shorter. I don't know what I did different though, the file is overwritten unfortunately. – Jonathan S. – 2017-09-14T21:50:30.307

2

Pyth, 28 bytes

j.u+?qeNY?>Y\/+PNdPPNPNYtzhz

Try it online!

Leaky Nun

Posted 2017-09-13T22:04:41.563

Reputation: 45 011

You can save a byte by using Q instead: j.u+?qeNY?>Y\/+PNdPPNPNYtQh.

– Erik the Outgolfer – 2017-09-14T12:50:18.130

26 bytes – Stan Strum – 2017-09-16T03:29:13.350

2

R, 119 bytes

function(s)for(i in 1:nchar(s))cat(rep(" ",cumsum(c(0,!diff(S<-(utf8ToInt(s)>48)*2-1))*S)[i]),substr(s,i,i),"
",sep="")

Try it online!

This differs somewhat from user2390246's answer. They each iterate over the string, printing out a certain number of space characters and then the appropriate /\ character.

However, I avoided splitting the string, opting instead to replace the characters with their UTF-8 encoding value instead, which then allows me to do arithmetic on the numbers directly, which saved me just a few bytes.

Giuseppe

Posted 2017-09-13T22:04:41.563

Reputation: 21 077

Just been pondering this some more, I think there is an error in your algorithm: TIO

– user2390246 – 2017-09-14T14:48:44.353

@user2390246 I fixed it! I had some misplaced parentheses, but now the diffinv definitely won't work here. – Giuseppe – 2017-09-14T20:04:57.760

2

Lua, 88 84 bytes

Improved version (-4 bytes thanks to QuertyKeyboard)

s=""g=s.gsub g(...,".",function(c)s=g(g(g(s,"\\"," "),"/?$",c)," /","/")print(s)end)

Try it online!

Original version (88 bytes)

Another attempt in Lua, this time with a completely different approach using string manipulation instead of a counter variable.

s=""for c in(...):gmatch"."do s=s:gsub("\\"," "):gsub("/?$",c):gsub(" /","/")print(s)end

Ungolfed:

s = ""
for c in string.gmatch((...), ".") do --for each character in the input
  --s contains the output from the previous iteration
  s = s:gsub("\\", " ") --Replace backslash with space -> indent by 1
  s = s:gsub("/?$", c) --Remove any / at the end of the string and append c to the string
  s = s:gsub(" /", "/") --Remove a single space in front of any / -> un-indent by 1
  print(s)
end

There's one interesting thing in the code: (...):gmatch"."
This uses some quirks in the Lua parser. When Lua encounters a piece of code in the form func "string", it'll convert this to func("string"). This is so that one can write print "string" to print a constant string and it only works with a single string literal after the function. Anything else will give a syntax error. However, this syntactic sugar also works with function calls in the middle of an expression, and more surprising, it works just fine together with the : method call syntactic sugar. So in the end, Lua will interpret the code like this:

(...):gmatch"."
-> (...):gmatch(".")
-> string.gmatch((...), ".")

If anyone can think of a way to remove one of the three gsub calls, please tell me.

Jonathan S.

Posted 2017-09-13T22:04:41.563

Reputation: 423

1I was disappointed to find that my gsub trick I commented in your other answer didn't quite work for this one. It actually ended up adding one byte. However, I wouldn't give up that easily. First, I tried to store gsub as a variable to shorten the code. To my surprise, my code was exactly the same amount of bytes - 88. However, I realized that with gsub being saved, my gsub trick could now work! Here's my code that shaved off 4 bytes: s=""g=s.gsub g(...,".",function(c)s=g(g(g(s,"\\"," "),"/?$",c)," /","/")print(s)end) – QuertyKeyboard – 2017-09-14T21:22:03.357

@QuertyKeyboard Yup, I also tried storing gsub in a variable before the loop and then using it instead of writing gsub three time, and I was just as surprised to see it making absolutely no difference. Combining the "gsub instead of loop" and "store gsub" tricks is really neat, didn't think of that one! Thanks! :) – Jonathan S. – 2017-09-14T21:53:23.547

2

C# (.NET Core), 60/65 bytes

I tried shorter C# version

s=>{int i=0;return s.Select(x=>"".PadLeft(x<92?--i:i++)+x);}

as there was stated: "This also means that every input will start with a backslash." Or slighly longer which solve starting "/"

s=>{int i=s[0]&1;return s.Select(x=>"".PadLeft(x<92?--i:i++)+x);}

Try it online!

Dan

Posted 2017-09-13T22:04:41.563

Reputation: 21

Welcome to the site! :) – James – 2017-09-14T20:09:11.097

1

Pyth - 33 bytes

First attempt, will golf.

jsMC,*L;+ZsM._*VqVtzztMxL"/ \\"zz

Try it online here.

Maltysen

Posted 2017-09-13T22:04:41.563

Reputation: 25 023

my first attempt 32 bytes – Stan Strum – 2017-09-15T19:24:47.827

second attempt 28 bytes – Stan Strum – 2017-09-15T19:26:56.133

third attempt 26 bytes – Stan Strum – 2017-09-16T03:27:51.227

pinged @maltysen – Stan Strum – 2017-09-25T02:51:21.943

@StanStrum at this point, u can just post it as your own answer – Maltysen – 2017-09-25T17:10:08.553

right mate see you there – Stan Strum – 2017-09-25T18:11:45.913

1

Perl, 40 + 2 bytes

/\//&&$.--,say($"x$.,$_),/\\/&&$.++for@F

You need the -F flag.

user73921

Posted 2017-09-13T22:04:41.563

Reputation:

1

Perl, 34 38 + 1 bytes

to handle the two cases

s,(/)|.,$"x($1?$c&&--$c:$c++).$&.$/,ge

to be run with -p option

s,(/)|.,$"x($1?--$c:$c++).$&.$/,ge

EDIT: following comment doesn't work when first character is /

s,(/)|.,$"x($1?$c--:++$c).$&.$/,ge

however output will be shifted one character on the right if first char is \

Nahuel Fouilleul

Posted 2017-09-13T22:04:41.563

Reputation: 5 582

1Doesn't work for /\\/\\/. – Neil – 2017-09-14T09:59:00.180

With the updated question your original 34 solution is now perfectly valid – Ton Hospel – 2018-02-08T19:35:51.517

1

Pyth, 24 21 bytes

Port from Rod's answer.

VQ=-Z<N\<+*ZdN=+Z>N\<

Try it online!

Felipe Nardi Batista

Posted 2017-09-13T22:04:41.563

Reputation: 2 345

Invalid, prints [extra leading space on the first line if the string starts with \. BTW where is your code? – Mr. Xcoder – 2017-09-14T12:59:24.103

@Mr.Xcoder fixed – Felipe Nardi Batista – 2017-09-14T13:05:00.567

1

VBA (Excel), 181 bytes

Sub q()
a = Cells(1, 1)
For x = 1 To Len(a)
c = Mid(a, x, 1)
If c = "\" Then: Debug.Print b & c: b = b + " "
If c = "/" Then: b = Left(b, Len(b) - 1): Debug.Print b & c
Next
End Sub

remoel

Posted 2017-09-13T22:04:41.563

Reputation: 511

1You can golf this down significantly without changing your algorithm by taking advantage of the autoformatting nature of Excel VBA and by use of [...] notation: I got it down to 128 Bytes Sub q For x=1To[Len(A1)] c=Mid([A1],x,1) If c="\"Then Debug.?b;c:b=b+" " If c="/"Then b=Left(b,Len(b)-1):Debug.?b;c Next End Sub – Taylor Scott – 2017-09-15T17:50:25.663

Thank you for golfing my script. I learned something from this and will apply in the future. :) Didn't know I can use that to fetch data directly to the cells. Thanks again :) – remoel – 2017-09-18T04:42:10.850

1

SOGL V0.12, 16 13 bytes

{└=-:↕PFoF┘=+

Try it Here! - expects input on the stack, so for ease-of-use , is added

dzaima

Posted 2017-09-13T22:04:41.563

Reputation: 19 048

1

Implicit, 25 bytes

~.(´?`/ò](0ß´);@ß1?`\ó~.ö

Try it online!

Ungolfed/explanation:

~.         read input, increment
(          do..while top of stack truthy
 ´         decrement

 ?`/{      if input equal to /
   ]´[      decrement memory
 }

 ](0       pull memory, do..while truthy
  @32       print a space
  ´         decrement
 );        pop

 @@10      print input, print a newline

 ?`\{      if input equal to \
   ].[      increment memory
 }

 ~.        read input, increment
)          loop
&          exit (avoid implicit output)

Note that ß is equal to @32, ò is equal to ]´[, ó is equal to ].[, and ö can be used in place of )& when at the end of a program.

MD XF

Posted 2017-09-13T22:04:41.563

Reputation: 11 605

1

Dyalog APL, 31 bytes

{↑⍵,¨⍨' '/¨⍨{⍵-⍨+\¯1+2×⍵}⍵='\'}

Try it here!

dzaima

Posted 2017-09-13T22:04:41.563

Reputation: 19 048

{↑⍵↑¨⍨a-1-+\¯1*a←⍵='\'} – ngn – 2018-02-09T00:19:42.483

1

QBasic, 79 bytes

DO
c$=INPUT$(1)
IF"/">c$THEN END
c=2*ASC(c$)-139
i=i+c+p
?SPC(i\90);c$
p=c
LOOP

This program prints the slashes as you type them. To quit, press Enter (or anything earlier in the ASCII table than /).

Downslashes program in action

Explanation

With the variables i and p implicitly initialized to 0, we enter an infinite loop. INPUT$(1) reads one character from keyboard input. If this character is less than forward slash, END the program. Otherwise, we calculate c such that an input of / gives c=-45 and \ gives c=45. We then add c and p (the previous value) to i (the indent).

If p and c are the same, they add together to change i by either -90 or +90. If they are different, they cancel out and do not change i. We then print i\90 spaces followed by the character. (We use integer division because the value of i is actually going to be 45, 135, etc., since p is 0 on the first iteration instead of -45.)

Finally, set p=c for the next iteration, and loop.

DLosc

Posted 2017-09-13T22:04:41.563

Reputation: 21 213

1

Perl, 33 bytes

Includes +1 for the n option

perl -nE 's%.%say$"x(l^$&?--$a:$a++).$&%eg' <<< '\\\//\/\\'

Where it not for the fact that -F counts as +3 this would be 32:

echo -n '\\\//\/\\' | perl -F -E 'say$"x(l^$_?--$a:$a++).$_ for@F'

Ton Hospel

Posted 2017-09-13T22:04:41.563

Reputation: 14 114

1

Python 3, 78 bytes

a,x='',0
for i in input():x+=((1*i!='/')-(1*i=='/'))*(a==i);print(' '*x+i);a=i

Try it online!

Dat

Posted 2017-09-13T22:04:41.563

Reputation: 879

0

Python 2, 86 76 75 bytes

-1 byte thanks to Neil.

p,i='',0
for c in input():i+={'\\\\':1,'//':-1}.get(p+c,0);print' '*i+c;p=c

Try it online!

Fairly lame approach, I will try to golf the mapping at least. NVM I got rekt by another answer. >_>

totallyhuman

Posted 2017-09-13T22:04:41.563

Reputation: 15 378

0

V, 14 bytes

\/j>G
ç¯/<G

Try it online!

James

Posted 2017-09-13T22:04:41.563

Reputation: 54 537

0

Rust, 165 bytes

fn f(s:&str){let(_,a)=s.chars().fold((0,"".to_string()),|(i,r),c|(if c<'<'{i-1}else{i+1},format!("{}{}{}\n",r," ".repeat(if c<'<'{i-1}else{i}),c)));println!("{}",a)}

Try it online!

It's an adaptation of Rod's answer in Python 2.

jferard

Posted 2017-09-13T22:04:41.563

Reputation: 1 764

0

c64 basic v2, 71 70 61 bytes

1rEs:x=1024:fOy=1tolE(s):a=aS(mI(s,y,1)):pOx,a:x=x-165+a*2:nE

Input can be given as

0dA"\\/\/\\/\//"

If the string is longer as 25, the program will overwrite its own memory. And we won't do that, because basic programs overwriting themselves with POKEs contradict the OO paradigm.

peterh - Reinstate Monica

Posted 2017-09-13T22:04:41.563

Reputation: 347

0

Excel VBA, 74 72 Bytes

Anonymous VBE immediate window function that takes input from cell [A1] and outputs to the VBE immediate window

For i=1To[Len(A1)]:c=Mid([A1],i,1):s=s+(c="/"):?Spc(s)c:s=s-(c="\"):Next

Example I/O

[A1]="\\\//\\/\//\\///"
For i=1To[Len(A1)]:c=Mid([A1],i,1):s=s+(c="/"):?Space(s)c:s=s-(c="\"):Next
\
 \
  \
  /
 /
 \
  \
  /
  \
  /
 /
 \
  \
  /
 /
/

Taylor Scott

Posted 2017-09-13T22:04:41.563

Reputation: 6 709

0

GolfScript - 117 bytes

1/{'/'=}%1:s;[{s}{..(\;!?.0<{;,0:s;}{.@\>}if}while]0:M;1:i;{,{i*}%:a{M+' '*i 0<{'/'}{"\\"}if +"\n"+}/a)M+:M;;i~):i;}/

Ungolfed version

1/{'/'=}%
1:s;
[{s}
{
  ..(\;!?.0<{;,0:s;}{.@\>}if
}
while]
0:M;
1:i;
{
  ,{i*}%:a{M+' '*i 0<{'/'}{"\\"}if +"\n"+}/
  a)M+:M;;
  i~):i;
}/

At first glance it looked easy... it took me 2.5 hours. Probably there is room for improvement, perhaps tomorrow I'll do some optimization.

FedeWar

Posted 2017-09-13T22:04:41.563

Reputation: 271

0

JavaScript, 49 48 bytes

Takes input as an array of individual characters and outputs an array of lines.

a=>a.map(c=>" ".repeat(x+=d=c>'/',x-=!d)+c,x=-1)

Saved a byte borrowing a trick from the other JS solution.


Try it

f=
a=>a.map(c=>" ".repeat(x+=d=c>'/',x-=!d)+c,x=-1)
o.innerText=[String.raw`\\\\\\\\\\\\`,String.raw`\\\//\\/\//\\///`,String.raw`\/\/\/`].map(s=>f([...s]).join`\n`).join`\n\n`
oninput=_=>o.innerText=f([...i.value]).join`\n`
<input id=i><pre id=o>

Shaggy

Posted 2017-09-13T22:04:41.563

Reputation: 24 623

0

SmileBASIC, 65 bytes

INPUT S$WHILE""<S$C$=SHIFT(S$)DEC N,@L>C$?" "*N;C$INC N,@H<C$WEND

12Me21

Posted 2017-09-13T22:04:41.563

Reputation: 6 110

0

K4, 31 bytes

Solution:

-1(-1+\a-a*~~':a:-1 1"/"=x)$$x:

Examples:

q)k)-1(-1+\a-a*~~':a:-1 1"/"=x)$$x:"\\\\\\//\\\\/\\//\\\\///"
\
 \
  \
  /
 /
 \
  \
  /
  \
  /
 /
 \
  \
  /
 /
/

Works if you start with a / too:

q)k)-1(-1+\a-a*~~':a:-1 1"/"=x)$$x:"/\\\\/\\\\/"
/
\
 \
 /
 \
  \
  /

Explanation:

Generate list of negative numbers to (left) pad each of the input characters. Struggled to get a formula that worked, will look at the other solutions to see if there is a more simple method:

q)k)"/"=x
0001100101100111b
q)k)-1 1"/"=x
-1 -1 -1 1 1 -1 -1 1 -1 1 1 -1 -1 1 1 1
q)k)~~':a:-1 1"/"=x
1001010111010100b
q)k)a*~~':a:-1 1"/"=x
-1 0 0 1 0 -1 0 1 -1 1 0 -1 0 1 0 0
q)k)a-a*~~':a:-1 1"/"=x
0 -1 -1 0 1 0 -1 0 0 0 1 0 -1 0 1 1
q)k)+\a-a*~~':a:-1 1"/"=x
0 -1 -2 -2 -1 -1 -2 -2 -2 -2 -1 -1 -2 -2 -1 0
q)k)-1+\a-a*~~':a:-1 1"/"=x
-1 -2 -3 -3 -2 -2 -3 -3 -3 -3 -2 -2 -3 -3 -2 -1

Full breakdown:

-1(-1+\a-a*~~':a:-1 1"/"=x)$$x: / the solution
                             x: / save input as variable x
                            $   / string (converts to char lists))
                           $    / pad
  (                       )     / do this together
                     "/"=x      / boolean list of x equal to /
                 -1 1           / index into this list
               a:               / save as variable a
           ~~':                 / differ (not-not-each-previous)
         a*                     / multiply by a
       a-                       / subtract from a
     +\                         / sums
   -1                           / (start summing from -1)
-1                              / print to stdout

streetster

Posted 2017-09-13T22:04:41.563

Reputation: 3 635

0

Japt -R, 13 bytes

¬®ùZ>'/?°V:V´

Try it online!

Unpacked & How it works

Uq mZ{ZùZ>'/?++V:V--

Input: U = string of / and \, V = 0 (default)

Uq                    Split into chars
   mZ{                Map...
        Z>'/?           If the char is rightward (backslash)...
             ++V          Pre-increment V
                :V--      Otherwise, post-decrement V
      Zù                Left-pad the char with spaces to length V

-R                    Join with newline before printing

Bubbler

Posted 2017-09-13T22:04:41.563

Reputation: 16 616