How drunk am I and when can I drive again?

It's weekend and what are the cool guys doing on weekends? Drinking of course! But you know what's not so cool? Drinking and driving. So you decide to write a program that tells you how loaded you are and when you are gonna be able to drive again without getting pulled over by the cops and loosing your license.

The Challenge

Given a list of beverages you enjoyed this evening, calculate your blood alcohol level and the time you have to wait till you can hop into your car and get home.

Input

Input will be a list of drinks you had this night. This will look like this:

4 shots booze
1 glasses wine
2 bottles beer
3 glasses water


Containers will always be plural.

As you can see each entry consists of:

• The type of drink (booze, wine, beer, water)
• The container for the drink (shots, glasses, bottles)
• The amount x of the drinks you had of that type as integer with x > 0,

Each drink type adds a certain amount of alcohol to your blood:

booze ->  0.5 ‰ / 100 ml
beer  ->  0.1 ‰ / 100 ml
wine  ->  0.2 ‰ / 100 ml
water -> -0.1 ‰ / 100 ml


Water is the exception here, since it thins your blood out and lowers your alcohol level (would be so nice if that actually worked...).

Each container has a certain volume:

shots   -> 20 ml
glasses -> 200 ml
bottles -> 500 ml


Output

You have to output two numbers:

• The alcohol level in ‰
• The time in hours you have to wait until you reached 0.5 ‰ or less, so you can drive again. You loose 0.1 ‰ per hour.

Notes

• The alcohol level can never fall below zero.
• Same goes for the waiting time. If you have 0.5 ‰ or less, output zero.
• The order of drinks does not matter, so drinking water may lower the alcohol level below zero in the process of the calculation. If it remains there, you need to replace it with zero.

The alcohol level for the the example above would be calculated like this:

4 shots booze   -> 0.4 ‰
1 glasses wine  -> 0.4 ‰
2 bottles beer  -> 1.0 ‰
3 glasses water -> -0.6 ‰

=> 0.4 + 0.4 + 1 - 0.6 = 1.2 ‰


To reach 0.5 ‰ you need to loose 0.7 ‰. You loose 0.1 ‰ per hour, so you need to wait 7 hours to drive again.

Rules

• You can take the input in any format you want, but you have to use the exact strings as given above. You may take the numbers as integers.
• You can output the two numbers in any order, just make in clear which one you use in your answer.
• You may assume that the input will always have at least one entry.
• Function or full program allowed.
• Default rules for input/output.
• Standard loopholes apply.
• This is , so lowest byte-count wins. Tiebreaker is earlier submission.

Test cases

Input as list of strings. Outputs alcohol level first, values seperated by a comma.

["4 shots booze","1 glasses wine","2 bottles beer","3 glasses water"] -> 1.2, 7
["10 shots booze", "1 bottle water"] -> 0.5, 0
["3 glasses wine", "2 bottles booze"] -> 6.2, 57
["6 shots beer", "3 glasses water"] -> 0, 0
["10 glasses beer"] -> 2.0, 15


Happy Coding!

• "The alcohol level can never fall below zero." - Is the array in order of concession, or just in total? So if I have 1 shot of beer, and then 2 shots of water, and then 1 shot of beer, should it output 0% or .5%? Feb 14 '16 at 0:24
• @KuilinLi It's not, order does not matter. I will clarify, thanks for the comment! Feb 14 '16 at 0:26
• So it should output 0, and alcohol level can technically fall below zero in the middle of the drinking? Cuz otherwise, we have no way of knowing when the water was drunk if the array has water in it... We could even assume that, if the array contains water, we will drink the water first, and it will have zero effect on anything. Feb 14 '16 at 0:31
• @KuilinLi I made it clear in the challenge now. Alcohol level may fall below zero in the process of the calculation, you just have to round it to zero if it stays there. Feb 14 '16 at 0:34
• I don't drink, so my entry is function drive(a) { if (a.every(v=>/water/.test(v))) return [0, 0]; throw new TeetotalException; }
– Neil
Feb 14 '16 at 0:42

TSQL, 301, 299, 219, 206 Bytes

Input goes into temp table #I (you said any format :)

SELECT * INTO #I FROM (
VALUES
(4,'shots','booze')
,(1,'glasses','wine')
,(2,'bottles','beer')
,(3, 'glasses','water')
) A (Q, V, N)


Code:

SELECT IIF(L<0,0,L),IIF(10*L-.5<0,0,10*L-.5)FROM(SELECT SUM(Q*S*P)L FROM(VALUES('bo%',.5),('be%',.1),('wi%',.2),('wa%',-.1))A(W,S),(VALUES('s%',.2),('g%',2),('b%',5))B(X,P),#I WHERE N LIKE W AND V LIKE X)A;


Thanks for the ideas to improve it, Micky T :)

• For 2012+ you could use the IIF function rather than CASE statements for some bytes Feb 14 '16 at 21:01
• You could also change your column names in the subqueries to avoid having to qualify then in the join clauses eg JOIN(SELECT .. )A(Y,S)ON Y=N and (L+ABS(L))/2,10*((L-.5+ABS(L-.5))/2) is shorter than the previously mentioned IIF function. You may also save a bit if you look at doing a cross join on the values for size and strength. eg SELECT V,N,Q*S FROM(VALUES(...))A(N,S),(VALUES(...)B(V,Q) Feb 14 '16 at 21:44

JavaScript (ES6), 131

a=>a.map(s=>([a,b,c]=s.split ,t+=a*[50,20,2]['bgs'.search(b[0])]*~-'0236'['aeio'.search(c[1])]),t=0)&&[t>0?t/100:0,t>50?t/10-5:0]


Less golfed

a=>(
t=0,
a.map(s=>(
[a,b,c] = s.split ,
t += a * [50,20,2]['bgs'.search(b[0])] // char 0 is unique
* [-1,1,2,5]['aeio'.search(c[1])] // char 1 is unique
// golfed: add 1 to get a string of dingle digits, the sub 1 using ~-
)
),
[ t>0 ? t/100 : 0, t>50 ? t/10-5 : 0]
)


Javascript (ES6), 109

Takes input as arrays of arrays of strings/integers e.g.

[[4, "shots", "booze"],
[1, "glasses", "wine"],
[2, "bottles", "beer"],
[3, "glasses", "water"]]


Outputs to simple array e.g. [1.2, 7]

a=>(b=0,c={s:2,g:20,b:50,o:2,e:10,i:5,a:-10},a.map(([d,e,f])=>b+=d*c[e[0]]/c[f[1]]),g=b>0?b:0,[g/10,g?g-5:0])


Explained

a => (
b = 0,                                           // Counter For Alcohol Level
c = {s:2, g:20, b:50, o:2, e:10, i:5, a:-10},    // Look up for values
a.map(                                           // Loops over array
([d, e, f]) =>                                 // Sets d,e,f to respective array indexes
b += d * c[e[0]] / c[f[1]]                  // Increases Level by values from lookup
),
g = b > 0 ? b : 0,                               // If Level is lower than 0 make it = 0
[g / 10, g ? g - 5 : 0])                         // Output: Level / 10 and Level - 5 bound to 0

• Well played but not always valid: try [[3,"shots", "booze"]] Feb 17 '16 at 8:54
• @edc65 Good Catch! Feb 17 '16 at 10:35
• It just need a little adjustment and still a lot better than mine Feb 17 '16 at 12:02

Perl, 133 119 + 3 = 136 122 bytes

%u=(o,.5,e,.1,i,.2,a,-.1,g,2,b,5,s=>.2);/(\d+) (.).* .(.)/;$x+=$1*$u{$2}*$u{$3}}{$_=($x>0?$x:0).$".($x-.5>0?$x-.5:0)*10


To be run with perl -p. Takes line-oriented input on STDIN, produces output on STDOUT.

Less-golfed version:

# char->number conversion table
# declared using barewords except for 's', which can't be a bareword
# because it's a keyword
%u=(o,.5, e,.1, i,.2, a,-.1, g,2, b,5, s=>.2);

# extract the number, first letter of first word, second letter of
# second word
/(\d+) (.).* .(.)/;

# do unit conversion and multiply up all factors
$x +=$1 * $u{$2} * $u{$3}

# hack for -p to produce an END { ... print } block
}{

# format output
$_ = ($x > 0 ? $x : 0) .$" . ($x-.5 > 0 ?$x-.5 : 0)*10


Thanks to dev-null for suggestions saving 11 bytes.

• @dev-null thanks! I think the function made sense for an intermediate shortening, and I forgot to check whether it was still helping. Feb 14 '16 at 14:16
• If you always get valid input then you can change \d to . Feb 14 '16 at 16:28
• Would you please add an example run of the program, so its clear which input and output format you use? Feb 15 '16 at 8:41