# Забей руку Криббеджа

28

Эта задача состоит в том, чтобы выиграть руку Криббеджа. Если вы не играете в Криббедж, у вас есть кое-какое обучение. Мы играем со стандартной покерной колодой, и комбинация состоит из четырех карт плюс «открытая карта». Существует два типа рук: нормальная и «рука для кроватки».

Карты приходят в формате, `vs`где `v`один из: `A23456789TJQK`(T для десяти) и `s`является одним из `SCDH`. Рука будет дана в форме (например)

``````AS 2D 3H JS | 4S
``````

где `4S`открытая карта Рука для кроватки будет иметь формат

``````JD 3C 4H 5H | 5S !
``````

Лицевые карты имеют значение 10, а туз - значение 1. Подсчет очков выполняется следующим образом.

• Пятнадцать: за каждое подмножество из пяти карт, сумма которых составляет 15, добавьте два очка.
• Пары: за каждую пару карт с одинаковым рангом (не значением) добавьте два очка.
• Прогоны: для каждого максимального прогона последовательных карт длиной более 2, добавьте длину прогона в пунктах.
• Флеш: если все пять карт одной масти, добавьте пять очков. В противном случае, если все, кроме открытой карты, одной масти, добавьте четыре очка. Если это рука с колыбелью, четырехточечный вариант не учитывается.
• Нобы: если в руке есть валет с той же мастью из открытой карты, добавьте одно очко.

Заметки:

• Тройки и четверки не являются особенными - в тройке три пары, поэтому тройка стоит 6 очков.

• Пробеги могут перекрываться. Например, `AS AH 2D 3C | 2C`(двойной двойной прогон) имеет четыре трассы длиной 3 и две пары, поэтому стоит 3 + 3 + 3 + 3 + 2 + 2 = 16 баллов.

• Подсчитываются только максимальные пробеги, поэтому `KS QD JD TC | 9S`стоит 5 баллов, поскольку это пробег 5. Подвалы не учитываются.

Дом Правило:

Невозможно набрать 19 очков в руке. Вместо нуля сообщите 19 баллов.

Примеры:

``````5S 5H 5D JS | KS
21

AS 2D 3H JS | 4S !
9

JD 3C 4H 5H | 5S
12

9S 8S 7S 6S | 5H !
9

9S 8S 7S 6S | 5H
13

8D 7D 6D 5D | 4D !
14

8D 7D 6D 5D | 4D
14

AD KD 3C QD | 6D
19
``````

Это код гольф. Самое короткое решение побеждает.

4
«пятнадцать два, пятнадцать четыре, ...» Да, да, да, но это было давно.
dmckee

2
@dmckee, да, я был очень хорош в моих требованиях для оценки. Я думал о том, чтобы выложить полное описание скороговорки ... «пятнадцать два, пятнадцать четыре и пара на шесть; привязать их клюшками» . Но тогда описание проблемы будет 30 страниц.
Boothby

1
3 + 3 + 3 + 3 + 2 = 16? Я думаю, что вам не хватает еще +2.
Grc

1
И второй и последний примеры означают 9 и 1? Я думаю, что последнее правило должно применяться к ним, но я не уверен (никогда не играл в криббидж раньше).
grc

1
@ grc Да, я скучал по ним. Это единственная из известных мне игр, в которой выигрыш - самая сложная часть.
Boothby

Ответы:

2

### GolfScript, 187 178 174 символов

``````:c"J"c{"SCDH"?)},1/:s-1=+/,([s)-!5*s);)-!4*c"!"?)!*]\$-1=+0.14,{c{"A23456789TJQK"?)}%{},:v\{=}+,,.{@*\)}{;.2>**+1 0}if}/;;5-v{{=+}+v\/}/v{.9>{;10}*{1\$+}+%}/{15=},,2*+.!19*+
``````

Так как я никогда не играл в криббидж, я не знаю каких-либо хитростей. Поэтому я подумал, что единственный способ соревноваться (хотя бы немного) - это использовать язык гольфа. Код довольно простой GolfScript, тестовые примеры можно найти здесь .

Код более читабелен (немного переформатирован и немного разложен ):

``````# Save cards to <c>
:c;

# Is it a non-crib hand? <r>
c"!"?)!:r;

# Values go to <v>
c{"A23456789TJQK"?)}%{},:v;

# Suits go to <s>
c{"SCDH"?)},1/:s;

# Print score for Fifteens
v{.9>{;10}*{1\$+}+%}/{15=},,2* .p

# Print score for Pairs
-5v{{=+}+v\/}/ .p

# Print score for Runs
0..14,{v\{=}+,,.{*\)\}{;\.2>**+0 1}if}/;; .p

# Print score for Flush
[s)-!5*s);)-!4*r*]\$-1= .p

# And finally print the score for Nobs
c"J"s-1=+/,( .p

# Sum up the sub-scores and if score is zero set to 19
++++
.!19*+
``````

Изменить: Изменена логика для пятнадцати и флеш.

1
Хлоп! Это самый длинный сценарий GS, который я когда-либо видел! Браво!
Boothby

7

## С 364 388 символов

Он большой и некрасивый (хотя и не такой большой, как раньше):

``````char*L="CA23456789TJQKDHS",b,p,r,s,v,i=4,t,m,q;
g(j){++p[r[i]=strchr(L,b[j])-L];s[i]=strchr(L,b[j+1])-L;}
f(j,u){u==15?v+=2:++j<5&&f(j,u,f(j,u+(r[j]>9?10:r[j])));}
main(){gets(b);for(g(14);i--;r[i]^11|s[i]^s||++v)g(i*3);
for(f(i,0);++i<15;v+=q?q*q-q:t>2?t*m:0,t=q?t+1:0,m=q?m*q:1)q=p[i];
while(++t<5&&s[t]==*s);v+=t>4-!b?t:0;printf("%d\n",v?v:19);}
``````

(Для облегчения чтения были добавлены разрывы строк; они не включены в приведенный выше список.)

В описании проблемы не указывалось, должен ли код проверять наличие недопустимых входных данных, поэтому, естественно, я предполагал, что программа может свободно вести себя по желанию, если входные данные, скажем, содержат дополнительный пробел.

Вот негольфированная версия:

``````#include <stdio.h>
#include <string.h>

/* A-K correspond to values 1-13. Suit values are arbitrary.
*/
static char const *symbols="CA23456789TJQKDHS";

/* Used as both an input buffer and to bucket cards by rank.
*/
static char buf;

/* The cards.
*/
static int rank, suit;

/* The cards broken down by rank.
*/
static int buckets;

static int score;
static int touching, matching, i;

/* Read card number i from buf at position j.
*/
static void getcard(int j)
{
rank[i] = strchr(symbols, buf[j]) - symbols;
suit[i] = strchr(symbols, buf[j+1]) - symbols;
++buckets[rank[i];
}

/* Recursively find all combinations that add up to fifteen.
*/
static void fifteens(int j, int total)
{
for ( ; j < 5 ; ++j) {
int subtotal = total + (rank[j] > 9 ? 10 : rank[j]);
if (subtotal == 15)
score += 2;
else if (subtotal < 15)
fifteens(j + 1, subtotal);
}
}

int main(void)
{
fgets(buf, sizeof buf, stdin);
score = 0;

/* Read cards from buf */
for (i = 0 ; i < 4 ; ++i)
getcard(i * 3);
getcard(14);

/* Score fifteens */
fifteens(0, 0);

/* Score any runs and/or pairs */
touching = 0;
matching = 1;
for (i = 1 ; i < 15 ; ++i) {
if (buckets[i]) {
score += buckets[i] * (buckets[i] - 1);
++touching;
matching *= buckets[i];
} else {
if (touching > 2)
score += touching * matching;
touching = 0;
matching = 1;
}
}

/* Check for flush */
for (i = 1 ; i < 5 && suit[i] == suit ; ++i) ;
if (i >= (buf == '!' ? 5 : 4))
score += i;

/* Check for hisnob */
for (i = 0 ; i < 4 ; ++i)
if (rank[i] == 11 && suit[i] == suit)
++score;

printf("%d\n", score ? score : 19);
return 0;
}
``````

Поскольку я не уточнил, не стесняйтесь сбрить эти 20 символов!
Boothby

Это действительно впечатляет - вопрос большой и безобразный! Это кодовый гольф, сегфаутинг на входе в дерьмо - это нормально.
Boothby

5

## Руби 1,9 359 356

Это слишком долго - почти столько же, сколько C-решение.

``````R='A23456789TJQK'
y=gets
f=y.scan /\w+/
o=f.map(&:chr).sort_by{|k|R.index k}
s=0
2.upto(5){|i|o.combination(i){|j|t=0
j.map{|k|t+=k==?A?1:k<?:?k.hex: 10}
(t==15||i<3&&j.uniq!)&&s+=2}}
m=n=l=1
(o+[z=?_]).map{|k|k[z]?n+=1:R[z+k]?(m*=n
l+=n=1):(l>2&&s+=l*m*n
l=n=m=1)
z=k}
x=f.take_while{|k|k[y]}.size
x>(y[?!]?4:3)&&s+=x
y[?J+f+' ']&&s+=1
p s>0?s:19
``````

5

# Что-то для начала .. Ruby, 422 365 355 352

``````c=gets
a,b=c.scan(/(\w)(\w)/).transpose
f=->x{x.uniq.size<2}
s=f[b]?5:!c[/!/]&f[b[0,4]]?4:0
c[/J(.).*\1 ?!?\$/]&&s+=1
s+=[5,4,3].map{|i|a.permutation(i).map{|x|'A23456789TJQK'[x*'']?i:0}.inject :+}.find{|x|x>0}||0
a.map{|x|s+=a.count(x)-1}
2.upto(5){|i|s+=2*a.map{|x|x.tr(?A,?1).sub(/\D/,'10').to_i}.combination(i).count{|x|x.inject(:+)==15}}
p s<1?19:s
``````

Слегка разгульный

``````def t(c)
s=0

if c.scan(/[SDHC]/).uniq.size<2 # Flush
s+=5
elsif c[0..9].scan(/[SDHC]/).uniq.size<2 && c[-1]!=?! # Flush
s+=4
end
s+=1 if c =~ /J(.).*(\1\$|\1\s.\$)/ # Nobs

c=c.scan(/[^ \|]+/).map{|x|x}[0..4]
d = (3..5).map{|i|c.permutation(i).map{|x| 'A23456789TJQK'.include?(x*'') ? i : 0}.inject(:+)}.reverse.find{|x|x>0} || 0# Runs
s+=d
c.map{|x|s+=c.count(x)-1} # Pairs
c.map!{|x|x.tr('A','1').gsub(/[JQK]/,'10').to_i}
(2..5).map{|i|s+=2*c.combination(i).count{|x|15==x.inject(:+)}} # 15s
s<1 ? 19 : s
end
``````

Модульные тесты для гольфовой версии:

``````require "test/unit"

def t(c)
c=gets
a,b=c.scan(/(\w)(\w)/).transpose
f=->x{x.uniq.size<2}
s=f[b]?5:!c[/!/]&f[b[0,4]]?4:0
c[/J(.).*\1 ?!?\$/]&&s+=1
s+=[5,4,3].map{|i|a.permutation(i).map{|x|'A23456789TJQK'[x*'']?i:0}.inject :+}.find{|x|x>0}||0
a.map{|x|s+=a.count(x)-1}
2.upto(5){|i|s+=2*a.map{|x|x.tr(?A,?1).sub(/\D/,'10').to_i}.combination(i).count{|x|x.inject(:+)==15}}
p s<1?19:s
end

class Test1 < Test::Unit::TestCase
def test_simple
assert_equal 21, t("5S 5H 5D JS | KS")
assert_equal 21, t("JS 5H 5D 5S | KS")
assert_equal 12, t("JD 3C 4H 5H | 5S")
assert_equal 13, t("9S 8S 7S 6S | 5H")
assert_equal 14, t("8D 7D 6D 5D | 4D")
assert_equal 19, t("AD KD 3C QD | 6D")
assert_equal 9, t("AS 2D 3H JS | 4S !")
assert_equal 9, t("JS 2D 3H AS | 4S !")
assert_equal 14, t("8D 7D 6D 5D | 4D !")
assert_equal 9, t("9S 8S 7S 6S | 5H !")
end
end
``````

Полученные результаты:

``````% ruby ./crib.rb
Run options:

# Running tests:

21
21
12
13
14
19
9
9
14
9
.

Finished tests in 0.014529s, 68.8281 tests/s, 688.2813 assertions/s.

1 tests, 10 assertions, 0 failures, 0 errors, 0 skips
``````

4

# Python, 629 символов

Я только отправляю свой, потому что никто не имеет. Это довольно долго :(

``````g=range
i=raw_input().split()
r,u=zip(*[tuple(x)for x in i if x not in'!|'])
v=map(int,[((x,10)[x in'TJQK'],1)[x=='A']for x in r])
z=list(set(map(int,[(x,dict(zip('ATJQK',[1,10,11,12,13])).get(x))[x in'ATJQK']for x in r])))
z.sort()
z=[-1]*(5-len(z))+z
s=p=l=0
for a in g(5):
for b in g(a+1,5):
s+=2*(v[a]+v[b]==15)
p+=2*(r[a]==r[b])
if z[a:b+1]==g(z[a],z[b]+1)and b-a>1:l=max(l,b+1-a)
for c in g(b+1,5):s+=2*(v[a]+v[b]+v[c]==15)
for d in g(5):s+=2*(sum(v)-v[d]==15)
n=len(set(u))
s+=4*(n==2 and u[-1] not in u[:4] and i[-1]!='!')+5*(n<2)+('J'+uin i[:4])+2*(sum(v)==15)+p+((l*3,l*p)[p<5]or l)
print(s,19)[s<1]
``````

Вау, это долго! Хорошо сделано, хотя. Кстати, вам никогда не нужны пробелы до / после кавычек и скобок.
Boothby

1
О, спасибо, я забыл об этом. Теперь он немного короче;)
grc

Как насчет `print s or 19`? Я думаю, что вы также можете использовать Python 3.x и сбрить еще 3 символа ( `raw_input`до `input`, затем `print s or 19`до `print(s or 19)`).
Ry-

2

# Python 2, 606 584 байта

Сохранено 22 байта благодаря игре в гольф Джо Кинга .

``````from itertools import*
s,S,C,E=sum,sorted,combinations,enumerate
def f(a):a=a.split();a.pop(4);e=a.pop(5)if a[-1]<"\$"else 0;b=S("A23456789TJQK".index(i)for i,j in a);d=S(set(b));h=[j for i,j in a];z=len([s(k)for r in range(6)for k in C([[10,k+1][k<10]for k in b],r)if s(k)==15])*2+s(2for i,j in C(b,2)if i==j)+[4*(e<1),5][len(set(h))<2]*(len(set(h[:4]))<2)+(ain[j for i,j in a[:4]if i=="J"])+s(reduce(lambda x,y:x*y,[b.count(k)for k in m])*len(m)for m in[d[s(x[:i]):s(x[:i])+j]for x in[[len(list(e))for i,e in groupby(j-i for i,j in E(d))]]for i,j in E(x)if j>2]);return z or 19``````

Попробуйте онлайн!

Чуть короче, чем ответ GRC , и выбирает другой путь.

## Объяснение:

``````    # import everything from "itertools" library. We only need "combinations" and "groupby".
from itertools import*
# alias functions to shorter names
s,S,C,E=sum,sorted,combinations,enumerate

# function f which takes the hand+up card+crib string as its argument
def f(a):
# convert space-separated string into list of items.
a=a.split()

# remove the 4th index, which is always "|".
a.pop(4)

# change golfed by Jo King
# if the final item in the list is a "!" (if it is <"\$"), remove it from the list and assign it to variable "e".
# otherwise, assign 0 to variable "e".
# a non-empty string will evaluate to True and 0 will evaluate to False in IF checks later.
e=a.pop(5)if a[-1]<"\$"else 0

# for each card in the list, split the identifiers into the value(i) and the suit(j).
# return the value's index in the string "A23456789TJQK".
# so, ["5S", "5H", "5D", "JS", "KS"] will return [4, 4, 4, 10, 12].
# using the aliased built-in function sorted(), sort the list numerically ascending.
b=S("A23456789TJQK".index(i)for i,j in a)

# get the unique items in b, then sort the result numerically ascending.
d=S(set(b))

# for each card in the list, split the identifiers into the value(i) and the suit(j).
# return the suits.
h=[j for i,j in a]

# fifteens
# changes golfed by Jo King
# generate pairs of (10, value + 1) for all cards (since they are zero-indexed)
# since True and False evaluate to 1 and 0 in python, return 10 if k>=10
# and reduce all values >10 to 10
# get all unique combinations of cards for 5 cards, 4 cards, 3 cards, 2 cards, and 1 card
# add the values of all unique combinations, and return any that equal 15
# multiply the number of returned 15s by 2 for score
z=len([s(k)for r in range(6)for k in C([[10,k+1][k<10]for k in b],r)if s(k)==15])*2
+
# pairs
# using itertools.combinations, get all unique combinations of cards into groups of 2.
# then, add 2 for each pair where both cards have an identical value.
s(2for i,j in C(b,2)if i==j)
+
# flush
# changes golfed by Jo King
# using list indexing
# [4 * (0 if crib else 1), 5], get item at index [0 if more than one suit in hand+up card else 1]
#    -> 4 if not crib and not all suits same
#    -> 5 if all cards same
#    -> 0 otherwise
# * (0 if more than one suit in hand else 1)
#    -> 4 * 0 if not crib and not all suits same
#    -> 4 * 1 if not crib and all suits same
#    -> 5 * 1 if all cards same
#    -> 0 otherwise
[4*(e<1),5][len(set(h))<2]*(len(set(h[:4]))<2)
+
# nobs
# check if the suit of the 5th card (4, zero-indexed) matches the suit of any of the other 4 cards, and if it does is that card a Jack
(ain[j for i,j in a[:4]if i=="J"])
+
# runs
s(reduce(lambda x,y:x*y,[b.count(k)for k in m])*len(m)for m in[d[s(x[:i]):s(x[:i])+j]for x in[[len(list(e))for i,e in groupby(j-i for i,j in E(d))]]for i,j in E(x)if j>2])

# since only 0 evaluates to false, iff z==0 return 19, else return z.
print z or 19``````

## Объяснение для логики запусков, в частности:

``````# for each index and value in the list, add the value minus the index
# since the list is sorted and reduced to unique values, this means adjacent values will all be the same value after offset
# ex: "JD 3C 4H 5H | 5S" -> [2, 3, 4, 10] - > [2, 2, 2, 7]
z = []
for i,j in enumerate(d):
z.append(j-i)

# group the values by unique value
# then add the length of the groups to the list
# ex: [2, 2, 2, 7] -> [2:[2,2,2], 7:]
#     [2:[2,2,2], 7:] -> [, ]
w = []
for i,e in groupby(z):
w.append([len(list(e))])

# list is double-nested so that the combined list comprehension leaves "x" available in both places it is needed
z = []
for x in w:
for i,j in enumerate(x):
if j>2:
# if the group length is larger than 2
# slice the list of unique card values to obtain only run values
# since the run can be anywhere in the list, sum the preceding lengths to find the start and end index
a = d[ sum(x[:i]) : sum(x[:i])+j ]
z.append(a)

w = []
for m in z:
# get the number of times the value is in the entire hand
# ex: "JD 3C 4H 5H | 5S" -> [2,3,4,4,10] and (2,3,4) -> [1, 1, 2]
a = [b.count(k)for k in m]
# multiply all values together
# [1, 1, 2] = 1*1*2 = 2
a = reduce(lambda x,y:x*y, a)
# length of the run * number of duplicate values
a *= len(m)
w.append(a)

# sum the results of the runs
return sum(w)``````

1
Немного быстрой игры в гольф, `if`чтобы получить 584 байта
Джо Кинг

1

# Stax , 106 байт

``````Çí╬Δ╓↔╥.L§º♦½┌§└─»◄G≤n▒HJ♀p\$¼♥,Q¢▲»Δ÷♠º≈r↑Vo\b■┌4Üé∟]e:┬A½f║J4σ↔└ΓW6O?╧φ¡╫╠├√├ùß5₧k%5ê╜ò/Φ/7w╠█91I◘┬n≥ìk♂╪
``````

Запускать и отлаживать онлайн!

Бонус для CP437: видите символ тех костюмов на упакованном Stax? Жаль, что клубы не появляются ...

Эквивалент ASCII

``````jc%7<~6(4|@Y{h"A23456789TJQK"I^mXS{{A|mm|+15=_%2=_:u*+f%HxS{{o:-u1]=f{%mc3+|Msn#*+y{H"SHCD"ImY:uc5*s!yNd:u;**HH++yN|Ixs@11#+c19?
``````

## объяснение

``````jc%7<~6(4|@Y...X...Y...c19?
j                              Split on space
c%7<~                         Is it a crib hand? Put it on input stack for later use
6(                       Remove "!" if it exists
4|@                    Remove "|"
Y                   Store list of cards in y
...X               Store ranks in x
...            Perform scoring for ranks
Y           Store suits in y
...        Perform scoring for suits
c19?    If the score is 0, change it to 19

{h"..."I^mX
{        m     Map each two character string to
h             The first character
"..."I^      1-based index of the character in the string

S{{A|mm|+15=_%2=_:u*+f%H
S                          Powerset
{                   f%H   Twice the number of elements that satisfy the predicate
{A|mm                        Value of card. Take the minimum of the rank and 10
|+15=                   Sum of values equal 15 (*)
_%2=               Length is 2 (**)
_:u            All elements are the same (***)
*+          ( (***) and (**) ) or (*)

xS{{o:-u1]=f{%mc3+|Msn#*+
xS                                Powerset of ranks
{        f                      Filter with predicate
{o                                 Sort
:-u                              Unique differences between elements
1]=                           Is 
{%mc                  Length of all runs
3+|M              Maximum of all the lengths and 3
sn#           Number of runs with maximal length
*          Multiplied by its length

y{H"SHCD"ImY
y{        mY    For each two character string
H"SHCD"I      0-based index of the second character in the string "SHCD"

:uc5*s!yNd:u;**HH++
:uc5*                 5 points if all cards have same suit
s!               Not all cards have same suit (#)
yNd:u          First four cards have same suit (##)
;         Not a crib hand (###)
**HH++   4 points if (#) and (##) and (###), add to score

yN|Ixs@11#+
yN|I           Index of cards with the same suit of last card (not including itself)
xs@        The rank at these indices
11#     Number of Jacks with the same suit of last card