Contador de pontuação para Skat


11

Sua tarefa é escrever um pequeno programa, que conte os pontos de uma mão Skat. Um baralho Skat tem cartas de 7 a 10, valete, rainha, rei e ás (chamados Unter, Ober, König e Daus). Usamos os fatos alemães, que têm bolotas, folhas, copas e sinos em vez de paus, espadas, copas e diamantes. Os pontos são determinados pelo número no cartão:

  • 7, 8 e 9 são 0 pontos
  • Unter é de 2 pontos
  • Ober é de 3 pontos
  • König é de 4 pontos
  • 10 é 10 pontos
  • Daus é de 11 pontos.

Entrada / Saída

O formato de entrada consiste em dois símbolos, o primeiro representa o valor, enquanto o segundo representa o naipe:

  • 7, 8 e 9 representam a si mesmos
  • 0 (zero) significa 10
  • Unter, Ober, König e Daus são nomeados após suas primeiras letras (U, O e D)
  • O mesmo para bolotas, folhas, corações e Bellys (A, L, H e B)

A entrada é uma única linha de cartões, separada por um único espaço em branco. Você pode pegar a entrada de qualquer lugar, os argumentos da linha de comando também são bons. A saída é o valor da mão, impressa ou retornada como um código de saída. A saída do seu programa deve mostrar um erro, se algum cartão aparecer duas vezes na mão. (Portanto, 7A 0L 7Adeve retornar um erro em vez de 10). Também é bom encerrar com um código de saída 255 em vez de mostrar um erro, se esta for a maneira padrão do seu programa para gerar o resultado.

Exemplos

  • 7A 8A 9A UA OA KA 0A DA 7L 8L 9L UL OL KL 0L DL 7H 8H 9H UH OH KH 0H DH 7B 8B 9B UB OB KB 0B DB120
  • 7A 8L 0K DB 8L dá um erro
  • UA OB DL KH20

Regras

  • Código de golfe: o código mais curto vence
  • Aplicam-se regras usuais de golfe com código
  • O programa tem que trabalhar para todas as mãos, não apenas os exemplos
  • GIGO: Se a entrada for inválida, a saída pode ser arbitrária

A saída adicional para o stderr (por exemplo, avisos) está ok?
Ventero

@ Ventero: Sim, é. Qualquer maneira de errar é aceitável, mas deve estar claramente visível ao usuário, pois há um erro.
FUZxxl

Jack, Queen e Ace são chamados Unter, Ober, King e Daus? Um rei deveria estar lá?
Ry-

@minitech Não, não é.
FUZxxl

2
Eu acredito que você quer dizer "sinos", não "bellys". Muito diferente disso.
Boothby

Respostas:


2

APL ( 54 48)

Não tem de ser um caminho mais curto de selecionar o valor do cartão, mas eu não vejo isso.

(+/12-'D0.....KOU.'⍳⊃¨A)÷A≡∪A←↓A⍴⍨2,⍨2÷⍨⍴A←⍞~' '

Você recebe um DOMAIN ERRORse houver um cartão duplicado.

Explicação:

  • A←⍞~' ': armazena ( ) em Auma linha de entrada do usuário ( ) sem ( ~) os espaços.
  • 2,⍨2÷⍨⍴A: uma lista de dois elementos, contendo o comprimento de ( ) Adividido por ( ÷⍨) 2, seguido por ( ,⍨) o número 2. (Portanto, se a entrada for UA OB DL KHa lista, será (4, 2)).
  • ↓A⍴⍨: defina uma matriz ( ), com as dimensões dessa lista, contendo os valores de A. Em seguida, junte os elementos de suas linhas ( ), fornecendo uma lista de listas, por exemplo ['UA','OB','DL','KH'].
  • A←: Armazene esta lista em A.
  • A≡∪A: ∪Aé a lista de elementos exclusivos em A. Se isso é igual a A, não há duplicatas e isso retorna 1, caso contrário, 0.
  • ÷: divida o que está à esquerda (que faz o cálculo real) pelo resultado do teste de igualdade. Portanto, se não houver duplicatas, a pontuação permanecerá inalterada e, se houver duplicatas, você receberá um DOMAIN ERRORpor causa da divisão por zero.
  • ⊃¨A: Uma lista que fornece o primeiro elemento ( ) de cada elemento ( ¨) de A. Portanto, isso solta a letra da naipe, deixando a letra da pontuação. ( UODK)
  • 'D0.....KOU.'⍳: fornece o índice de cada uma das letras de pontuação nessa sequência, retorna 12 para valores que não estão na sequência. ( 10 9 1 8)
  • +/12-: subtraia todos esses 12 e adicione-os juntos. ( 2 + 3 + 11 + 4 = 20)


Perdi totalmente que sua resposta é a mais curta.
FUZxxl

10

Ruby 1.9, 52 caracteres

Entrada via argumentos da linha de comando. Estou assumindo que a mensagem de erro ao ter cartões duplicados não importa, então ela apenas reclama de um erro de conversão de avaliação / tipo.

p eval$*.uniq!||$*.map{|i|"..UOK#$<.0D"=~/#{i}?/}*?+

Exemplo de uso:

$ ruby1.9 skatscore.rb 7A 8A 9A UA OA KA 0A DA 7L 8L 9L UL OL KL 0L DL 7H 8H 9H UH OH KH 0H DH 7B 8B 9B UB OB KB 0B DB
120

$ ruby1.9 skatscore.rb 7A 7A
skatscore.rb:1:in `eval': can't convert Array into String (TypeError)
    from skatscore.rb:1:in `<main>'

Por um lado, acho que o erro variável indefinido para cartões duplicados é meio coxo. Por outro lado, não quebra as regras, por isso é meio inteligente.
Igby Largeman

1
@ Charles: Uma vez que a especificação só exige um erro, acho que o erro exatamente é praticamente irrelevante. E, se houver métodos curtos de produzir algum erro, tudo bem, eu acho.
Joey

6

Scala, 87 82 caracteres

args.distinct(args.size-1);println(args.map(a=>1+" UOK     0D".indexOf(a(0))).sum)

Lança uma exceção em cartões repetidos.


4

Haskell, 122 108 107 caracteres

import List
main=interact$f.words
f x|nub x==x=show$sum$map(maybe 0 id.(`elemIndex`"  UOK     0D").head)x

error""é mais curto que undefined. Salve um caractere usando interact.
FUZxxl

@FUZxxl: Usá- interactlo não imprimirá uma nova linha, por isso não tenho certeza se isso é aceitável. No entanto, pude economizar muito mais usando um padrão incompleto em vez de undefined.
hammar

Onde eu disse que é necessária uma nova linha? Não me lembro.
FUZxxl

2

GolfScript 54 53 52

Editar 1:

Acabei de descobrir um erro no código. Ele não detectou cartões duplicados se os duplicados foram os dois primeiros na entrada (porque eu estava usando o *operador fold e não o /operador de cada um para o primeiro loop).

Agora eu corrigi o código e também consegui retirar 1 caractere no processo. Aqui está a nova versão:

' '/{1$1$?){]?}{\+}if}/2%{"UOK0D"\?).0>+.4>5*+}%{+}*

A entrada deve estar na pilha como uma sequência, no formato especificado (exemplo '7A UA DA':).

Caso a entrada seja válida, o programa imprime o valor total dos cartões.

Caso haja pelo menos um cartão duplicado, o programa lança a seguinte exceção:

(eval):1:in `block in initialize': undefined method `class_id' for nil:NilClass (NoMethodError)

Edição 2:

Depois de ver esta postagem no meta site , decidi postar uma descrição do código. Isso também me ajudou a encontrar e corrigir um erro. Então, aqui vai:

# Initially, we epect the input string to be on the stack
# Example: "7A UA DA"

' '/            # split the input string by spaces
                # now we have on the stack an array of strings
                # (in our example: ["7A" "UA" "DA"])

# {1$1$?)!{\+}{]?}if}/  -> this piece of code checks for duplicate cards
#
# The trailing symbol (/) is the 'each' operator, meaning that the 
# preceding code block (enclosed in curly brackets) will be executed 
# for every cards in the previous array.
#
# Before each execution of the code block, the current card value
# is pushed on the stack.
#
# Basically what this code does is concatenate cards into a string
# and checks whether the current card is contained in the accumulated
# value.
#
# So, for each card, this is what we execute:

1$              # copies the concatenated string on top of the stack
                # (initially this is an empty string)

1$              # copies the current card on top of the stack

?               # returns (places on the stack) the 0-based index where 
                # the current card is found in the concatenated string
                # or -1 if not found

)               # increments the topmost stack value
                # Now we have 0 if the card is not a duplicate
                # or a value greater than 0 otherwise

{]?}{\+}if      # if the current stack value is non-0 (duplicate)
                # then execute the first code {]?} (generates an error)
                # Otherwise, if the card is valid, execute the {\+} block.
                # What this code does is essentially concatenate the current 
                # card value:
                #    \ -> swaps the two topmost stack values; now we have
                #         the concatenated string and the current card value
                #    + -> this is the concatenation operator

# After the previous code block finishes execution (in case the input is)
# valid, we end up having the concatenated card values on the stack
# In our example, this value is "DAUAUB7A".

# The next code fragment is the one that computes the card values
# This is the code: 2%{"UOK0D"\?).0>+.4>5*+}%{+}*

# And this is how it can be broken down:

2%              # takes only the even indexed chars from the existing string 
                # in our case, "DAUA7A" -> "DU7"
                # Only these characters are important for determining the 
                # card values.

# The following piece of code is:
# {"UOK0D"\?).0>+.4>5*+}%

# This code performs a map; it takes the individual chars,
# computes the corresponding numeric value for each of them and outputs an
# array containing those values

# This is achieved using the map operator (%) which evaluates the preceding 
# code block, delimited by curly braces, so, essentially this is the code that 
# computes the value for a card:
# "UOK0D"\?).0>+.4>5*+
# It can be broken down like this:

"UOK0D"         # pushes the "UOK0D" string on the stack
\               # swaps the two topmost stack values
                # Now, these values are: "UOK0D" and "l" 
                # (where "l" represents the current letter
                # that gives the card its value: U,O,K,0,D,7,8...)

?               # Find the index of the card's letter in the
                # "UOK0D" string.
                # Remember, this is 0-based index, or -1 if not found.

)               # increment the index value
                # Now we have the following value:
                #     1 if the card is U
                #     2 if the card is O
                #     3 if the card is K
                #     4 if the card is 0
                #     5 if the card is D
                #     0 if it is anything else

.0>+            # if the current value is greater than 0,
                # add 1 to it.

.4>5*+          # if the current value is greater than 4,
                # add 5 to it.

# Passing through these steps, we now have the following value:
#     2  if the card is U
#     3  if the card is O
#     4  if the card is K
#     10 if the card is 0
#     11 if the card is D
#     0  if it is anything else
# This is the exact value we were looking for.

# Now we have an array containing the value of each card.
# in our example, [0, 2, 11]
# The next piece of code is easy:

{+}*            # uses the * (fold) operator to add up all the
                # values in the array.

# This leaves the total value of the cards on the stack,
# which is exactly what we were looking for (0+2+11=13).

# Golfscript is awesome! :-)

1

Python, 114 caracteres

i=input().split();print(sum(int(dict(zip('7890UOKD','000A234B'))[x[0]],16)for x in i)if len(i)<=len(set(i))else'')

Infelizmente, o indexmétodo das listas no Python gera um erro se um elemento não for encontrado, em vez de retornar um valor negativo, e a importação defaultdictexigiria mais caracteres do que ele salvaria.


1

eTeX, 201 caracteres (sem contar as duas quebras de linha irrelevantes)

\def~#1#2{\catcode`#113\lccode`~`#1\lowercase{\def~}##1 {\ifcsname
#1##1 ~\D\fi\if\csname#1##1 ~\fi+"#2}}~70~80~90~0A~U2~O3~K4~DB\def
\a[#1]{\let~\endcsname\write6{^^J \the\numexpr#1 }\end}\expandafter\a

Usado como etex filename.tex [UA OB DL KH]. É necessário colocar o argumento entre colchetes: caso contrário, o eTeX não tem como determinar se chegamos ao final da lista de argumentos.

EDIT: conforme permitido na declaração da pergunta, entrada incorreta pode causar (um) erro. Por exemplo, etex filename.tex [OK]trava horrivelmente (porque Knão é uma cor válida).


Não funciona na minha máquina.
FUZxxl

@FUZxxl. Qual é a saída de etex -v? Qual é a mensagem de erro (aproximadamente)? O código deve ser colocado em um arquivo (com nome filename.texou qualquer outra coisa terminada em .tex) e usar esse nome na linha de comando etex filename.tex [<argument>]. (sorry para repassar o mesmo comentário, eu esqueci " @FUZxxl")
de Bruno Le Floch

Por favor, olhe aqui: hpaste.org/48949
FUZxxl

@FUZxxl. Obrigado pelo seu feedback. Knão é uma cor válida e a substituição por Xseus exemplos remove os erros (ela trava Kporque a letra tem outro significado, King). Eu poderia tornar o erro menos horrível adicionando \stringantes de cada um ##1, mas isso custaria mais 12 caracteres.
Bruno Le Floch

Desculpe. Eu distorci o exemplo. Agora está funcionando. Desculpe.
FUZxxl

1

PowerShell, 79 80

($a=$args|sort)|%{$s+=(10,11+4..0)['0DKOU'.IndexOf($_[0])]}
$s/("$a"-eq($a|gu))

Joga »Tentativa de dividir por zero.« Se as cartas aparecerem duas vezes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.