Make some Alphabet Rain

54

5

Alphabet Rain

The Task:

The basic premise is to print out the input string and then repeat each character vertically, based on it's (0-indexed) position in the (case-insensitive) alphabet A-Z. A is at location 0 so is not repeated, e is at position 4 so is repeated 4 times, P is at position 15 so is repeated 15 times, ! is not in A-Z so is repeated 0 times, etc.

For clarity, anything that falls outside of the range B-Zb-z, for example digits or special characters, will not be repeated, and thus will only appear on the first line.

This is , so shortest solution in each language is the winner.

Input:

  • Input will be in the standard printable ASCII character set, from 32 up to 126 ~.
  • The input string will be 1 character long or longer.
  • There will not be any leading or trailing whitespace.
  • You can take take input as a string ("hello") or list of characters ( ["h", "e", "l", "l", "o"])

Examples:

Input of aaaa gives:

aaaa

Input of abcda gives:

abcda
 bcd
  cd
   d

Input of Programming Puzzles & Code Golf!, gives:

Programming Puzzles & Code Golf!
Progr mming Puzzles   Code Golf
Progr mming Puzzles   Code Golf
Progr mming Puzzles    ode Golf
Progr mming Puzzles    o e Golf
Progr mming Puzzl s    o   Golf
Progr mming Puzzl s    o   Gol
Pro r mmin  Puzzl s    o    ol
Pro r mmin  Puzzl s    o    ol
Pro r mm n  Puzzl s    o    ol
Pro r mm n  Puzzl s    o    ol
Pro r mm n  Puzzl s    o    ol
Pro r mm n  Puzz  s    o    o
Pro r    n  Puzz  s    o    o
Pro r       Puzz  s    o    o
Pr  r       Puzz  s
 r  r        uzz  s
 r  r        uzz  s
             uzz  s
             uzz
             uzz
              zz
              zz
              zz
              zz
              zz

Input of ~|[abc<0>cba]|~, gives:

~|[abc<0>cba]|~
    bc   cb
     c   c

Notes:

  • standard loopholes apply
  • output can be a list of strings, but:
  • extraneous trailing newlines are not allowed (single \n on final line is acceptable)
  • output can be a list of lists of characters, so long as it looks like it's raining characters
  • no leading newline
  • to our Nordic users who have a few extra letters in their "A-Z" alphabet, feel free to support them, but it's not part of the challenge

streetster

Posted 2017-10-10T09:24:29.260

Reputation: 3 635

2Is a single leading \n acceptable? – Lynn – 2017-10-10T12:01:26.557

@Lynn, no leading newlines, the first line should be the input string/character list - I'll update the post! – streetster – 2017-10-10T14:25:07.887

18FWIW, I think they look more like icicles than rain – caird coinheringaahing – 2017-10-10T18:39:05.367

@cairdcoinheringaahing sounds almost festive – Pureferret – 2017-10-11T17:02:03.430

:( Just Nordic? – ASCII-only – 2017-10-12T03:10:18.380

Just cos I know the Danish alphabet goes a-å rather than a-z, so was just mean as a fun bonus if anyone wanted to tackle it :) – streetster – 2017-10-12T07:15:17.800

Answers

22

6502 machine code (C64), 113 bytes

00 C0 20 FD AE 20 9E AD 85 FB 20 A3 B6 A0 00 84 FC B1 22 99 6F C1 C9 41 90 14 
C9 5B B0 04 E9 40 B0 0E C9 C1 90 08 C9 DB B0 04 E9 C0 B0 02 A9 00 99 6F C0 C5 
FC 30 02 85 FC C8 C4 FB D0 D3 A9 00 99 6F C1 A0 C1 A9 6F 20 1E AB A9 0D 20 D2 
FF A6 FC D0 01 60 C6 FC A0 00 B9 6F C1 F0 E6 BE 6F C0 D0 07 A9 20 99 6F C1 D0 
05 CA 8A 99 6F C0 C8 D0 E7

screenshot

Online demo

Usage: sys49152,"[string]", e.g. sys49152,"Programming Puzzles & Code Golf!".

Important: If the program was loaded from disk (like in the online demo), issue a new command first! This is necessary because loading a machine program trashes some C64 BASIC pointers.

Note: The C64 is by default in a mode without lowercase letters -- in order to be able to enter a mixed-case string, switch to lowercase mode first by pressing SHIFT+CBM.


Explanation

Here's a commented disassembly listing:

         00 C0       .WORD $C000        ; load address
.C:c000  20 FD AE    JSR $AEFD          ; consume comma
.C:c003  20 9E AD    JSR $AD9E          ; evaluate expression
.C:c006  85 FB       STA $FB            ; store string length
.C:c008  20 A3 B6    JSR $B6A3          ; free string
.C:c00b  A0 00       LDY #$00           ; initialize counter
.C:c00d  84 FC       STY $FC            ; and number of "extra" lines
.C:c00f   .copyloop:                    
.C:c00f  B1 22       LDA ($22),Y        ; load next character
.C:c011  99 6F C1    STA .outbuf,Y      ; store to buffer
.C:c014  C9 41       CMP #$41           ; compare with 'a'
.C:c016  90 14       BCC .zerocount     ; smaller -> no repetition
.C:c018  C9 5B       CMP #$5B           ; compare with 'z'
.C:c01a  B0 04       BCS .checkupper    ; larger -> check for uppercase
.C:c01c  E9 40       SBC #$40           ; subtract 'a' ('a' - 1 and carry)
.C:c01e  B0 0E       BCS .cl_storecount ; and jump to store in repeat count
.C:c020   .checkupper:                  
.C:c020  C9 C1       CMP #$C1           ; compare with 'A'
.C:c022  90 08       BCC .zerocount     ; smaller -> no repetition
.C:c024  C9 DB       CMP #$DB           ; compare with 'Z'
.C:c026  B0 04       BCS .zerocount     ; larger -> no repetition
.C:c028  E9 C0       SBC #$C0           ; subtract 'A' ('A' - 1 and carry)
.C:c02a  B0 02       BCS .cl_storecount ; and jump to store in repeat count
.C:c02c   .zerocount:                   
.C:c02c  A9 00       LDA #$00           ; store 0 ...
.C:c02e   .cl_storecount:               
.C:c02e  99 6F C0    STA .repcount,Y    ; ... in repeat count
.C:c031  C5 FC       CMP $FC            ; compare with number of extra lines
.C:c033  30 02       BMI .cl_next       ; smaller -> go on with loop
.C:c035  85 FC       STA $FC            ; repeat count to number of extra lines
.C:c037   .cl_next:                     
.C:c037  C8          INY                ; next
.C:c038  C4 FB       CPY $FB            ; compare with string length
.C:c03a  D0 D3       BNE .copyloop      ; not yet reached? -> repeat
.C:c03c  A9 00       LDA #$00           ; terminate string in buffer
.C:c03e  99 6F C1    STA .outbuf,Y      ; with 0 byte
.C:c041   .outloop:                     
.C:c041  A0 C1       LDY #>.outbuf      ; output ...
.C:c043  A9 6F       LDA #<.outbuf      ; ...
.C:c045  20 1E AB    JSR $AB1E          ; ... string
.C:c048  A9 0D       LDA #$0D           ; and output ...
.C:c04a  20 D2 FF    JSR $FFD2          ; ... newline
.C:c04d  A6 FC       LDX $FC            ; load extra line count
.C:c04f  D0 01       BNE .ol_step       ; not zero -> go on
.C:c051  60          RTS                ; WE ARE DONE HERE ;)
.C:c052   .ol_step:                     
.C:c052  C6 FC       DEC $FC            ; decrease extra line count
.C:c054  A0 00       LDY #$00           ; initialize counter
.C:c056   .eraseloop:                   
.C:c056  B9 6F C1    LDA .outbuf,Y      ; load next character from buffer
.C:c059  F0 E6       BEQ .outloop       ; 0 byte? -> end of string, output
.C:c05b  BE 6F C0    LDX .repcount,Y    ; load repeat count for this characer
.C:c05e  D0 07       BNE .el_step       ; not 0 yet? -> jump to decrement
.C:c060  A9 20       LDA #$20           ; load code for space
.C:c062  99 6F C1    STA .outbuf,Y      ; store in current string position
.C:c065  D0 05       BNE .el_next       ; and jump to next loop iteration
.C:c067   .el_step:                     
.C:c067  CA          DEX                ; decrease repeat count ...
.C:c068  8A          TXA                ; ... and ...
.C:c069  99 6F C0    STA .repcount,Y    ; ... store back
.C:c06c   .el_next:                     
.C:c06c  C8          INY                ; increase counter ...
.C:c06d  D0 E7       BNE .eraseloop     ; and jump back to loop

.C:c06f   .repcount:
.C:c06f              .RES $100          ; 256 bytes for repeat count
.C:c16f   .outbuf:
.C:c16f              .RES $100          ; 256 bytes as buffer for output

Felix Palmen

Posted 2017-10-10T09:24:29.260

Reputation: 3 866

3c64 machine code. I'm impressed. – Dschoni – 2017-10-11T12:16:37.970

@Dschoni thanks, but it's still simple code (and it's fun, for me!) -- you should have a look at the demo scene for really impressive C64 works ;) – Felix Palmen – 2017-10-11T12:57:44.500

If we're gonna keep getting these, we might want to set up links to a JavaScript C64 emulator so people can see them run. – trlkly – 2017-10-12T03:50:23.160

1@trlkly I have such a link in my submission, click on "Online demo" ;) – Felix Palmen – 2017-10-12T05:10:59.837

14

05AB1E, 13 12 bytes

,εDlAsk×}ζ»,

Try it online!

Explanation

,             # print input
 ε      }     # apply to each char in input
  D           # duplicate
   l          # convert to lower case
    Ask       # get index of current char in the lower case alphabet
       ×      # repeat the char that many times
         ζ    # transpose with space as filler
          »,  # join on newlines and print

Emigna

Posted 2017-10-10T09:24:29.260

Reputation: 50 798

32Need to get index of char in lowercase alphabet? just Ask for it – Uriel – 2017-10-10T10:53:15.543

8

Pyth, 12 10 9 bytes

.tm+*xGr0

Test suite.

Explanation:

.tm+*xGr0dddQ   Expanded program with autofilled input variable
  m      dddQ    For each character d in the input:
       r0d     get its lowercase variant
     xG        and return its 0-based index in the alphabet 
                   (-1 if not found, for special chars)
                (empty string for A/a and special characters)
    *     d    that many of the corresponding character
   +       d   and one more for good measure (because x is 0-indexed)
.t             Transpose it and fill blanks with spaces

12 bytes:

j.t*VmxGr0d

(with trailing newline)

Test suite.

Explanation:

j.t*VmxGr0d
QQ              Expanded program with autofilled input variable
Q               print the input verbatim
     m    dQ    For each character d in the input:
        r0      get its lowercase variant
      xG        and return its 0-based index in the alphabet 
                    (-1 if not found, for special chars)
   *V       Q   multiply the corresponding characters in (the second autofilled input)
                 by their alphabet indices we just calculated
                 (empty string for A/a and special characters)
 .t             Transpose it and fill blanks with spaces
j               Join the result on newlines

Steven H.

Posted 2017-10-10T09:24:29.260

Reputation: 2 841

output can be a list of lists of characters, so long as it looks like it's raining characters - Hence you don't need j – Mr. Xcoder – 2017-10-10T11:25:52.247

Ah, you're right! I was keeping it because the 12-byte version was printing one line verbatim and I couldn't mix the formats like that, and I forgot I could remove that now that everything is in the transpose. Thanks! – Steven H. – 2017-10-10T11:27:35.177

8

Python 3, 83 bytes

f=lambda s,k=65:[*{*s}-{' '}]and[s]+f([[' ',c][91>ord(c.upper())>k]for c in s],k+1)

Try it online! Takes a list of characters. Returns a list of lists of characters.

Python 2, 90 bytes

f=lambda s,k=65:s.strip()and s+'\n'+f(''.join([' ',c][91>ord(c.upper())>k]for c in s),k+1)

Try it online! Takes a string. Returns a string.

Lynn

Posted 2017-10-10T09:24:29.260

Reputation: 55 648

7

Mathematica, 115 89 bytes

It takes as input a list of characters [{"a", "b", "c", "d", "a"}] and outputs a list of lists of characters

Thread[PadRight[Table[#,Max@Position[Alphabet[]/."a"->#,#|ToLowerCase@#]]&/@#]/. 0->" "]&

Try it online!

-26 bytes from Misha Lavrov

-5 bytes from user202729

but if you want to see the output as it is in the test case, try this (128 bytes) code
Try it online!

J42161217

Posted 2017-10-10T09:24:29.260

Reputation: 15 931

For future readers: The part "this answer only works on Mathematica..." is a bit misleading, the problem is Mathematica only support Unicode character in notebook (REPL) mode. In script mode, it only understand ASCII and special characters which have been converted to ASCII (e.g., (3 bytes) -> \[Infinity] (11 bytes)).

– user202729 – 2017-10-10T16:17:34.597

@user202729 ok,I'll edit and address people to read your comment.thanks – J42161217 – 2017-10-10T16:20:47.187

Golf suggestion for Mathematica (script mode): \[Infinity] (11 bytes) can be replaced by Infinity (8 bytes) or \:221e (6 bytes). The last one is the default representation of special characters without names. (although it is not the main part) – user202729 – 2017-10-10T16:21:33.160

We can avoid Infinity entirely. The problematic part is If[(d=Min@Position[Alphabet[],If[UpperCaseQ@#,ToLowerCase@#,#]])==∞,1,d] and we can change this to Max@Position[Alphabet[]/."a"->#,#|ToLowerCase@#]. (Searching in the list {#,b,c,d,...,y,z}, we're guaranteed to find # at least once.) – Misha Lavrov – 2017-10-10T23:53:37.560

@MishaLavrov very nice. fixed it! – J42161217 – 2017-10-11T00:36:29.457

6

Dyalog APL, 27 22 bytes

5 bytes saved thanks to @Adám

⍉∘↑⊢⍴¨⍨1⌈27|⎕A⍳819⌶⍨∘1

Try it online!

How?

⍴¨⍨ - shape each char to length of

    1⌈ - at least one or

    ⎕A⍳819⌶⍨∘1 - index of the char uppercased in alphabet

        27| - modulo 27

- flatten to a matrix

- and transpose

Uriel

Posted 2017-10-10T09:24:29.260

Reputation: 11 708

22 bytes: ⍉∘↑⊢⍴¨⍨1⌈27|⎕A⍳819⌶⍨∘1

– Adám – 2017-10-10T10:40:33.417

@Adám thanks! updated – Uriel – 2017-10-10T10:44:13.470

6

Charcoal, 12 bytes

θ↙↓E⮌θ×ι⌕α↥ι

Try it online!

-3 thanks to Neil.

Erik the Outgolfer

Posted 2017-10-10T09:24:29.260

Reputation: 38 134

5

Python 2, 111 106 99 98 97 87 93 bytes

s=input()
i=65
while s.strip():print s;s=''.join([' ',c][91>ord(c.upper())>i]for c in s);i+=1

Try it online!

TFeld

Posted 2017-10-10T09:24:29.260

Reputation: 19 246

whilecan be replaced with exec to save few bytes, ican start with 65 to save more one to reach 87 bytes – Rod – 2017-10-10T14:46:03.247

The OP says extraneous trailing newlines are not allowed, but your code prints several of them when the input doesn’t contain z or Z. – Lynn – 2017-10-10T23:03:51.483

@Lynn Fixed, I forgot to double-check the execchange... – TFeld – 2017-10-11T07:48:28.313

5

Python, 105 103 bytes

2 bytes saved thanks to @TFeld

lambda s:'\n'.join(''.join((' '+l)[i<1or 91>ord(l.upper())>i+64]for l in s)for i in range(26)).rstrip()

Try it online!

Uriel

Posted 2017-10-10T09:24:29.260

Reputation: 11 708

103 bytes – TFeld – 2017-10-10T10:47:24.683

@TFeld nice catch, thanks! – Uriel – 2017-10-10T10:50:05.203

5

C# (.NET Core), 162 bytes

s=>{string A="abcdefghijklmnopqrstuvwxyz",r=s;for(int i=-1;++i<s.Max(A.IndexOf);)r+='\n'+string.Concat(s.Select(c=>A.IndexOf(char.ToLower(c))>i?c:' '));return r;}

Try it online!

Nejosan

Posted 2017-10-10T09:24:29.260

Reputation: 151

2

Welcome to PPCG and nice first answer. You can shorten your code by using a few tricks. Here is a more golfed version of your code: Try it online!.

– Ian H. – 2017-10-10T17:01:55.217

Thanks for the comments, I assumed my code had to be executable by itself, so I built it upon that assumption! Thanks for the comment and the mentoring. – Nejosan – 2017-10-11T07:29:14.097

2

If you want to find some more tricks on how to golf in C#, take a look at this post, or take a look at existing C# answers. Happy golfing!

– Ian H. – 2017-10-11T07:31:46.363

Nice answer. Keep going :) – aloisdg moving to codidact.com – 2017-10-12T13:24:09.427

1

Hi, welcome to PPCG! Great first answer, especially now that it's golfed. +1 from me. Btw, it's currently 180 bytes, not 162. The required import using System.Linq; is unfortunately mandatory to add to the byte-count (or you should change Max to System.Linq.Max and Select to System.Linq.Max, which would be higher than simply using System.Linq; once.) Again welcome, and enjoy your stay. Oh, and I see @IanH. already mentioned Tips for Golfing in C#. Tips for golfing in <all languages> might also be interesting to read through.

– Kevin Cruijssen – 2017-10-17T13:43:47.770

5

Bash, 78, 76 71 bytes

for c in {B..a};{ [[ -n ${1// } ]]&&echo "$1";set "${1//[!$c-Z${c,}-z]/ }";}

Depending on collation (default LC_ALL) can save some more bytes

for c in {b..z} _;{ [[ -n ${1// } ]]&&echo "$1";set "${1//[!$c-Z]/ }";}

Try It Online

Nahuel Fouilleul

Posted 2017-10-10T09:24:29.260

Reputation: 5 582

4

Perl 5, 43 bytes

41 bytes code + 2 for -nl.

$c=A;print,s/$c|[^a-z]/ /gi,$c++while/\S/

Try it online!

Dom Hastings

Posted 2017-10-10T09:24:29.260

Reputation: 16 415

1loop for [_0-9] characters, maybe s/["-$c]/ /gi and -l not needed – Nahuel Fouilleul – 2017-10-10T10:37:35.010

@NahuelFouilleul Ahh, yes, I was a little too quick on the test cases. They should be added to the OP! :) Thanks! +4 :( – Dom Hastings – 2017-10-10T10:39:38.053

my suggestion doesn't work for any characters between 32 and 126 (non alpha greater than Z) – Nahuel Fouilleul – 2017-10-10T10:42:18.970

@NahuelFouilleul Can't find a shorter way that meets all requirements... I'll keep playing... – Dom Hastings – 2017-10-10T11:50:53.640

4

JavaScript (ES6), 87 78 76 bytes

-9 bytes thanks to @RickHitchcock.
-2 bytes thanks to @Neil.

f=(s,i=10)=>s.trim()&&s+`
`+f(s.replace(/./g,c=>parseInt(c,36)>i?c:" "),i+1)

Takes input as a string and returns with one trailing newline.

Test Cases

f=(s,i=10)=>s.trim()&&s+`
`+f(s.replace(/./g,c=>parseInt(c,36)>i?c:" "),i+1)

;["hello", "Programming Puzzles & Code Golf!", "~|[abc<0>cba]|~", "abcdefg0123456789"]
.forEach(s=>console.log(f(s)));
.as-console-wrapper{max-height:100%!important}

Justin Mariner

Posted 2017-10-10T09:24:29.260

Reputation: 4 746

76 bytes (one trailing new line): f=(s,i=10)=>s.trim()&&s+'newline'+f(s.replace(/./g,c=>parseInt(c,36)-i?c:" "),i+1) – Rick Hitchcock – 2017-10-10T14:26:02.247

@RickHitchcock That seems to infinite loop for an input string containing numbers: Try it online!. The idea of step-by-step changes to s is really nice, though.

– Justin Mariner – 2017-10-10T15:14:02.993

Ahh, good point. That can be fixed at the cost of 2 bytes: parseInt(c,36)-i>0 – Rick Hitchcock – 2017-10-10T15:16:25.737

1@RickHitchcock Can you not use parseInt(c,36)>i instead to save 2 bytes? – Neil – 2017-10-10T21:24:42.807

@Neil, duh. Justin: What Neil said. : ) – Rick Hitchcock – 2017-10-10T21:28:45.743

@RickHitchcock Updated, thanks guys! – Justin Mariner – 2017-10-11T00:12:25.157

4

R, 125 123 bytes

Outgolfed by plannapus

for(i in 1:max(p<-pmax(1,match(tolower(S<-el(strsplit(scan(,""),''))),letters),na.rm=T)))cat(ifelse(p<i," ",S),'\n',sep='')

Try it online!

Prints to stdout with a single trailing newline and reads from stdin().

Let's break it down:

S <- el(strsplit(scan,""))            # split the string to characters

m <- match(tolower(S),letters)        # 1-based index in letters (lowercase a-z)
p <- pmax(1,m,na.rm=T)                # parallel max, replaces NA (non-alphabet) or 0 with 1
for(i in 1:max(p)){                   # iterate
 cat(                                 # print
  ifelse(p<1,' ',S),                  # the corresponding letter in S if p>=1, space otherwise
  '\n',sep='')                        # newline, and no spaces between chars
}

Alternate answer, 106 bytes

function(S)for(i in 1:max(p<-pmax(1,match(tolower(S),letters),na.rm=T)))cat(ifelse(p<i,' ',S),'\n',sep='')

Try it online!

Function; prints to stdout but it's basically my response above ported to accept a list of characters rather than splitting the string, so I feel like it's "cheating." Plus, plannapus' approach with regex is quite neat!

Giuseppe

Posted 2017-10-10T09:24:29.260

Reputation: 21 077

4

Octave / MATLAB, 74 66 bytes

@(s)char(arrayfun(@(c){repmat(c,1,prod(find(upper(c)==65:90)))},s))'

Try it online!

Luis Mendo

Posted 2017-10-10T09:24:29.260

Reputation: 87 464

4

R, 118 114 bytes

function(a)while(grepl("[^ ]",a)){F=F+1;cat(a,"\n");for(j in c("[^a-zA-Z]",letters[F],LETTERS[F]))a=gsub(j," ",a)}

Thanks to @Giuseppe for those 4 bytes off

Try it online!

Short explanation:

function(a)
    while(grepl("[^ ]",a)){ #As long as the string is not just spaces.
        F=F+1 #Increment letter counter (F is FALSE, hence 0 by default)
        cat(a,"\n") #Print string
        for(j in c("[^a-zA-Z]",letters[F],LETTERS[F])) #Get rid of non-letters, and the current letter in lower and upper case
             a=gsub(j," ",a)
    }

plannapus

Posted 2017-10-10T09:24:29.260

Reputation: 8 610

ohhh, wait, potential issue: if a is all spaces, this won't print out anything...but you can change the while condition to grepl()|!F which is still a byte shorter than your original answer. – Giuseppe – 2017-10-11T13:43:24.033

3

PHP, 69 78 77 85+1 bytes

for($c=A;!$c[1]&&~trim($s=&$argn);$s=eregi_replace("[^".++$c."-Z]"," ",$s))echo"$s
";

requires PHP<7. Run as pipe with -nR or try it online.

Titus

Posted 2017-10-10T09:24:29.260

Reputation: 13 814

@Shaggy thanks for pointing out. It´s complete now. – Titus – 2017-10-10T21:48:57.663

+1 for $c=A;!$c[1];$c++. Nice one! Sadly extraneous trailing newlines are not allowed (single \n on final line is acceptable). So it fails for all strings not containing z. – Christoph – 2017-10-11T12:33:08.133

1@Christoph fixed – Titus – 2017-10-12T07:50:06.903

3

Japt, 15 14 11 10 bytes

First chance to play with Japt's new string padding methods so there might still be room for improvement.

y_ùZInZu c

Try it


Explanation

Implicit input of string U.

y_

Pass each column of U through a function, where Z is the current element (or letter, in this case).

InZu c

Convert Z to uppercase (u), get its charcode (c) and subtract (u) 64 (I).

ùZ

Pad the start of Z with itself until it reaches that length.


Alternative

y_ùZ9aZn36

Try it

Shaggy

Posted 2017-10-10T09:24:29.260

Reputation: 24 623

But couldn't you change ùZ to p to save a b...never mind, that's really clever... – ETHproductions – 2017-10-10T18:32:35.607

@ETHproductions: I made a few attempts with p (there might be 1 in the edit history) but ù won out in the end. – Shaggy – 2017-10-10T18:56:36.240

3

Haskell, 137 136 127 119 bytes

import Data.Char
p c=last$0:[k|k<-[0..25],k+65==ord(toUpper c)]
f s=[[last$c:[' '|i>p c]|c<-s]|i<-[0..maximum$map p s]]

Try it online!

Pretty long but I can't think of any way to shorten it further. I feel like there must be some way shorter than the if-then syntax but I don't see it.

EDIT: Thanks @streetster for helping me shave off one byte! I didn't use toUpper at first because of the cost of importing Data.Char but I forgot that it also provides ord which is much shorter than fromEnum

EDIT 2: Thanks to @Laikoni for shaving off another 6 bytes and identifying a bug which I have now fixed. I used 26 instead of 25 because I forgot that Haskell arrays are inclusive. Then I noticed I could use last instead of head which would allow me to use 0: rather than ++[0].

EDIT 3: Thanks again Laikoni for those 8 bytes. I had actually forgotten about that space. For some reason Sublime Text flips out without it and I forgot to remove it. I wasn't aware that lists of lines were allowed, I should've read the rules more carefully.

user1472751

Posted 2017-10-10T09:24:29.260

Reputation: 1 511

1Can you lowercase the input to avoid having to check A-Z as well as a-z and then mod'ing? – streetster – 2017-10-10T16:58:46.910

@streetster In haskell the toLower and toUpper functions require importing Data.Char which costs more chars than it saves. TIO

– user1472751 – 2017-10-10T17:06:42.663

1

You may want to have a look at the tips for golfing in Haskell. E.g. if i>p c then ' ' else c can be shortened to last$c:[' '|i>p c].

– Laikoni – 2017-10-11T10:30:51.003

Two more things: There is an unnecessary space in [k | and returning a list of lines is allowed, so you don't need the unlines. Finally, you might be interested in our Haskell chat room.

– Laikoni – 2017-10-11T13:58:41.793

3

Excel VBA, 110 Bytes

Anonymous VBE Immediate Window Function that takes input as expected type Variant\String from range [A1] and uses it to make it rain the alphabet in the VBE immediate window.

?[A1]:For i=1To 26:For j=1To[Len(A1)]:c=Mid([A1],j,1):d=Asc(UCase(c)):?IIf((d>64+i)*(d<91),c," ");:Next:?:Next

Sample I/O

[A1]="qwertyuiop[]ASDFGHJKL:'zxcvbnm,./"
?[A1]:For i=1To 26:For j=1To[Len(A1)]:c=Mid([A1],j,1):d=Asc(UCase(c)):?IIf((d>64+i)*(d<91),c," ");:Next:?:Next
qwertyuiop[]ASDFGHJKL:'zxcvbnm,./
qwertyuiop   SDFGHJKL  zxcvbnm   
qwertyuiop   SDFGHJKL  zxcv nm   
qwertyuiop   SDFGHJKL  zx v nm   
qwertyuiop   S FGHJKL  zx v nm   
qw rtyuiop   S FGHJKL  zx v nm   
qw rtyuiop   S  GHJKL  zx v nm   
qw rtyuiop   S   HJKL  zx v nm   
qw rtyuiop   S    JKL  zx v nm   
qw rtyu op   S    JKL  zx v nm   
qw rtyu op   S     KL  zx v nm   
qw rtyu op   S      L  zx v nm   
qw rtyu op   S         zx v nm   
qw rtyu op   S         zx v n    
qw rtyu op   S         zx v      
qw rtyu  p   S         zx v      
qw rtyu      S         zx v      
 w rtyu      S         zx v      
 w  tyu      S         zx v      
 w  tyu                zx v      
 w   yu                zx v      
 w   y                 zx v      
 w   y                 zx        
     y                 zx        
     y                 z         
                       z 

Taylor Scott

Posted 2017-10-10T09:24:29.260

Reputation: 6 709

Brutal!!! It seams you can also make ?A1:... – LS_ᴅᴇᴠ – 2017-10-17T14:12:40.240

@LS_ᴅᴇᴠ, unfortunately, as the [] indicates that the contained string should be evaluated to an object in/on/as a workbook, the [A1] call may not reduced to A1 - as this will not take and print the initial input from the range [A1]; rather this will just leave an empty line and all subsequent lines will be printed – Taylor Scott – 2017-10-17T19:55:14.937

Ups, you're right... Didn't notice this! – LS_ᴅᴇᴠ – 2017-10-18T12:53:10.240

3

Bash + sed, 37

sed -rne"/^ *$/q;p;s/\W|"{a..z}/\ /gi

Try it online.

Digital Trauma

Posted 2017-10-10T09:24:29.260

Reputation: 64 644

it looks like it's repeating characters in the alphabet 1-too-many times – streetster – 2017-10-12T10:50:22.120

@streetster I think its fixed now. – Digital Trauma – 2017-10-12T16:21:31.493

2

Ruby, 70 67 74 bytes

f=->s{puts s;(?b..?z).each{|c|s.gsub! /[^#{c}-z]/i,' ';puts s if s=~/\S/}}

Thanks to @TuukkaX for pointing out some parens could be dropped (-3 bytes)

Unfortunately I then had to add 7 bytes because original version failed to handle "z".

Calling it:

f.call('The quick brown fox jumps over the lazy dog!')
The quick brown fox jumps over the lazy dog!
The quick brown fox jumps over the l zy dog
The quick  rown fox jumps over the l zy dog
The qui k  rown fox jumps over the l zy dog
The qui k  rown fox jumps over the l zy  og
Th  qui k  rown fox jumps ov r th  l zy  og
Th  qui k  rown  ox jumps ov r th  l zy  og
Th  qui k  rown  ox jumps ov r th  l zy  o
T   qui k  rown  ox jumps ov r t   l zy  o
T   qu  k  rown  ox jumps ov r t   l zy  o
T   qu  k  rown  ox  umps ov r t   l zy  o
T   qu     rown  ox  umps ov r t   l zy  o
T   qu     rown  ox  umps ov r t     zy  o
T   qu     rown  ox  u ps ov r t     zy  o
T   qu     row   ox  u ps ov r t     zy  o
T   qu     r w    x  u ps  v r t     zy
T   qu     r w    x  u  s  v r t     zy
T    u     r w    x  u  s  v r t     zy
T    u       w    x  u  s  v   t     zy
T    u       w    x  u     v   t     zy
     u       w    x  u     v         zy
             w    x        v         zy
             w    x                  zy
                  x                  zy
                                     zy
                                     z

Neil Slater

Posted 2017-10-10T09:24:29.260

Reputation: 261

The parentheses at the lambda definition can be removed. +1. – Yytsi – 2017-10-10T19:13:35.457

2

C (gcc), 189 bytes

#define F for(q=c,p=s;*p;++p,++q)
char*p,*q,s[99],c[99];main(h){gets(s);F{*q=*p>64&&*p<91?*p-65:*p>96&&*p<123?*p-97:0;h=h>*q?h:*q;}for(puts(s);h--;){F{putchar(*q?--*q,*p:32);}putchar(10);}}

Try it online!

Felix Palmen

Posted 2017-10-10T09:24:29.260

Reputation: 3 866

Try puts(""); instead of putchar(10) – Conor O'Brien – 2017-10-12T03:13:55.553

178 bytes – ceilingcat – 2018-08-21T00:33:36.883

2

Haskell, 98 bytes

p c=sum[length[a..c]|a:e<-["B[","b{"],[c]<e]
f s=[[last$c:[' '|i>p c]|c<-s]|i<-[0..maximum$p<$>s]]

Try it online!

Example usage: f "[Abc]" yields a list of lines: ["[Abc]"," bc "," c "]. Use putStr.unlines.f $ "[Abc]" for pretty-printed output:

[Abc]
  bc
   c

Partly inspired by Now directly based on user1472751's Haskell answer.


Previous approach (100 99 bytes)

f s=[h|i<-[0..26],h<-[[(c:concat[c<$[a..c]|[a,e]<-["B[","b{"],c<e]++cycle" ")!!i|c<-s]],any(>' ')h]

Try it online!

Laikoni

Posted 2017-10-10T09:24:29.260

Reputation: 23 676

2

Oracle SQL, 186 Bytes

Assumes the string will be in a table t in column v:

WITH a(s,l)AS(SELECT v,64 FROM t UNION ALL SELECT REGEXP_REPLACE(s,'[^'||CHR(l+1)||'-Z]',' ',1,0,'i'),l+1 FROM a WHERE l<90)SELECT LISTAGG(RTRIM(s),CHR(10))WITHIN GROUP(ORDER BY l)FROM a

SQL Fiddle

Oracle 11g R2 Schema Setup:

CREATE TABLE t ( v ) AS
SELECT '~|[abc<0>cba]|~' FROM DUAL
/

Query 1:

WITH a(s,l)AS(
  SELECT v,64 FROM t
UNION ALL
  SELECT REGEXP_REPLACE(s,'[^'||CHR(l+1)||'-Z]',' ',1,0,'i'),l+1
  FROM a
  WHERE l<90
)
SELECT LISTAGG(RTRIM(s),CHR(10))WITHIN GROUP(ORDER BY l)
FROM a

Results:

|      LISTAGG(RTRIM(S),CHR(10))WITHINGROUP(ORDERBYL) |
|-----------------------------------------------------|
| ~|[abc<0>cba]|~                                     |
|    abc   cba                                        |
|     bc   cb                                         |
|      c   c                                          |

MT0

Posted 2017-10-10T09:24:29.260

Reputation: 3 373

2

PowerShell, 122 127 bytes

param($a)$a;(1..25|%{$i=$_;(-join([char[]]$a|%{(' ',$_)[$_-match'[a-z]'-and[math]::Max(0,($_-bor32)-96-$i)]})).TrimEnd()})-ne''

Try it online!

Short thanks to how PowerShell can dynamically cast between [char] and [int], but long because of removing extraneous whitespace and the calculation of whether to output a space or the character.

Bugfix thanks to beatcracker.

AdmBorkBork

Posted 2017-10-10T09:24:29.260

Reputation: 41 581

Unfortunately, this fails on ~|[abc<0>cba]|~ test case. Try this: param($a)$a;(1..25|%{$i=$_;(-join([char[]]$a|%{(' ',$_)[$_-match'[a-z]'-and[math]::Max(0,($_-bor32)-96-$i)]})).TrimEnd()})-ne'' – beatcracker – 2017-10-16T05:12:23.483

@beatcracker Good catch. That's a clever way of handling the comparison. Thanks! – AdmBorkBork – 2017-10-16T13:02:35.093

2

Jelly, 15 bytes

ØaḊiЀŒl‘⁸ẋ"z⁶Y

Try it online!

Leaky Nun

Posted 2017-10-10T09:24:29.260

Reputation: 45 011

2

Java 8, 151 147 144 143 139 bytes

s->{String x="\n"+s;for(int i=64,t;++i<91;)for(char c:x.toCharArray())s+=(t=c&~32)>64&t<91&t>i|c<11?c:" ";return s.replaceAll("\\s+$","");}

Explanation:

Try it here.

s->{                   // Method with String as both parameter and return-type
  String x="\n"+s;     //  Temp-String (equal to leading new-line + input)
  for(int i=64,        //  Index-integer `i` (starting at 64)
          t;           //  Temp-integer
      ++i<91;)         //  Loop (1) from 'A' (65) to 'Z' (90) (inclusive)
    for(char c:x.toCharArray())
                       //   Inner loop (2) over the character of the array
      s+=(t=c&~32)>64  //    If the current character as uppercase is larger than 'A'
         &t<91         //    and smaller or equal to 'Z'
         &t>i          //    and larger than the current index
         |c<11?        //    or the current character is a new-line
          c            //     Append the current character to `s`
         :             //    Else:
          " ";         //     Append a space to `s` instead
                       //   End of inner loop (2) (implicit / single-line body)
                       //  End of loop (1) (implicit / single-line body)
  return s             //  Return the result,
    .replaceAll("\\s+$",""); 
                       //   after we've removed all trailing spaces and new-lines
}                      // End of method

Kevin Cruijssen

Posted 2017-10-10T09:24:29.260

Reputation: 67 575

2

q, 42 37 bytes

{(+)max[m]$(m:1+mod[.Q.a?(_)x]26)#'x}

-5 thanks to streetster!


old solution+explanation:

{(+)max[m]$'(m:1+mod[.Q.a?lower x;26])#'x}


{                                        }  / lambda func
                     .Q.a?lower x           / get lowercase of input (ignores non-alpha values) and find (?) their index in "a...z" (.Q.a). non-alpha values return `26`
                 mod[.Q.a?lower x;26]       / get mod 26 of each index, this returns 0 where index is 26
            (m:1+mod[.Q.a?lower x;26])      / add 1 and assign to m
            (m:1+mod[.Q.a?lower x;26])#'x   / m and x conform, so we can take (#) m copies of each (') x at corresponding indices
    max[m]$'(m:1+mod[.Q.a?lower x;26])#'x   / get max of m, and pad each ($') of right-side list to that length
 (+)                                        / transpose the char matrix

scrawl

Posted 2017-10-10T09:24:29.260

Reputation: 1 079

1{(+)max[m]$(m:1+mod[.Q.a?(_)x]26)#'x} for 37, cant remember how I solved it when creating the question, probably very similar though! – streetster – 2019-09-04T13:37:58.103

@streetster, thanks! updated. didn't know about k's _ , i typed lower in the q interpreter and got k){$[~t&77h>t:abs@@x;.z.s'x;19<t;.z.s@. x;~t in 10 11h;'`type;_x]}. hence giving my answer in q haha – scrawl – 2019-09-04T13:58:19.447

1

SOGL V0.12, 12 11 bytes

ā,{Z⁴UW1Χ∙┼

Try it Here!

Explanation:

ā            push an empty array
 ,{          for each character in the input, pushing it
   Z           push the uppercase alphabet
    ⁴          push a duplicate of the character
     U         uppercase it
      W        find its index in that alphabet
       1Χ      get the maximum of that and 1
         ∙     repeat the character that many times
          ┼    append horizontally to that array

dzaima

Posted 2017-10-10T09:24:29.260

Reputation: 19 048

1

QBIC, 141 bytes

_L;|dim g(a)┘dim H(a)[a|_SA,b,1|┘H(b)=B┘o=asc(ucase$(B))-65~o<1or o>25|o=0]g(b)=o~g(b)>p|p=g(b)}?A[p|[a|~g(d)|g(d)=g(d)-1\H(d)=@ `]?H(d)';`]?

Wow, this has to be the longest entry I've made using QBIC...

Explanation

_L |                        Assign to num var 'a' the length of
  ;                         A$, which is read off the CMD line
dim g(a)                    Define 'g' as an array of 'a' slots. The lower-
                            case letter denotes it will store numbers.
                            g() will store if we still need to rain down the char at pos ()
                            of the input string.
┘                           Inject a linebreak in the compiled QBasic
dim H(a)                    Define H$ to be an array, also of length 'a', for strings
                            H$(x) will store what to rain down if g(x) > 0
[a|                         Run along the length of the input string
                            (QBasic: FOR b = 1 TO a STEP 1)
  _SA,b,1|┘                 Take a substring at index b on string A$, length 1 and 
                            store as B$; lift out each character one at a time
  H(b)=B┘                   Save the character in H$(x)
  o=asc(ucase$(B))-65       Take the ASCII codepoint of that substring, as uppercase 
                            minus 65. [A-Z] maps to 0-25. Save that number as 'o'
  ~o<1or o>25               IF o is not in range
  |o=0]                     THEN set o to zero (the same value as 'A/a')
  g(b)=o                    SET the number of rain-down copies to 'o'
  ~g(b)>p                   IF the number of raindowns exceeds the prvious max,
  |p=g(b)                   THEN store the new max into 'p'. This defines the rain-down depth
}                           END IF, NEXT
?A                          PRINT the original, \n
[p|                         FOR c = 1 TO max-depth 
  [a|                       FOR d = 1 to LEN(A$)
    ~g(d)                   IF the rain-down counter is positive
    |g(d)=g(d)-1            THEN decrement it by 1
    \H(d)=@ `               ELSE replace the char by a literal space in the char map
    ]                       END IF
    ?H(d)                   PRINT the character at the current pos int he char map
      ';`                   and suppress newlines
  ]                         NEXT character
?                           PRINT \n at the end of the line

steenbergh

Posted 2017-10-10T09:24:29.260

Reputation: 7 772

I was going to write a QBasic answer until I realized that 26 lines of output wouldn't fit on the screen without scrolling. Does QBIC have the same limitation? If so, what are your thoughts on how that affects the validity of this solution? – DLosc – 2017-11-25T01:50:30.567

@DLosc Same restriction applies to QBIC; it runs QBasic code after all. However, I feel the answer is valid - within the technical possibilities of the QBasic platform. Inputs that don't require displaying 26 lines (like ~|[abc<0>cba]|~) show that the functionality of this is according to spec. – steenbergh – 2017-11-25T09:34:44.667

1

Stacked, 47 bytes

[[:upcase ALPHA\index 0 max#+*]"!LF#`togrid tr]

Try it online! Takes input as list of characters, and returns a list of list of characters.

[[:upcase ALPHA\index 0 max#+*]"!LF#`togrid tr]          input: str
 [                            ]"!                        for(char of str)
   upcase ALPHA\index                                        get index of uppercase char
                                                             in uppercase alphabet
                      0 max                                  max(0, index)
  :                        #+*                               repeat char ^ times
                                 LF#`togrid                  convert to aligned char array
                                            tr               transpose     

Conor O'Brien

Posted 2017-10-10T09:24:29.260

Reputation: 36 228

1

Jq 1.5, 106 bytes

foreach("\n","^B-Zb-z",(range(24)|[.+66,.+98]|implode))as$x(.;gsub("[\($x)]";" ");.)|select(.!=length*" ")

Expanded

   foreach ("\n",                            # first pattern won't match anything
            "^B-Zb-z",                       # next a, A and punctuation
            (range(24)|[.+66,.+98]|implode)  # then Bb, Cc, ...
   ) as $x (
     .
   ; gsub("[\($x)]";" ")                     # apply each pattern to input
   ; .
   )
 | select(.!=length*" ")                     # eliminate blank lines

Try it online!

jq170727

Posted 2017-10-10T09:24:29.260

Reputation: 411

1

SNOBOL4 (CSNOBOL4), 181 bytes

	S =OUTPUT =INPUT
	U =&UCASE
	L =&LCASE
Z	S NOTANY(U L ' ') =' '	:S(Z)
N	U LEN(1) . X REM . U
	L LEN(1) . Y REM . L
R	S (X | Y) =' '	:S(R)
	S NOTANY(' ')	:F(END)
	OUTPUT =S	:(N)
END

Try it online!

	S =OUTPUT =INPUT		;* read input and print it
	U =&UCASE			;* alias for uppercase letters
	L =&LCASE			;* alias for lowercase letters
Z	S NOTANY(U L ' ') =' '	:S(Z)	;* replace non-alphabet, non-space characters with space
N	U LEN(1) . X REM . U		;* get the Next uppercase letter
	L LEN(1) . Y REM . L		;* get the Next lowercase letter
R	S (X | Y) =' '	:S(R)		;* replace all those with spaces
	S NOTANY(' ')	:F(END)		;* if S is all spaces, terminate the program
	OUTPUT =S	:(N)		;* else print S and goto N
END

Giuseppe

Posted 2017-10-10T09:24:29.260

Reputation: 21 077

1

Julia 1.0, 97 bytes

f(s,h=c->isletter(c)&&(c-'A')%32)=println.([s;[map(c->h(c)>i ? c : ' ',s) for i=0:maximum(h,s)]])

Try it online!

user3263164

Posted 2017-10-10T09:24:29.260

Reputation: 381

This only prints one b, 2 c etc, think you need a +1 or something somewhere :) – streetster – 2019-08-07T05:52:47.030

Should be fixed now – user3263164 – 2019-08-07T10:06:09.173

1

Stax, 12 bytes

î┌→♠─l∙╨"«Pò

Run and debug it

recursive

Posted 2017-10-10T09:24:29.260

Reputation: 8 616

1

Assembly (MIPS, SPIM), 319 bytes

.text
.globl main
main:
lw $4 4($5)
li $2 4
syscall
li $9 65
li $11 91
li $14 122
move $12 $4
li $2 11
syscall
g:
li $4 10
syscall
addi $9 1
bge $9 $11 n
addi $8 $12 -1
l:
addi $8 1
lb $4 ($8)
beqz $4 g
blt $4 $9 e
blt $4 $11 f
addi $13 $9 32
blt $4 $13 e
bgt $4 $14 e
f:
syscall
j l
e:
li $4 32
j f
n:
li $2 10
syscall

Try it online!

almost positive this can be golfed further, (might be able to use mod instead of a bunch of branches, idk) but i'm not complaining. Takes the string as a command line argument. most of the registers are used for magic ascii numbers, though $9 and $8 update - $9 is the current iteration, starting at 65 (a). $8 starts at the beginning of the string, then iterates over the string until reaching a null terminator. characters that are no longer valid are replaced with '32' or space. Prints a single trailing newline, on the last line.

The output is padded - that is, if the input string is 5 characters long, each printed row will also be 5 characters long, even if this means the last few bytes in a row are space characters. or more practically: "Faa"=>
"Faa" "F " "F " "F " "F " "F "
The instructions did not specify if we had to trim each row to the shortest possible or if this behavior was allowed. If the trimmed variant is desired I can mark this non-competing.

Andrew Baumher

Posted 2017-10-10T09:24:29.260

Reputation: 351

one cool aside: flipping the contents of e and f in the code will result in [stalagmites](https://tio.run/##RU9BbsIwELzvK7ZShOBQVDsGga89cOULceNYqdZxIaGUfN5du8G9WDOzO7Pj8av3MW4n@zPB1lEwhL7pB0iPBrpjpVCtq90GqMdKooLxMX40RJkfcb/LQAg8ij@kUEgJPnxbJpL9i1OIYnU6a7z5VrSmbXOgAONsAilzWORDjnrlC7ooTEzKWFeHDRh7mRNxYGhKgANswZzULT5Rp1Et/2d1WnQLUUy6ZzvesroU/ESCQT8/U4rHGM/X4K6N9/3g8HybZ7IjrvA9tBZPgbqXXw " - the code will print the line at the top, then grow from the bottom up, as if the text dripped down to the ground and built up over time. Did that by accident first and wondered what I did wrong.

– Andrew Baumher – 2019-09-05T15:08:26.900

Nice! No requirement to trim the strings so all good on that front :) – streetster – 2019-09-05T17:27:15.243