Quão bêbado estou e quando posso dirigir de novo?

8

É fim de semana e o que os caras legais estão fazendo nos finais de semana? Bebendo, é claro! Mas você sabe o que não é tão legal? Beber e dirigir. Então, você decide escrever um programa que diz a você como está carregado e quando poderá dirigir novamente sem ser detido pela polícia e perder sua licença.

O desafio

Dada uma lista de bebidas que você apreciou esta noite, calcule o seu nível de álcool no sangue e o tempo que você precisa esperar até entrar no seu carro e chegar em casa.

Entrada

Entrada será uma lista de bebidas que você tomou esta noite. Isso ficará assim:

4 tiros bebida
1 taça de vinho
2 garrafas de cerveja
3 copos de água

Os contêineres sempre serão plurais.

Como você pode ver, cada entrada consiste em:

  • O tipo de bebida (bebida, vinho, cerveja, água)
  • O recipiente para a bebida (doses, copos, garrafas)
  • A quantidade x das bebidas que você tomou desse tipo como número inteiro com x> 0,

Cada tipo de bebida adiciona uma certa quantidade de álcool ao seu sangue:

bebida -> 0,5 0.5 / 100 ml
cerveja -> 0,1 ‰ / 100 ml
vinho -> 0,2 ‰ / 100 ml
água -> -0,1 ‰ / 100 ml

A água é a exceção aqui, pois diminui o sangue e diminui o nível de álcool (seria muito bom se isso realmente funcionasse ...).

Cada contêiner possui um certo volume:

doses -> 20 ml
copos -> 200 ml
garrafas -> 500 ml

Resultado

Você precisa gerar dois números:

  • O nível de álcool em ‰
  • O tempo em horas em que você deve esperar até atingir 0,5 ‰ ou menos, para poder dirigir novamente. Você perde 0,1 ‰ por hora.

Notas

  • O nível de álcool nunca pode cair abaixo de zero.
  • O mesmo vale para o tempo de espera. Se você tiver 0,5 ‰ ou menos, produza zero.
  • A ordem das bebidas não importa; portanto, a água potável pode diminuir o nível de álcool abaixo de zero no processo de cálculo. Se ele permanecer lá, você precisará substituí-lo por zero.

O nível de álcool para o exemplo acima seria calculado da seguinte forma:

4 doses de bebida -> 0,4 ​​‰
1 taça de vinho -> 0,4 ​​‰
2 garrafas de cerveja -> 1,0 ‰
3 copos de água -> -0,6 ‰

=> 0,4 ​​+ 0,4 + 1 - 0,6 = 1,2 ‰

Para atingir 0,5 ‰, você precisa perder 0,7 ‰. Você perde 0,1 ‰ por hora, e precisa esperar 7 horas para dirigir novamente.

Regras

  • Você pode pegar a entrada no formato que quiser, mas precisa usar as strings exatas, conforme indicado acima. Você pode pegar os números como números inteiros.
  • Você pode produzir os dois números em qualquer ordem, apenas deixe claro qual deles você usa na sua resposta.
  • Você pode assumir que a entrada sempre terá pelo menos uma entrada.
  • Função ou programa completo permitido.
  • Regras padrão para entrada / saída.
  • Brechas padrão se aplicam.
  • Isso é , e a menor contagem de bytes vence. O desempate é uma submissão anterior.

Casos de teste

Entrada como lista de strings. Emite primeiro o nível de álcool, valores separados por vírgula.

["4 doses de bebida", "1 copo de vinho", "2 garrafas de cerveja", "3 copos de água"] -> 1,2, 7
["10 doses de bebida", "1 garrafa de água"] -> 0,5, 0
["3 copos de vinho", "2 garrafas de bebida"] -> 6,2, 57
["6 shots beer", "3 glasses water"] -> 0, 0
["10 copos de cerveja"] -> 2,0, 15

Feliz codificação!

Denker
fonte
1
"O nível de álcool nunca pode cair abaixo de zero." - A matriz está em ordem de concessão ou apenas no total? Então, se eu tomar 1 dose de cerveja, 2 doses de água e 1 dose de cerveja, deve produzir 0% ou 0,5%?
Kuilin Li 14/02/16
1
@KuilinLi Não é, a ordem não importa. Vou esclarecer, obrigado pelo comentário!
Denker
1
Portanto, deve produzir 0, e o nível de álcool pode tecnicamente cair abaixo de zero no meio da bebida? Porque, caso contrário, não temos como saber quando a água estava bêbada se a matriz contiver água ... Poderíamos até assumir que, se a matriz contiver água, beberemos a água primeiro e ela terá efeito nulo. qualquer coisa.
Kuilin Li 14/02/16
1
@KuilinLi Deixei claro no desafio agora. O nível de álcool pode cair abaixo de zero no processo de cálculo, basta arredondar para zero se permanecer lá.
Denker 14/02
7
Eu não bebo, então minha entrada éfunction drive(a) { if (a.every(v=>/water/.test(v))) return [0, 0]; throw new TeetotalException; }
Neil

Respostas:

1

Javascript (ES6), 109

Recebe entrada como matrizes de matrizes de strings / inteiros, por exemplo

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

Saídas para um array simples, por exemplo[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])

Explicado

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
reubn
fonte
Bem jogado, mas nem sempre válida: try[[3,"shots", "booze"]]
edc65
@ edc65 Boa captura!
21716 reubn
Ele só precisa de um pouco de ajuste e ainda muito melhor do que a minha
edc65
6

TSQL, 301 , 299 , 219 , 206 bytes

A entrada entra na tabela temporária #I(você disse qualquer formato :)

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

Código:

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;

Obrigado pelas idéias para melhorá-lo, Micky T :)

Liesel
fonte
Para 2012+ você pode usar a IIFfunção em vez de CASEdeclarações para alguns bytes
MickyT
1
Você também pode alterar os nomes das colunas nas subconsultas para evitar a qualificação nas cláusulas de junção, por exemplo, JOIN(SELECT .. )A(Y,S)ON Y=Ne (L+ABS(L))/2,10*((L-.5+ABS(L-.5))/2)é menor que a função IIF mencionada anteriormente. Você também pode economizar um pouco se tentar fazer uma junção cruzada nos valores de tamanho e resistência. por exemploSELECT V,N,Q*S FROM(VALUES(...))A(N,S),(VALUES(...)B(V,Q)
MickyT 14/02
3

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]

Menos golfe

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]
)
edc65
fonte
1

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

Para ser executado com perl -p. Pega entrada orientada a linha em STDIN, produz saída em STDOUT.

Versão com menos golfe:

# 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

Obrigado a dev-null por sugestões de economia de 11 bytes.

David Morris
fonte
@ dev-null obrigado! Acho que a função fazia sentido para um encurtamento intermediário e esqueci de verificar se ainda estava ajudando.
David Morris
Se você sempre terá entrada válida, então você pode mudar \dpara.
andlrc
Você poderia adicionar um exemplo de execução do programa, para ficar claro qual formato de entrada e saída você usa?
Denker