# Make a Word Icicle

Due to technical limitations of Stack Exchange, the title is rendered incorrectly. The correct title for this challenge is

Make a

Word Icicle!
Word Icicle
Word  cicle
ord  cicle
ord   icle
ord   i le
or    i le
or    i l
or      l
or
r


Today's challenge is to make icicles out of the input word. Given a string of entirely printable ASCII, and at least 2 non-space characters, perform the following steps:

1. Print the current state of the string.

2. Replace the lexically smallest character (other than spaces) with a space. If there is a tie, replace the leftmost character.

3. Repeat on consecutive lines until the string contains only 1 non-space character.

This creates the effect that the input string looks like it's melting...

I'm Melting!!!
I'm Melting !!
I'm Melting  !
I'm Melting
I m Melting
m Melting
m  elting
m   lting
m   ltin
m   lt n
m    t n
t n
t


### Rules

• After a couple iterations, your output will almost surely have trailing spaces on each line. If you choose to truncate these, that is allowed.

• You may have one trailing empty line, but not more.

• Remember that the input may contain several spaces, but these are all effectively skipped. For example, the input a a should give

a      a
a

• You may take input as a list of strings if you want. For output, you may return or print a list of strings, a single string with newlines, or char matrix/2D array. Generally, I prefer permissive IO formats, so other formats are most likely allowed as long as they are consistent and clearly correspond to the right output. If in doubt, feel free to ask. As usual, full programs or functions are allowed.

• Remember, this is a contest to make the shortest answer in any language! If you choose to answer in Java, try to make the shortest Java answer (in bytes) that you can.

### Test cases

Hello World! -->

Hello World!
Hello World
ello World
ello  orld
ello  orl
llo  orl
lo  orl
o  orl
o  or
or
r

AbCdEfGhIjKlMnOpQrStUvWxYz -->

AbCdEfGhIjKlMnOpQrStUvWxYz
bCdEfGhIjKlMnOpQrStUvWxYz
b dEfGhIjKlMnOpQrStUvWxYz
b d fGhIjKlMnOpQrStUvWxYz
b d f hIjKlMnOpQrStUvWxYz
b d f h jKlMnOpQrStUvWxYz
b d f h j lMnOpQrStUvWxYz
b d f h j l nOpQrStUvWxYz
b d f h j l n pQrStUvWxYz
b d f h j l n p rStUvWxYz
b d f h j l n p r tUvWxYz
b d f h j l n p r t vWxYz
b d f h j l n p r t v xYz
b d f h j l n p r t v x z
d f h j l n p r t v x z
f h j l n p r t v x z
h j l n p r t v x z
j l n p r t v x z
l n p r t v x z
n p r t v x z
p r t v x z
r t v x z
t v x z
v x z
x z
z

PPCG is da BEST -->

PPCG is da BEST
PPCG is da  EST
PP G is da  EST
PP G is da   ST
PP   is da   ST
P   is da   ST
is da   ST
is da    T
is da
is d
is
s

({({})({}[()])}{}) -->

({({})({}[()])}{})
{({})({}[()])}{})
{ {})({}[()])}{})
{ {}) {}[()])}{})
{ {}) {}[ )])}{})
{ {}  {}[ )])}{})
{ {}  {}[  ])}{})
{ {}  {}[  ] }{})
{ {}  {}[  ] }{}
{ {}  {}   ] }{}
{ {}  {}     }{}
{}  {}     }{}
}  {}     }{}
}   }     }{}
}   }     } }
}     } }
} }
}

• "lexically smallest" means by code point? – Giuseppe Apr 13 '18 at 18:03
• @Giuseppe Yes, the character with the smallest ASCII code point (other than space obviously) – James Apr 13 '18 at 18:04
• Reminds me of another challenge where we had to, I think, vertically repeat a character by its index in the alphabet. – Shaggy Apr 13 '18 at 18:23
• @Shaggy You're probably thinking of Make some Alphabet Rain. – Rainbolt Apr 13 '18 at 20:11
• That reference to MediaWiki though... – Erik the Outgolfer Apr 14 '18 at 12:56

# Python 2, 71 70 bytes

-1 byte thanks to ovs

x=input()
while x.strip():print x;r=x.replace;x=r(min(r(*' ~')),' ',1)


Try it online!

# Retina, 28 bytes

/\S/+¶<~(O.
0L$\S 0$$&¶  Try it online!Explanation: /\S/+  Repeat while the input value isn't blank. ¶<  Print the current value. ~(  Execute the rest of the script on the value. Then, execute the result of that script as a script on the value. O.  Sort the characters into order. 0L\S 0$&¶


Select the first nonblank character and output a Retina program that replaces the first literal ($\) occurrence of that character ($&) with a space (trailing space in original code).

# APL (Dyalog Unicode), 18 11 bytes

∪∘↓∘⍉⍋∘⍋⍴⌸⊢


Try it online!

uses ⎕io←1; returns an array of strings (vector of character vectors)

• Is the ∪ necessary? – user41805 Apr 13 '18 at 20:16
• @Cowsquack yes, otherwise the first few rows of the output could be identical – ngn Apr 13 '18 at 20:19
• @Cowsquack thanks, I didn't notice that – ngn Apr 13 '18 at 20:26
• fortunately, fixing this led to a shorter solution :) – ngn Apr 13 '18 at 21:43
• Nice one, really clever usage of ⍋∘⍋ :) – user41805 Apr 14 '18 at 7:14

# 05AB1E, 9 bytes

ðм{v=yð.;


Try it online!

### Explanation

ð      # Push space
м      # Implicit input. Remove spaces
{      # Sort. Gives string of sorted, non-space chars
v      # For each char in that string
=    #   Print latest string, without popping. The first time it prints the input
y    #   Push current char
ð    #   Push space
.;   #   Replace first occurrence of current char by space
# Implicitly end for-each loop

• {ðKv=yð.; was mine, nice one. – Magic Octopus Urn May 1 '18 at 17:28
• @MagicOctopusUrn Heh, pretty similar – Luis Mendo May 1 '18 at 17:52
• @MagicOctopusUrn Actually, it would still be the same 9 bytes in the latest 05AB1E version.. : replaces all characters instead of .; which replaces the first (i.e. see what your 7-byter does with the ! in the test case). Also, the challenge explicitly states excluding spaces, so your 7-byter wouldn't work for input with multiple spaces. PS: Nice answer, Luis! +1 from me. :) – Kevin Cruijssen Oct 22 '18 at 14:50
• @KevinCruijssen leave it to me to forget why I had to use .; in the first place. I literally remember struggling with that on May 1st earlier this year now that you mention it. – Magic Octopus Urn Oct 22 '18 at 14:57
• @LuisMendo Well, none of the commands you've used in this answer have changed in the Elixir rewrite of 05AB1E. :) – Kevin Cruijssen Oct 22 '18 at 15:17

# Pyth, 1714 13 bytes

V-SQdQ=XQxQNd


Try it here

V-SQdQ=XQxQNd
V-SQd              For each non-space character in the sorted input (Q)...
Q             ... print the current value of Q...
= Q          ... and set Q to itself...
xQN       ... with the first instance of the character...
X    d      ... replaced by a space.


# sed-rn, 142 143 bytes

:a
p
s/$/ ABCDEFGHIJKLMNOPQRSTUVWXYZ/ s \w+$	!"#$%\&'()*+,-./0123456789:;<=>?@&[\\]^_\L&{|}~ :b /(.).* \1/!s/ ./ / tb s/(.)(.*) \1.*/ \2/ ta  Try it online! (note: there are tabs in the program) Since sed has no concept of lexicographical order, I had to hardcode the set of printable ASCII characters in and it takes up more than half the bytecount. Using sed 4.2.2 will reduce bytecount by 2, since that allows for unnamed labels, Try it online! -r enables extended regular expressions (golfier) -n disables implicit printing of the pattern space at the end of the program The pattern space starts with the input :a label a, this is the main program loop p print the pattern space (fancy name for the buffer) now we append the set of printable ASCII characters (excluding the space) s/$/ ABCDEFGHIJKLMNOPQRSTUVWXYZ/ append a tab, acting as the 1-byte delimiter, followed by the uppercase alphabet

s<tab> substitute (sed can take any character as the delimiter, in this case the tab is used to save a byte from escaping the /)

• \w+$ the uppercase alphabet we just appended • <tab> with • !"#$%\&'()*+,-./0123456789:;<=>?@&[\\]^_\\L&{|}~<tab> the rest of the characters, note that \L& is the lowercase version of the uppercase alphabet

:b label b, remove characters from the beginning set that are not present in input

/(.).* \1/! if the first character from the ASCII set is not in the input

• s/ ./ / remove it

tb repeat b until the substitution fails

s/(.)(.*) \1.*/ \2/ replace the first character in the ASCII set present in the input with a space, and remove the ASCII set

ta recurse

• Non-greedy matching would have been really helpful here, but I was able to come up with something that fooled sed enough to save at least 4 bytes: Try it online! – Neil Apr 14 '18 at 0:35
• (Cows quack pointed out that I was only partly able to fool sed, as I remove identical characters in the wrong order.) – Neil Apr 14 '18 at 10:33

# Ruby, 605855 47 bytes

->a{[-a]+a.scan(/\S/).sort.map{|x|a[x]=' ';-a}}


Try it online!

• You can swap in a-b=[' '] and a-b for a quick -2 bytes – benj2240 Apr 13 '18 at 19:09
• Yeah, thanks for that, but now I've changed the approach a bit, so it is no longer used. – Kirill L. Apr 13 '18 at 21:04
• I like the new approach! – benj2240 Apr 13 '18 at 21:41

# R, 140 100 bytes

-40 bytes Thanks to Giuseppe !

function(x)for(i in any((z=utf8ToInt(x))<33):max(y<-rank(z,,"f"))){z[y==i]=32
cat(intToUtf8(z),"
")}


Try it online!

A solution using outer and Giuseppe's magic to work properly is longer at 104 bytes. Inspired by this answer.

function(x,z=utf8ToInt(x)-32)apply(t(outer(rank(z,,"f"),(2-(min(z)>0)):nchar(x),">=")*z+32),1,intToUtf8)


Try it online!

• 109 bytes taking input as a vector of chars – Giuseppe May 1 '18 at 22:07
• 100 bytes taking input as a string! – Giuseppe May 1 '18 at 22:08
• Still, a very nice answer; mine had ballooned to over 200 bytes since I didn't remember about rank! – Giuseppe May 1 '18 at 22:08
• @Giuseppe Tell me about it - I first tried "order" for a result that was melting but not in the correct order! – JayCe May 1 '18 at 22:40
• @Giuseppe and my attempt at using outer inspired by your post only managed to remove all spaces. TIO I'd love to see a working outer approach posted as a separate answer. Still working on it but it might not be that elegant. – JayCe May 1 '18 at 23:52

# Python 3, 71 bytes

f=lambda a:[*a.strip()]and[a]+f(a.replace(min(a.replace(*" ~"))," ",1))


Try it online!

-4 bytes thanks to ovs

• Save 2 bytes using *bool({*a}-{" "}) instead of if{*a}-{" "}else[a] – RootTwo Apr 13 '18 at 20:54
• @RootTwo wouldn't this result in a RecursionError? – ovs Apr 13 '18 at 21:11
• @RootTwo if/else shortcuts but *bool doesn't, so yes, recursionerror like ovs said – HyperNeutrino Apr 14 '18 at 2:44
• Of course you are correct. Because of a bug, my function recursed by calling your function so it appeared to work. – RootTwo Apr 14 '18 at 4:41

# Python 2, 706966 64 bytes

def f(s):print s;S=set(s)-{' '};S and f(s.replace(min(S),' ',1))


Try it online!

Thx for 2 bytes from ovs via using S and f() instead of if S:f()

• You're missing the ...If there is a tie, replace the leftmost character... rule, you can fix that with replace(min(...),' ',1) – Rod Apr 13 '18 at 19:55
• @Rod: Ah! Got it... – Chas Brown Apr 13 '18 at 19:58

$Combine the two links to the left into a chain. Ụ Grade up; sort the indices of s by their corresponding values. Let's call the result J. Grade up again, sorting the indices of J by the corr. values in J. This enumerates the positions of s as described before. ẋ" Repeat each character of s that many times. z⁶ Zip the resulting 2D array, filling missing characters with spaces. Q Unique; deduplicate the array of rows.  # Perl 5-n, 37 34 bytes Dropped three bytes with help from @TonHospel say&&s/\Q$a/ / while($a)=sort/\S/g  Try it online! • Ah, very nice, much nicer approach! I think you need the \Q though for the last test case.... I missed that the first times too! – Dom Hastings Apr 14 '18 at 5:25 • You're right. Added it. – Xcali Apr 14 '18 at 5:47 • Shorter: say&&s/\Q$a/ / while($a)=sort/\S/g. Also properly handles 0 – Ton Hospel Apr 15 '18 at 16:28 # JavaScript, 6766 65 bytes Because I haven't golfed drunk in a while! s=>[...t=s].sort().map(x=>x> ?t+=${s=s.replace(x, )}:0)&&t


Try it online

Thanks to DanielIndie for pointing out 4 redundant bytes that beer included!

• why do you specify y in the map? :P it can be made 67 – DanielIndie Apr 14 '18 at 8:17
• @DanielIndie, because Beer! :D Thanks for pointing it out. – Shaggy Apr 14 '18 at 8:37
• yes, i thought that would be the case :P – DanielIndie Apr 14 '18 at 8:45

# K (ngn/k), 26 24 bytes

{?(,x),x{x[y]:" ";x}\<x}


Try it online!

• Beautiful! My K attempt came in at 41: {.[x;(-1+#x)&x?_ci&/_ic x _dv" ";:;" "]} I'm wasting bytes converting to ints and back and making sure it doesn't go out of bounds. – uryga May 2 '18 at 1:34
• @uryga Thanks. If I had implemented projections properly, {@[x;y;:;" "]} could have been @[;;:;" "]. Which version of k do you use? I'm not familiar with these: _ci _ic _dv. – ngn May 2 '18 at 12:16
• I think it's 2.8-ish? I'm using the Kona interpreter which provides operators as builtins: char-of-int, int-of-char, delete-value. – uryga May 2 '18 at 12:19

# C# (Visual C# Interactive Compiler), 129 bytes

var s=ReadLine();while(s.Any(c=>c!=32)){WriteLine(s);var i=s.IndexOf(s.Min(c=>c==32?(char)999:c));s=s.Remove(i,1).Insert(i," ");}


Try it online!

• c!=32 can be c>32; c==32 can be c<33; and (char)999 can be '¡' (or any other character above the printable ASCII unicode range). – Kevin Cruijssen Apr 16 '18 at 7:00
• Oh, and you can save two more bytes changing the while to for and placing the var s=ReadLine() and s=s.Remove(i,1).Insert(i," ") inside it (so the two semi-colons are no longer needed). – Kevin Cruijssen Apr 16 '18 at 7:07

## Perl 5 with -nlF/\s|/, 39 bytes

@F=sort@F;say,s~\Q$F[$F++]~ ~ while/\S/


This might be pushing the boundaries of Perl's flags not being counted, if so I'll revert to the previous answer.

Try it online!

12 bytes saved thanks to Laikoni

f s|(a,_:b)<-span(/=minimum(id=<<words s))s=putStrLn s>>f(a++' ':b)


Try it online!

This one terminates in an error

g(a,_:b)=a++' ':b
mapM_ putStrLn.(iterate$g.(span=<<(/=).minimum.concat.words))  Try it online! This one terminates in an error # Haskell, 86 bytes u=concat.words g(a,_:b)=a++' ':b (take.length.u)<*>(iterate$g.(span=<<(/=).minimum.u))


Try it online!

u=concat.words
f x|(a,_:b)<-span(/=minimum(u x))x=a++' ':b
(take.length.u)<*>(iterate f)


Try it online!

• 67 bytes: f s|(a,_:b)<-span(/=minimum(id=<<words s))s=putStrLn s>>f(a++' ':b) Try it online! – Laikoni Apr 13 '18 at 22:15
• @Laikoni Thanks! I was just on the verge of something like that and I fell asleep. However I don't think I would have come up with id=<< that's pretty clever – Wheat Wizard Apr 13 '18 at 23:32

# JavaScript (Node.js), 80 65 bytes

x=>[...x].sort().map(c=>x=x.replace(c,' ',c>' '&&console.log(x)))


Try it online!

Didn't know replace take string as string, not regexp

# K4, 2820 18 bytes

Solution:

?x{x[y]:" ";x}\<x:


Example:

q)k)?x{x[y]:" ";x}\<x:"PPCG is da BEST"
"PPCG is da BEST"
"PPCG is da  EST"
"PP G is da  EST"
"PP G is da   ST"
"PP   is da   ST"
" P   is da   ST"
"     is da   ST"
"     is da    T"
"     is da     "
"     is d      "
"     is        "
"      s        "
"               "


Explanation:

It's the same thing as ngn is doing. Find indices that would result in an ascending list, overwrite them one-by-one with " ", then take the distinct to remove any duplicate lines:

?x{x[y]:" ";x}\<x: / the solution
x: / save input as x
<   / return indices that would result in ascending sort
x{        ; }\    / two-line lambda with scan
" "        / whitespace
:           / assignment
x[y]            / x at index y
x      / return x
?                  / distinct


# gcc 32-bit, 66 65 bytes

char*p,i;f(a){for(i=32;i++;)for(p=a;*p;)*p==i?puts(a),*p=32:++p;}
main(){char s[]="3.1415926";f(s);}


Thanks for Jonathan Frech for -1 byte

• *p==i?...:0; could probably be *p-i?0:...;. – Jonathan Frech Apr 13 '18 at 20:06
• @JonathanFrech No, it's 1 byte longer (though *p-1||(...) is same length) – l4m2 Apr 14 '18 at 7:45
• Sorry, did not recognize the importance to keep the comma expression together. However, this might be 65 bytes. I also do not know how f(a) compiles, as a should be of type char*, but I assume that has something to do with your 32-bit gcc usage. – Jonathan Frech Apr 14 '18 at 17:20
• @JonathanFrech I think char*p,i;f(long long a){for(i=31;++i;)for(p=a;*p;)*p==i?puts(a),*p=32:++p;} on tio(64bit) may explain how f(a) work – l4m2 Apr 14 '18 at 18:11
• I am sorry, though I asked the OP about the challenge specifications and they said the input string may start with a space. Therefore my proposed solution is invalid (as such an input results in an infinite loop) and you should most likely revert back to your original solution. – Jonathan Frech Apr 14 '18 at 20:27

# MATLAB, 74 bytes

This uses the 2-output form of the max() function to retrieve the smallest character and its index, having transformed the string to zero values in the spaces and 256-the character value for the printable characters.

s=input('s');x=1;while(x);disp(s);[x,y]=max((256-s).*(s~=' '));s(y)=' ';end

• Welcome to PPCG! Nice work! – AJFaraday Apr 16 '18 at 12:58

# Common Lisp, 240228 224 bytes

(setf s(read))(defun f(x)(setf y(char-code(elt s x)))(if(= y 32)1e9 y))(loop for _ across s do(print s)do(setf s(replace s" ":start1(position(code-char(reduce #'min (loop for i from 0 below(length s)collect i):key #'f))s))))


Try it online!

This is my first time posting.
I'm in the process of learning lisp so I'm sure someone can think of something shorter than this.

• Welcome to the site! Good to see some common lisp! – Wheat Wizard Apr 14 '18 at 21:24

# APL (Dyalog Unicode), 39 bytesSBCS

{⎕←⍵⋄×≢⍵∩g←' '~⍨⎕UCS⍳256:∇' '@(⊃g⍋⍵)⊢⍵}


Try it online!

Dfn.

### How?

{⎕←⍵⋄×≢⍵∩g←' '~⍨⎕UCS⍳256:∇' '@(⊃g⍋⍵)⊢⍵} ⍝ Main function, argument ⍵
⎕←⍵⋄                                    ⍝ Print ⍵
g←' '~⍨⎕UCS⍳256                 ⍝ Assign to g every Unicode character except space
×≢⍵∩                :               ⍝ If ⍵∩g is not empty
∇              ⍝ Recursively call the function with argument:
' '@       ⍵  ⍝ Space at
(⊃g⍋⍵)    ⍝ The first (⊃) element in ⍵ graded up (⍋) with g
⍝ to its left argument, in this case g.


# V, 27 bytes

>>ò2Ùúú^lDhrfDj|@"r kdòdj<H


Try it online!

Hexdump:

00000000: 3e3e f232 d9fa fa5e 6c44 6872 6644 6a7c  >>.2...^lDhrfDj|
00000010: 4022 7220 6b64 f264 6a3c 48              @"r kd.dj<H


# PowerShell, 103 99 bytes

param($a)2..$a.length|%{($x=$a);[regex]$p=""+([char[]]$a-ne' '|sort)[0];$a=($p.replace($x," ", 1))}  Try it online! Takes input as a string into $a. We then loop from 2 to $a.length (i.e., the appropriate number of vertical times necessary to remove all but one character). Each iteration, we output the current string and conveniently saved into $x at the same time. We then construct a new [regex] object, $pattern consisting of the remaining characters in $a that are -notequal to space, sorted, then the 0th one thereof.

We then set $a equal to a new string of the regex object with the .Replace method to replace in the string $x, the $pattern, with a space " ", but only the 1st match. Yeah, this syntax is weird. The strings are left on the pipeline and implicit Write-Output gives us a newline between them for free, plus one trailing newline. # Java (JDK 10), 140 bytes s->{for(int m=1,i;m>0;s=s.substring(0,i=s.indexOf(m=s.chars().filter(c->c>32).min().orElse(0)))+" "+s.substring(i+1))System.out.println(s);}  Try it online! Technically there's a blank line, but it's not empty. # Stax, 9 bytes ü¡%/"=πbΓ  Run and debug it This is the same algorithm as Luis' 05AB1E solution # MATL, 17 16 bytes tSXz"tOy@=f1)(]x  ### Explanation t % Implicit input. Duplicate S % Sort Xz % Remove spaces " % For each char in that string t % Duplicate last result. This is the most recent string obtained % from replacing chars by spaces in the input O % Push 0 y % Duplicate from below @ % Push current char = % Equals? (element-wise) Gives 1 for occurrences of current char % in the most recent string, 0 otherwise f % Indices of nonzeros 1) % Get the first entry ( % Write 0 at that position. Char 0 will be displayed as space ] % End x % Delete last result, which consists only of space / char zero  # Excel VBA, 167 bytes An anonymous VBE immediate window function that takes input from range [A1] and outputs to the VBE immediate window. s="Code(Mid(A$1,Row(),1))":[B1].Resize([Len(A1)])="=If("&s &"=32,1E3,"&s &")":For i=1To[Len(A1)-CountIf(B:B,1E3)]:?[A1]:[A1]=[Substitute(A1,Char(Min(B:B))," ",1)]:Next


# Ungolfed and Commented

''  run as call icicle("Test") or icicle"I am the WALRUS
Sub icicle(Optional str As String)
If Not IsMissing(str) Then [A1] = str   ''  pipe input
[B:B].Clear                             ''  reset between runs
[B1].Resize([Len(A1)]) = "=If(Code(Mid(A$1,Row(),1))=32,1E3,Code(Mid(A$1,Row(),1)))"  ''  get char number for every char in input
For i = 1 To [Len(A1)-CountIf(B:B,1E3)] ''  iterate across from 1 to length of input - number of spaces
Debug.Print [A1]                    ''  output a single line
[A1]=[Substitute(A1,Char(Min(B:B))," ",1)]  ''  replace minimum char with space
Next
End Sub


# Japt, 32 18 bytes

Saved 14 bytes thanks to Shaggy!

rS ¬£=hSUbZn gYÃiN


Try it online!

• Save a byte by returning an array of lines: ethproductions.github.io/japt/… – Shaggy Apr 13 '18 at 20:49
• 22 bytes. Will try a port of my JS solution soon, see how that works out. – Shaggy Apr 14 '18 at 8:46
• Got it down to 18 bytes. – Shaggy Apr 14 '18 at 9:44