# Falling ASCII balls

## 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: 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! :)

• Test cases with no expected result are not test cases Jun 25, 2016 at 15:26
• @edc65 I added expected results to the question Jun 25, 2016 at 15:33
• Is it okay if I take the directory as input from the user as part of the program? Jun 25, 2016 at 15:49
• @Dopapp What do you mean exactly? Jun 25, 2016 at 15:52
• See my answer. Jun 25, 2016 at 16:07

# MATL, 313027 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


# C, 125122 121 bytes

b={};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.

• 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 Jun 25, 2016 at 11:45
• @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
Jun 25, 2016 at 12:32
• Well, I used 'x' for testing. Nevermind. Your code's great :) Jun 25, 2016 at 12:56
• @Jacajack In the new version it's not a one character fix anymore, but I saved 3 more bytes :)
– orlp
Jun 25, 2016 at 16:21
• 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 Jun 25, 2016 at 16:29

# 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

b={},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));}


//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 = {}, 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

• Save 4 bytes: ~(c=getchar()) instead of (c=getchar())!=EOF. Jun 25, 2016 at 14:45
• @marinus That's what I had.
– orlp
Jun 25, 2016 at 16:16
• if (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
Jun 25, 2016 at 22:05
• @orlp I understand, thanks for advice :) Jun 25, 2016 at 22:08
• l=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
Jun 25, 2016 at 22:09

# Pyth, 272625 24 bytes

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


Try it online!

• Fails if the last line is not the ground.
– orlp
Jun 25, 2016 at 11:23
• @orlp Oh, I thought the ground level can only be in the last line. Jun 25, 2016 at 11:30
• It still fails after your edit.
– orlp
Jun 25, 2016 at 12:53
• @orlp No, it doesn't Jun 25, 2016 at 13:29
• @orlp It was in the rules that "You can add spaces, to fill empty lines, if that does help you." Jun 25, 2016 at 14:40

## Matlab, 1009689 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


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

• 1 for l in i -> 1for l in i Jun 25, 2016 at 16:09
• @LeakyNun, does that trick work with all keywords and numbers? Jun 25, 2016 at 16:10
• I believe so. Also, (n-1)*20 -> ~-n*20 Jun 25, 2016 at 16:10
• Hold on. Doesn't Python3 require parentheses with the print call? Jun 25, 2016 at 16:15
• @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
Jun 25, 2016 at 22:14

# 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

• In this case, I think, it's code snippet rather than full standalone Python script, isn't it? Jun 25, 2016 at 19:56
• @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! Jun 25, 2016 at 20:04
• Sure, I just thought lambdas were assumed to be code snippets here (meta.codegolf.stackexchange.com/a/1146/55729). I guess everything is fine, then. Thank you for your opinion :) Jun 25, 2016 at 20:11

# 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>

• Wouldn't sqrt(x) be shorter than pow(x,.5)`? Jun 25, 2016 at 23:32
• @Jacajack yes thanks I don't know how that slipped off my mind Jun 25, 2016 at 23:37