Exploding Cats!
JavaScript (ES6), 211 216 220
Edit 1 byte saved thx @usandfriends
s=>[...s].map((c,i)=>{for(R=_=>Math.random()*h-l|0;x=R(y=R()),!(i-(l/2|0)?x|y&&x*x+y*y<=l*l&g[y+=l][x+=l]<'!':x=y=l););z=[...g[y]],z[x]=c,g[y]=z.join``},l=s.length,g=Array(h=l-~l).fill(' '.repeat(h)))&&g.join`
`
Test
f=s=>[...s].map((c,i)=>{for(R=_=>Math.random()*h-l|0;x=R(y=R()),!(i-(l/2|0)?x|y&&x*x+y*y<=l*l&g[y+=l][x+=l]<'!':x=y=l););z=[...g[y]],z[x]=c,g[y]=z.join``},l=s.length,g=Array(h=l-~l).fill(' '.repeat(h)))&&g.join`
`
// Less golfed
U=s=>(
l=s.length,
h=l-~l, // l+l+1
g=Array(h).fill(' '.repeat(h)),
[...s].map((c,i)=>{
for(R=_=>Math.random()*h-l|0;
x=R(y=R()), // set x,y to a random value in range -l ... l
!(i - (l/2|0) // check if at mid point of input string
? x|y && // if not, check x and y must not be both 0
x*x + y*y <= l*l & // then check position inside the circle of ray L
g[y+=l][x+=l] < '!' // then add offset L and check if position is not already used
: x=y=l // if at midpoint in input string, x and y have fixed value L
);
); // loop until valid position found
z = [...g[y]]; // modify string at current position: convert to array ...
z[x] = c; // ... set element ...
g[y] = z.join`` // ... back to string
}),
g.join`\n`
)
setInterval(_=>O.textContent=(f(I.value)),1000)
Word <input id=I value='qwert'><pre id=O></pre>
Ruby, 211 207 203 196 characters
Thanks to edc65 for 4 characters
->(x){x=x.chars
o,b,c=x.size
l=o*2+1
a=Array.new(l){Array.new l,' '}
a[o][o]=x.delete_at o/2
a[b][c]=x.pop if a[b=rand(l)][c=rand(l)]==' '&&(b-o)**2+(c-o)**2<=o*o while x[0]
a.map(&:join).join $/}
Explanation:
->(x){...}
define an anonymous function that takes in an argument x
x=x.chars
transform x
from a string into an array of one-character strings
o,b,c=x.size
store the length of the input in o
for later use. b
and c
simply need to be initialized to something, so save 2 characters by attaching to a previous assignment.
l=o*2+1
this is the length/width of the field where all characters could possibly go, also the diameter of the explosion circle.
Array.new(l){Array.new l,' '}
make an l
xl
sized 2D array of space characters.
a[o][o]=x.delete_at o/2
sets the center of the array to the center of the values of x
(the input), while deleting that value from x
... while x[0]
run the block (in this case, the code before while
because it is inline) over and over until x
is empty. In ruby, accessing an index that does not exist returns nil
, which is a falsey value.
a[b=rand(l)][c=rand(l)]==' '
Assign b
and c
to random values where 0 <= n < l
. Then check if the spot at b
,c
is empty (aka is set to space character)
(b-o)**2+(c-o)**2<=o*o
Pythagorean distance check. o
is the length of the input. **
is ruby's exponentiation operator, and val<=o*o
is shorter than val**0.5<=o
.
a[b][c]=x.pop
delete the last value from x
. Set the position a
,b
to that value in array a
a[b][c]=x.pop if a[b=rand(l)][c=rand(l)]==' '&&(b-o)**2+(c-o)**2<=o*o while x[0]
Set a random position to the last value if that position is free and is within the explosion radius; keep doing this until we run out of characters to place.
$/
is set to the operating system's newline. It's also shorter than "\n"
a.map(&:join).join $/
Map all the arrays in a
to a single-string version of themselves (eg ['a','b','c']
-> 'abc'
). Take that new array and join it with newlines. Implicit return.