10
\$\begingroup\$

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!

\$\endgroup\$
6
  • 1
    \$\begingroup\$ "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%? \$\endgroup\$
    – kuilin
    Feb 14, 2016 at 0:24
  • 1
    \$\begingroup\$ @KuilinLi It's not, order does not matter. I will clarify, thanks for the comment! \$\endgroup\$
    – Denker
    Feb 14, 2016 at 0:26
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – kuilin
    Feb 14, 2016 at 0:31
  • 1
    \$\begingroup\$ @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. \$\endgroup\$
    – Denker
    Feb 14, 2016 at 0:34
  • 9
    \$\begingroup\$ I don't drink, so my entry is function drive(a) { if (a.every(v=>/water/.test(v))) return [0, 0]; throw new TeetotalException; } \$\endgroup\$
    – Neil
    Feb 14, 2016 at 0:42

5 Answers 5

7
\$\begingroup\$

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

\$\endgroup\$
2
  • \$\begingroup\$ For 2012+ you could use the IIF function rather than CASE statements for some bytes \$\endgroup\$
    – MickyT
    Feb 14, 2016 at 21:01
  • 1
    \$\begingroup\$ 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) \$\endgroup\$
    – MickyT
    Feb 14, 2016 at 21:44
3
\$\begingroup\$

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]
)
\$\endgroup\$
1
\$\begingroup\$

Javascript (ES6), 111

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>5?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 > 5 ? g - 5 : 0])                     // Output: Level / 10 and Level - 5 bound to 0
\$\endgroup\$
3
  • \$\begingroup\$ Well played but not always valid: try [[3,"shots", "booze"]] \$\endgroup\$
    – edc65
    Feb 17, 2016 at 8:54
  • \$\begingroup\$ @edc65 Good Catch! \$\endgroup\$
    – reubn
    Feb 17, 2016 at 10:35
  • \$\begingroup\$ It just need a little adjustment and still a lot better than mine \$\endgroup\$
    – edc65
    Feb 17, 2016 at 12:02
1
\$\begingroup\$

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.

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

C (GCC), 176 166 bytes

-10 bytes thanks to @ceilingcat

float x;main(a){for(char b[9],c[9];~scanf("%d%s%s\n",&a,b,c);)x+=a*(*b-98?*b-103?.02:.2:.5)*(*c-98?c[1]-97?2:-1:c[1]-111?1:5);printf("%f %f",x>0?x:0,fmax(0,x*10-5));}

Attempt This Online!

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.