Calculate gravity on a 1D field

6

1

Given a string or list, calculate the effects of gravity on that string/list.

The string will be made of 5 characters:

  • N has a weight of 2
  • L has a weight of 1
  • S has a weight of -2
  • D has a weight of -1

(the 5th character is whatever you want, it means empty space. I use (space) in my examples)

Items with negative weight fall upwards (towards the top of the string), and items with positive weight fall downwards (towards the bottom of the string).

When an object collides with something, one of three things happens:

  • If the object collides with the top or bottom "walls" of the input, then it just stops.

  • If the object collides with another object, their weight/velocity is summed (i.e. N and D would give 1). If the result is positive, both objects fall downwards. If it's negative, they fall upwards.

  • If an object (let's call it A) collides with an object B, and B is already pinned against the ceiling/floor, A will just come to rest against B.

All non-occupied spaces of the string/list should be filled with the empty character.

If it wasn't clear already: each character in the string/line is on top of the next one. i.e. NL is the same as:

N
L

And SD is:

(blank)
S
D

Test cases: (uses (the space character) to show empty space)

" L D " -> " LD  " or "  LD "

" SDLN " -> "SD  LN"

" NLLSSD " -> "NLLSSD  "

Comrade SparklePony

Posted 2017-05-10T18:46:24.773

Reputation: 5 784

3"Given a delimited string or list." Can also use a string without delimiters? Since all items are just individual characters that shouldn't be a problem, right? And what's the expected outcome for N0S or L0D? – Martin Ender – 2017-05-10T18:59:32.190

@MartinEnder About the delimited string, that was left over form a previous version of the question. It has been edited out. And I added a test case to address the second issue. If it is still unclear, please let me know. – Comrade SparklePony – 2017-05-10T20:52:50.700

Why the NUL character? – mbomb007 – 2017-05-10T21:21:01.270

Should've specified a directional order-of-operations. – Magic Octopus Urn – 2017-05-16T19:54:02.673

Side note: if "physics" is to be accounted for, letters with negative weights should probably fall downwards just like the rest. – Julian Wolf – 2017-05-16T23:04:09.073

Would ␣␣NSDLLD␣␣ become NSD␣␣␣␣LLD? – zgrep – 2017-05-18T16:05:04.040

@zgrep Yes, it would. – Comrade SparklePony – 2017-05-18T17:02:08.500

Do things such as -2 and 2 fall/rise faster than -1 and 1? – zgrep – 2017-05-18T17:07:07.407

@zgrep Everything falls/rises at the same rate. – Comrade SparklePony – 2017-05-18T17:08:05.440

Answers

4

Haskell, 169 180 bytes

g s=sum[n|c<-s,(d,n)<-zip"SD LN"[-2..],c==d]
w=elem ' '
h(x:y:r)|(w x&&g y<0)||(w y&&g x>0)=y:h(x:r)|w(x++y)||g x<0=x:h(y:r)|t<-x++y=h$t:r
h r=r
concat.until((==)=<<h)h.map(:[])

Try it online! Example usage: concat.until((==)=<<h)h.map(:[]) $ " SDLN ".

Edit: +11 bytes, now also works for the " NSDLLD " test case proposed by @zgrep.

(short) Explanation:

h works on a list of tokens where initially each char of the input string is token. Until the token list no longer changes, h bubbles through the list comparing two tokens x and y at a time. Depending on the tokens their order is kept (x:h(y:r)), they are swapped (y:h(x:r)) or combined to a single token (t<-x++y=h$t:r).

g computes the weight of a token and w checks whether a token contains a space.

Laikoni

Posted 2017-05-10T18:46:24.773

Reputation: 23 676

2

OCaml, 379 bytes

let rec n f a i=try n f(f a i)(i+1)with _->a
let r s=String.(concat""(let rec w s=if ' '=s.[0]then`E else(function
0->`F|w when w<0->`L|_->`H)(n(fun a i->index"SD LN"s.[i]-2+a)0 0)and l=function
a::b::t->(function`E,`L|`H,`E->l(b::a::t)|_,`L|`H,_|`F,`F|`E,`E->l((a^b)::t)|_->let
c=a::l(b::t)in if b=List.nth c 1 then c else l c)(w a,w b)|x->x in l(n(fun a
i->a@[sub s i 1])[]0)))

To test:

let () =
    List.iter (fun s -> Printf.printf "`%s`\n" (r s)) [
        "   S S   S S   ";
        "   D D   D D   ";
        "               ";
        "   L L   L L   ";
        "   N N   N N   ";
        "NL";
        " SD";
        " L D ";
        " SDLN ";
        " NLLSSD ";
    ]

juloo65

Posted 2017-05-10T18:46:24.773

Reputation: 81

1

Python 2, 322 bytes

Try it online

import re
S=input()
C=str.count
D=''
while S!=D:
 D=S
 for i in[(i.group(),i.span())for i in re.finditer('\w+',S)]:
    s=i[0];g=C(s,'N')*2+C(s,'L')-C(s,'S')*2-C(s,'D');l=g<0;b=g>0;c=(1,-1)[b]
    if g:S=S[:i[1][0]-1]*l+re.sub('^ '*l+i[0]+' $'*b,''.join([i[0],' '][::c]),[S[i[1][0]-1:],S[:i[1][1]+1]][b])+S[i[1][1]+1:]*b
print S

Dead Possum

Posted 2017-05-10T18:46:24.773

Reputation: 3 256