Falling ASCII balls

16

2

Input

You are given a 2D map with balls and ground in it. It looks like this:

  1         5          2
                 3
     4


__________________________

Each number is a ball, and the _ is ground level. The underscore _ character is not allowed in any other line than ground level line. There are only spaces, newlines and digits 0-9 allowed above ground level. You cannot assume that last line is the ground level - empty lines below ground level are allowed. You can also add spaces, to fill empty lines, if that does help you.

Balls can have numbers from 0 to 9, can be placed above each other, but not under ground. The ball's numbers will be unique.

Assume that each character is one meter.

Get map from pastebin!
Test case 1 - should output something like this
Test case 2 - should produce same results as first map

Challenge

Your challenge is to read a map like that from a file or from stdin — you are allowed to use cat balls.txt | ./yourexecutable — and output velocity of each ball when it hits the ground.

Here's the formula for velocity:

enter image description here

Assume that h is the line number difference between the ground's line number, and the ball's line number, and that g equals 10m/s^2.

Output

You should output each balls number and velocity in m/s at ground level. For example N - Vm/s, where N is ball number and V is its velocity. You can also output an array if you want.

Happy coding! :)

Jacajack

Posted 2016-06-25T10:45:27.083

Reputation: 501

Test cases with no expected result are not test cases – edc65 – 2016-06-25T15:26:37.237

@edc65 I added expected results to the question – Jacajack – 2016-06-25T15:33:23.033

Is it okay if I take the directory as input from the user as part of the program? – Daniel – 2016-06-25T15:49:01.843

@Dopapp What do you mean exactly? – Jacajack – 2016-06-25T15:52:18.497

See my answer.

– Daniel – 2016-06-25T16:07:42.357

Answers

8

MATL, 31 30 27 25 bytes

95\16\5B#fG&X>1)b- 20*X^h

Input is a 2D char array with ; as row separator:

['  1         5          2  ';'                 3        ';'     4                    ';'                          ';'                          ';'__________________________']

Try it online! Or include an initial t in the code to display the map for greater clarity.

Here are the other test cases: first, second.

Explanation

95\      % Take input implicitly. Modulo 95: convert to numbers and map '_' into 0
16\      % Modulo 16: map space into 0 and digit chars into corresponding numbers
5B#f     % Find row indices and values of nonzero entries
G        % Push input again
&X>      % Index of maximum of each column. This finds character '_'
1)       % Get first value (they are all equal)
b        % Bubble row indices of numbers up in the stack
-        % Subtract to get distance from each number to the ground
20*X^    % Multiply by 20, take sqrt. This gives the velocity values
h        % Horizontally concat numbers and velocities. Display implicitly

Luis Mendo

Posted 2016-06-25T10:45:27.083

Reputation: 87 464

7

C, 125 122 121 bytes

b[99]={};main(l,c){for(;(c=getchar())<95u;)b[c]=(l+=c==10);for(c=47;++c<58;)b[c]&&printf("%c,%f\n",c,sqrt((l-b[c])*20));}

Compile & run with gcc -w golf.c -lm && cat balls.txt | ./a.out.

orlp

Posted 2016-06-25T10:45:27.083

Reputation: 37 067

That's really great, sir! I didn't say that in my question, but I'd like you to know, that your example does not output anything, when character other than 0 ... 9 occurs in text file. Anyway, +1, because not pointing this out is my fault – Jacajack – 2016-06-25T11:45:28.623

@Jacajack No, any character is fine as long as it does not contain a character with ASCII code bigger than _. However, this could be fixed with one extra byte (!= instead of <). – orlp – 2016-06-25T12:32:20.053

Well, I used 'x' for testing. Nevermind. Your code's great :) – Jacajack – 2016-06-25T12:56:56.387

@Jacajack In the new version it's not a one character fix anymore, but I saved 3 more bytes :) – orlp – 2016-06-25T16:21:09.307

Nice! :) I'll take a look at what I can do with my code, when I come back home. I know it can be shortened a lot, but I don't want it to be a copy of yours :p – Jacajack – 2016-06-25T16:29:47.727

6

C -194(-5) 150 137 bytes

With a little bit more time and thinking, I golfed off 44 bytes
Thanks to orlp for helping me to save 13 bytes

I'll start with my C code:

b[256]={},n,i=47;main(l,c){for(;~(c=getchar());n=c==95?l:n)b[c]=(l+=c==10);for(;++i<58;)b[i]&&printf("%d %f\n",i-48,sqrt((n-b[i])*20));}

And human readable version:

//Throws many warnings, but lack of libraries is tolerated

/*
    c - current character
    l - line number (starts at 1)
    n - ground level
    i - iterator
    b - balls array
*/

b[256] = {}, n, i = 47; //That actually works, as long as you are using ASCII

main( l, c )
{
    for ( ;~( c = getchar( ) ); n = c == 95 ? l : n ) //Read stdin and search for ground
        b[c] = ( l += c == 10 ); //Increment lines counter on newlines, and save line numbers

    for ( ; ++i < 58; ) //Iterate through balls
        b[i] && printf( "%d %f\n", i - 48, sqrt( ( n - b[i] ) * 20 ) ); //Print out data    
}

Compile and run like that: gcc -o balls ballsgolf.c -lm && cat 1.txt | ./balls

Output

1 10.000000
2 10.000000
3 8.944272
4 7.745967
5 10.000000

Jacajack

Posted 2016-06-25T10:45:27.083

Reputation: 501

Save 4 bytes: ~(c=getchar()) instead of (c=getchar())!=EOF. – marinus – 2016-06-25T14:45:04.917

@marinus That's what I had. – orlp – 2016-06-25T16:16:47.237

1if (x != -1) is the same as if (~x) (on two's complement machines) because ~-1 is (uniquely) 0. In C golf never use while(cond), as for(;cond;) is just as long and provides more opportunities for golfing. In your example this can become for(;~(c=getchar());n=c==95?l:n)b[c]=(l+=c==10);. – orlp – 2016-06-25T22:05:36.177

@orlp I understand, thanks for advice :) – Jacajack – 2016-06-25T22:08:58.800

1l=1 can be circumvented by making l the first argument for main, as the C runtime passes the number of arguments to main as its first argument (argc), and when you call a program without any command line arguments (./a.out), then argc = l = 1. n=0; is unnecessary, as global integers are automatically initialized to 0. So just n; will suffice. – orlp – 2016-06-25T22:09:19.557

The c=n; is unnecessary if you rename the loop variable n in the second loop to i. – orlp – 2016-06-25T22:11:27.483

@orlp That's right. I don't know why, I was little bit afraid of not initializing variables with 0. Also, I thought that declaring variable like this in for loop would be invalid. argc stuff is whlole new level of trickiness, though. It's good to know things like these, thanks a lot! :) – Jacajack – 2016-06-25T22:21:36.253

4

Pyth, 27 26 25 24 bytes

smf-hT" _".e,b@*20-xd\_k2dC
smf@hT`M;.e,b@*20-xd\_k2dC
smf@T`M;.e,b@*20-xd\_k2dC
sm@#`M;.e,b@*20-xd\_k2dC

Try it online!

Leaky Nun

Posted 2016-06-25T10:45:27.083

Reputation: 45 011

1Fails if the last line is not the ground. – orlp – 2016-06-25T11:23:42.303

@orlp Oh, I thought the ground level can only be in the last line. – Leaky Nun – 2016-06-25T11:30:58.800

1It still fails after your edit. – orlp – 2016-06-25T12:53:26.040

@orlp No, it doesn't

– Leaky Nun – 2016-06-25T13:29:53.573

Yes it does. I gave an input on which it fails, which is exactly one empty line after the underscores. – orlp – 2016-06-25T14:22:10.693

1

@orlp It was in the rules that "You can add spaces, to fill empty lines, if that does help you."

– Leaky Nun – 2016-06-25T14:40:37.207

3

Matlab, 100 96 89 90 bytes

s=input('');X=find(s==95);for i=0:9
[x y]=find(s==48+i);if(x)[i sqrt(20*(X(1)-x))]
end
end

Many bytes saved thanks to Luis Mendo

Input format:

['  1         9          2  ';'                 3        ';'     4                    ';'                          ';'                          ';'__________________________']

Explanation:

X=find(s==95)         -- finds '_', we'll need X(1) to determine max height
for i=0:9             -- loops through balls' numbers
[x y]=find(s==48+i)   -- finds the ball
if(x)                 -- if it is present
[i sqrt(20*(X(1)-x))] -- output its number and velocity

pajonk

Posted 2016-06-25T10:45:27.083

Reputation: 2 480

3

Python 3, 84 bytes

Version 6, 84 bytes: (Thanks to Leaky Nun!)

lambda a:[(c,(~-(len(a)-i)*20)**.5)for i,s in enumerate(a)for c in s if c.isdigit()]

Version 5, 91 bytes:

lambda a:[c+":"+str((~-(len(a)-i)*20)**.5)for i,s in enumerate(a)for c in s if c.isdigit()]

Version 4, 92 bytes:

lambda i:[c+":"+str((~-(len(i)-n)*20)**.5)for n in range(len(i))for c in i[n]if c.isdigit()]

Version 3, 99 bytes:

def r(i):x=len(i);print([c+":"+str((~-(x-n)*20)**.5)for n in range(x)for c in i[n] if c.isdigit()])

Version 2, 102 bytes:

def r(i):
 n=len(i)
 for l in i:
  for c in l:
   if c.isdigit():print(c+":"+str((~-n*20)**.5))
  n-=1

The above versions take an array of strings as input.

Version 1, 140 bytes:

with open(input(),"r")as i:
 n=sum(1for l in i);i.seek(0)
 for l in i:
  for c in l:
   if c.isdigit():print(c+":"+str((~-n*20)**.5))
  n-=1

This takes the directory of the file as input from the user.

Daniel

Posted 2016-06-25T10:45:27.083

Reputation: 6 425

1 for l in i -> 1for l in i – Leaky Nun – 2016-06-25T16:09:08.907

@LeakyNun, does that trick work with all keywords and numbers? – Daniel – 2016-06-25T16:10:16.837

1I believe so. Also, (n-1)*20 -> ~-n*20 – Leaky Nun – 2016-06-25T16:10:38.783

I'm not sure, but I guess you could probably save a lot of byte by taking an array of strings as input instead, or just define a function taking an array of strings. – Leaky Nun – 2016-06-25T16:12:45.297

1Hold on. Doesn't Python3 require parentheses with the print call? – Yytsi – 2016-06-25T16:15:36.327

I'm not sure, but I think you could make this into one line: for c in l:if c.isdigit():print c+":"+str((~-n*20)**.5) – Leaky Nun – 2016-06-25T16:15:42.907

@TuukkaX, yeah you're right. Thanks for catching that! – Daniel – 2016-06-25T16:22:21.240

@LeakyNun, do you know if I am allowed to take an array as input? – Daniel – 2016-06-25T16:23:45.590

@Dopapp I think so. The MATL answer does it as well. – Yytsi – 2016-06-25T17:09:56.873

1@LeakyNun No it doesn't work for all keywords and numbers in Python 2. It specifically does not work for keywords starting with an e, because then the Python tokenizer will attempt to parse it as floating point scientific notation (e.g. 1e5). Example that fails: f = lambda n:-1if n<0else 1. An example that fails in both Python version is 0or 1, because the tokenizer thinks 0o starts an octal number. – orlp – 2016-06-25T22:14:34.287

Try enumerate. – Leaky Nun – 2016-06-26T00:34:17.453

@LeakyNun, do you have an idea of how to improve my last answer which uses enumerate? – Daniel – 2016-06-27T20:59:13.697

lambda a:[(c,(~-(len(a)-i)*20)**.5)for i,s in enumerate(a)for c in s if c.isdigit()] Oh, also it doesn't work if the ground level is not the last line. – Leaky Nun – 2016-06-27T22:44:00.927

@LeakyNun, why would that not work if the ground level is not the last line? Doesn't if c.isdigit() take care of that? – Daniel – 2016-06-27T22:47:50.197

2

Python 3, 84 bytes

lambda x:[[i,(20*x[x.find(i):x.find('_')].count('\n'))**.5]for i in x if i.isdigit()]

An anonymous function that accepts input by argument as a multi-line string with all empty lines filled with spaces, and returns an array where each element is of the form [ball number, speed].

How it works

lambda x                      Function with input x
...for i in x if i.isdigit()  Loop through all characters i in x for which i is a digit,
                              and hence one of the balls
x[x.find(i):x.find('_')]      Slice x to give the substring between the ball and the ground
....count('\n')               Count the number of newlines in the substring to give the
                              height of the ball
(20*...)**.5                  Calculate the speed of the ball as it hits the ground
[i,...]                       Package the ball number and speed into a list
:[...]                        Return all ball-speed pairs as a list with elements [ball
                              number, speed]

Try it on Ideone

TheBikingViking

Posted 2016-06-25T10:45:27.083

Reputation: 3 674

In this case, I think, it's code snippet rather than full standalone Python script, isn't it? – Jacajack – 2016-06-25T19:56:09.423

@Jacajack This is in fact a function, not a snippet, which is allowed by default. In Python, lambda functions are functions without a name which can assigned to a variable and then called when needed; you could write f = MyAnswer, and then call using f(x). There is a consensus that there is no need to name lambdas. Nice challenge, by the way!

– TheBikingViking – 2016-06-25T20:04:59.493

Sure, I just thought lambdas were assumed to be code snippets here (http://meta.codegolf.stackexchange.com/a/1146/55729). I guess everything is fine, then. Thank you for your opinion :)

– Jacajack – 2016-06-25T20:11:52.800

2

JavaScript (ES6) 93

Edit 2 bytes saved thx @Jacajack

A function with a multiline string as input parameter. Output is not sorted (as this in not requested)

a=>[...a].reverse().map(c=>c>'Z'?b=i:c<' '?++i:c>' '&&console.log(c,Math.sqrt((i-b)*20)),i=0)

Test

F=
a=>[...a].reverse().map(c=>c>'Z'?b=i:c<' '?++i:c>' '&&console.log(c,Math.sqrt((i-b)*20)),i=0)

function test()
{
  F(I.value);
}

test()
#I { height: 12em; width: 30em}
<textarea id=I>
    
 
  1         5          2
                 3
     4


__________________________




</textarea>
<button onclick="test()"></button>

edc65

Posted 2016-06-25T10:45:27.083

Reputation: 31 086

Wouldn't sqrt(x) be shorter than pow(x,.5)? – Jacajack – 2016-06-25T23:32:18.067

@Jacajack yes thanks I don't know how that slipped off my mind – edc65 – 2016-06-25T23:37:24.713