Exploding Cats!

17

Challenge

You will be making a program/function that takes a string input of length n, and:

  1. Puts the kth char at the center of the space, where k = (n+1)/2. This will be the location of your ground zero.
  2. Puts the rest of the non-whitespace chars randomly arranged around ground zero. The Pythagorean distance from the char must not exceed n.
  3. Outputs the result.

If you need clarifications, see the example below.


Rules

  • Standard loopholes apply!
  • I/O must be in the form of a string.
  • Input will always be odd to ensure that you have a central char to put at ground zero.
  • Every valid output should occur with a non-zero probability.

This is ; shortest code in bytes wins!


Example

Input: qwert

The boundaries of the explosion emanating from ground zero (x's mark valid places for the rest of the chars to be):

     x
  xxxxxxx
 xxxxxxxxx
 xxxxxxxxx
 xxxxxxxxx
xxxxxexxxxx
 xxxxxxxxx
 xxxxxxxxx
 xxxxxxxxx
  xxxxxxx
     x

Example output:

       t
     r

q    e


      w

Mama Fun Roll

Posted 2016-01-23T23:55:46.853

Reputation: 7 234

Selecting position randomly, one char could go in the same position of an other and overwrite it. Is this alllowed? (My suggestion: no) – edc65 – 2016-01-24T09:38:50.593

You are right: No. – Mama Fun Roll – 2016-01-24T16:52:07.050

1What on earth does this have to do with blowing me up? (I genuinely don't understand the relevance of the title...) – cat – 2016-01-25T00:08:12.493

1@cat This is a modification of a cat program, except that you explode the input. – Mama Fun Roll – 2016-01-25T00:55:00.063

3A little bit related – Mego – 2016-01-25T19:31:12.037

Answers

1

APL (Dyalog Classic), 68 66 65 63 62 bytes

{⍵@(n⊣¨¨@(⊢≡¨⌽)i[n?≢i←⍸(××n≥*∘.5)+.ר⍨n-⍳s])⊢''⍴⍨s←2⍴1+2×n←≢⍵}

Try it online!

{ } anonymous function with argument

n←≢⍵ variable n is the length

s←2⍴1+2×n variable s is the shape of the result: 2n+1 by 2n+1

''⍴⍨s create a square of spaces with that shape

A@I⊢B puts elements A at (pairs of) indices I in matrix B

+.ר⍨n-⍳s squared distances from the centre of the matrix

(××n≥*∘.5) boolean matrix indicating where those distances are non-zero and ≤n

coordinate pairs for the 1s in the boolean matrix

i[n?≢i← ... ] choose n of them randomly (no duplicates)

n⊣¨¨@(⊢≡¨⌽) change the central one to n n

⍵@( ... )⊢ ... put the chars from the argument at the given indices in the matrix of spaces

ngn

Posted 2016-01-23T23:55:46.853

Reputation: 11 449

3

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>

edc65

Posted 2016-01-23T23:55:46.853

Reputation: 31 086

You have an extra space before g.map(r=>r.join``)... – usandfriends – 2016-01-24T13:28:52.043

@usandfriends thx I don't know how I missed it – edc65 – 2016-01-24T13:36:57.640

Use new Date()%h-l instead of Math.random()*h-l|0. It saves bytes. – ericw31415 – 2016-05-06T23:59:33.977

1@ericw31415 use just 0. It saves bytes too. But both won't work – edc65 – 2016-05-07T11:33:39.743

2

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 lxl 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.

Shelvacu

Posted 2016-01-23T23:55:46.853

Reputation: 610

o*o is shorter then **0.5 – edc65 – 2016-01-25T13:30:56.613

1

Python 3, 286 bytes

import random as r
i=input()
l=len(i)
a=range(-l,l+1)
g=[(y,x)for y in a for x in a]
p=[(y,x)for y,x in g if abs(x+y*1j)<=l and x|y]
m=i[l//2]
d=[*i.replace(m,"",1).center(len(p))]
r.shuffle(d)
o=""
for c in g:
	o+=m if c==(0,0)else d.pop()if c in p else" "
	if c[1]==l:o+="\n"
print(o)

Trying it online is an option.

Whoops, stumbled onto this due to recent activity, didn't notice it was over two years old somehow until I spent a good while on this. Well, two answers is kind of sad, so this is probably a good idea to post anyway. I'm sure there are dozens of ways to improve on this—didn't notice until just now that input is always odd, which would've been helpful to know.

Explanation

i=input() is input, of course, l=len(i) is saving the length of the string because it's used quite a few times.

a=range(-l,l+1) — a quick tool to create an iterator ranging the available distances away from the origin both ways along one dimension.

g=[(y,x)for y in a for x in a] builds a list of tuple coordinates that makes up the entire final grid.

p=[(y,x)for y,x in g if abs(x+y*1j)<=l and x|y] creates a subset of the list containing only the coordinates that non-center letters can possibly land on.

m=i[l//2] establishes the center character.

d=[*i.replace(m,"",1).center(len(p))] — the center character's taken out, leaving us with the other debris. The center() function is very nice here, because it allows us to pad out the line (with by default a space) until it's a certain number of characters long. Here, that's the number of spaces the letters can land on, thus mirroring the distribution we need.

r.shuffle(d) naturally shuffles said distribution to be actually... distributed.

The loop, for c in g: o+=m if c==(0,0)else d.pop()if c in p else" ", looks over the entire square of feasible tiles, regardless of anything possibly landing on it or not, and as necessary, adds a character to our output string o. Characters are popped out of our sample of debris so that they only appear once.

if c[1]==l:o+="\n" — Adds line breaks as well. Returns.

Reecer6

Posted 2016-01-23T23:55:46.853

Reputation: 181