Какова оценка моей руки Scopa?

14

Мне нравятся проблемы с карточными играми, поэтому я сделал это для итальянской карточной игры Scopa. Моя семья играет в эту игру с незапамятных времен. У него очень интересная система начисления очков, которая должна доставлять удовольствие игрой в гольф. Я отправлю ответ в R, чтобы начать веселье, которое, я уверен, люди улучшат.

Задача: выяснить количество очков, набранных в раунде Скопы, с учетом карт, которые игрок захватил во время раунда, в качестве входных данных.

В колоде Скопа 40 карт. Если вы используете международную колоду, вы удаляете 8, 9 и 10, оставляя A, 2,3,4,5,6,7, Q, J, K в каждой масти. 1 Есть два игрока или партнерства, и после каждого раунда все карты в конечном итоге захватываются одним или другим из двух игроков. Счет считается следующим (более подробная информация здесь ):

  • Игрок с наибольшим количеством карт набирает 1 очко.
  • Игрок с наибольшим количеством алмазов (или монет при использовании итальянской колоды) получает 1 очко.
  • Игрок с 7 бриллиантами (или монетами), известной как сет-белло или красивая семерка, получает 1 очко.
  • Игрок с самой высокой примирой набирает 1 очко. Первичная оценка игрока - это сумма очков карты наибольшего достоинства, которую игрок захватил в каждой масти (см. Таблицу ниже). Если у вас нет хотя бы одной карты в каждой масти, вы проиграете по умолчанию, даже если ваш счет превысит счет вашего оппонента. В чрезвычайно редком случае, когда ни один из игроков не имеет хотя бы одной карты в каждой масти, игрок с более высоким общим количеством очков получает очко. 2

Таблица начальных баллов

| Rank  | Value |
| ----- | ----- |
| 7     | 21    |
| 6     | 18    |
| A     | 16    |
| 5     | 15    |
| 4     | 14    |
| 3     | 13    |
| 2     | 12    |
| Q,J,K | 10    |

Таким образом, игрок может набрать максимум 4 очка за раунд. 3 Если есть галстук, который возможен для карт, алмазов или первобытных очков , никто не набирает очки.

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

Правила вызова

вход

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

Входные данные должны быть в строковом формате, в котором один символ представляет ранг каждой карты, а один символ - ее масть. Это устраняет потенциальную лазейку для прохождения начальных оценок непосредственно в качестве входных данных. Преобразование карточных рангов в начальные баллы должно быть выполнено в программе. Однако вы можете использовать одну строку, разделенную пробелами или запятыми, массивом строк или любым другим форматом. Например, если вы решите кодировать ранги как76A5432QJKи подходит, какDCHSвы могли бы использовать входные данные, такие как['7D', '6H', 'QD', 'JS']или'7D,6H,QD,JS'.

Выход

Целое число от 0 до 4, представляющее счет игрока.

выигрыш

Самый короткий ответ в байтах побеждает!

Контрольные примеры

["7D", "6D", "AD", "5D", "4D", "3D", "2D", "QD", "7C", "6C", "4C", "3C", "2C", "7H", "4H", "2H", "5S", "3S", "QS", "JS", "KS"]

4 : 1 балл за> 20 карт, 1 балл за> 5 бриллиантов, 1 балл за 7 бриллиантов и 1 балл за 78 очков в примире (7,7,7,5, когда у противника 7,6,5, К за 64)

["3D", "7C", "6C", "AC", "5C", "4C", "3C", "2C", "QC", "4H", "7S"]

Набирает 0 : <= 20 карт, <= 5 бриллиантов, нет 7 бриллиантов, и только 69 баллов в примире (7,7,4,3, где у оппонента 7,7,6, К на 70)

[7D", "6D", "AD", "5D", "4D", "3D", "2D", "7C", "6C", "AC", "5C", "4C", "3C", "2C", "7H", "6H", "AH", "5H", "4H", "3H", "2H"]

Результаты 3 : 1 балл за> 20 карт, 1 балл за> 5 бриллиантов, 1 балл за 7 бриллиантов. Primiera будет 63 (7,7,7) и противник может только набрать 51 (7, Q, Q, Q) , но так как эта рука не имеет лопат она теряет точку по умолчанию.

["7D", "6D", "AD", "5D", "4D", "3D", "2D", "QD", "JD", "KD", "QC", "QH", "QS"]

Результаты 3 : <= 20 карт, 1 очко за> 5 бриллиантов, 1 очко за 7 бриллиантов. Primiera только баллы 51 (7, Q, Q, Q) , и противник может набрать 63 (7,7,7) , но так как рука оппонента не имеет алмазов эта рука выигрывает primiera точку по умолчанию.

["7D", "6D", "AD", "5D", "4D", "3D", "2D", "QD", "JD", "KD", "7C", "7H"]

Результаты 3 : <= 20 карт, 1 очко за> 5 бриллиантов, 1 очко за 7 бриллиантов. Несмотря на то, что у этой руки нет пиков, она все равно выигрывает примиру со счетом от 63 до 57 (7,7,7 против 7,6,6), потому что рука противника не имеет бриллиантов.

["7D", "6D", "AD", "5D", "4D", "3D", "2D", "QD", "JD", "KD", "QC", "QH"]

Баллы 2 : <= 20 карт, 1 балл за> 5 бриллиантов, 1 балл за 7 бриллиантов. В этой руке нет пиков, а в руке противника нет бриллиантов. Соперник побеждает примиру со счетом от 63 до 41 (7,7,7 против 7, Q, Q).

[] (пустой массив)

Результаты 0


1: По крайней мере, в нашей семье Джек превосходит «Куин» в Скопе, но это не имеет значения для целей подсчета очков.

2: я играю в эту игру с детства и никогда не видел, чтобы это случилось, но ваш код лучше справится с этим делом!

3: есть бонусные баллы за «зачистки», набранные во время раунда, которые я игнорирую для этой задачи.

qdread
источник
1
Должен ли каждый ранг быть представлен отдельным персонажем?
Дверная ручка
@ Doorknob Нет, не обязательно, но, по крайней мере, в решении, над которым я работаю, я обнаружил, что необходимо иметь уникальный символ для каждого ранга, чтобы все тесты были правильными.
qdread
@ Хороший улов. спасибо
qdread

Ответы:

6

Рубин, 156 153 байта

->a{b='';([a[40],a.scan(/.d/)[5],a=~/;d/,'dchs'.gsub(/./){l=a.scan /.(?=#$&)/;l.size<10&&b+=(';865432'.tr(l*'','')+?0)[0];l.max}.sum>b.sum||p]-[p]).size}

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

->a{
b='';                # stores primiera of other player
([                   # this array stores all checks
a[40],               # check if >20 cards (>40 characters)
a.scan(/.d/)[5],     # check if >5 diamonds
a=~/;d/,             # check if 7 of diamonds
'dchs'.gsub(/./){    # for each suit, build a string with...
l=a.scan /.(?=#$&)/; # find all cards with this suit
l.size<10&&          # if there are less than 10, the other person has some, so
b+=                  # append to their score string the following:
(';865432'           #   start with all the cards
.tr(l*'','')         #   remove the ones we have
+?0)                 #   add back the JQK at the end
[0];                 #   take the highest
l.max}               # return the highest card that we have
.sum                 # take the sum of the codepoints
>b.sum               # check if it's greater than the other player's sum
||p                  # if not, evaluate to nil
]-[p])               # remove all nils
.size}               # count how many are left

Это использует ;865432000для представления 76A5432QJKсоответственно, и костюмы в нижнем регистре. (Выбор символов заключается в том, что вычитание 38 из каждого дает их первичное значение, но на самом деле мы никогда этого не делаем, потому что имеет значение только относительное различие.)

Мы не проверяем, пропускает ли один из игроков костюм, потому что это не нужно - поскольку все карты считаются как 38 плюс их действительное значение, если кто-то пропускает костюм, наибольшее количество очков, которое он может получить, (21 + 38) * 3 = 177, что меньше (10 + 38) * 3 + 21 + 38 = 203 - наименьшее количество очков, которое может получить другой игрок. Мы не можем позволить двум игрокам пропустить неравное ненулевое количество мастей, потому что игрок может пропустить только 0, 1 или 2 масти, а если кто-то пропускает 2 масти, у него есть все карты двух других мастей.

Дверная ручка
источник
4

R, 320 298 265 238 229 224 211 209 179 байт

Это решение в основном благодаря @digEmAll, в форме функции.

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

function(h,S=sum,A=apply,l=99+c(11,8,5:2,6,!1:3)%o%!!1:4)S(S(p<-outer(c(7:2,'A','K','J','Q'),c('D','C','H','S'),paste0)%in%h)>20,S(p[1:10])>5,p[1],S(A(l*p,2,max)-A(l*!p,2,max))>0)

Ниже приведены лучшие из моих старых посредственных попыток на 209 байтов.

редактирование: игра в гольф путем наложения алиасов на некоторые функции, а затем с помощью идеи Дурнкоба о добавлении константы к партитуре вместо проверки мастей.

следующее редактирование: избавился от некоторой избыточности, а затем включил некоторые улучшения от Джузеппе

следующее редактирование: -2 байта благодаря digEmAll

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

function(h,s=sum,l=c(11,8,5:2,6,!1:3)+99)s(length(h)>20,s(grepl('D',h))>5,'7D'%in%h,s(sapply(c('D','C','H','S'),function(i,r=c(7:2,'A','K','J','Q')%in%substr(h[grep(i,h)],1,1))s(l[r][1],-l[!r][1],na.rm=T)))>0)
qdread
источник
1
Вы можете получить помощь в чате для игры в гольф R , digEmAll даже итальянский!
Джузеппе
1
Просто несколько советов, но если вы можете поменять точку с запятой просто новой строкой (которая выглядит как один байт в R), это бесплатный обмен, который сделает ваш ответ более читабельным. Кроме того, проверьте Try It Online, который является онлайн бегунком кода, если у вас его нет. Не требуется, но опять же, приятно использовать. Это может даже генерировать сообщения
CGCC
1
253 байта - я не совсем уверен, что это сработает, поскольку я в основном пробовал обычный набор гольфов, но не стесняйтесь проверять и сообщать мне.
Джузеппе
1
209
digEmAll
2

JavaScript (ES6),  171  163 байта

Принимает ввод как набор карточек, используя их стандартное представление.

c=>(c.size>20)+((g=o=>[..."CHSD"].map(s=>[..."JQK2345A67"].map((v,i)=>(S=o^c.has(v+s))?m="111345679"[++n,i]||12:0,n=m=0)|(n?0:T=1,t-=m),T=t=4)|t*T)(1)>g``)+S+(n>5)

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

комментарии

c =>                                // c = set of cards
  (c.size > 20) + (                 // +1 point if we have more than 20 cards
    ( g = o =>                      // g is a function taking the flag o (for 'opponent')
      [..."CHSD"].map(s =>          // for each suit s, ending with diamonds:
        [..."JQK2345A67"]           //   for each rank v at position i, sorted from
        .map((v, i) =>              //   lowest to highest primiera score:
          (S = o ^ c.has(v + s)) ?  //     if the player owns this card, set S to 1 and:
            m = "111345679"[++n, i] //       increment n; update m to the score of this
                || 12               //       rank (we use the official score - 9)
          :                         //     else:
            0,                      //       do nothing
          n = m = 0                 //     start with n = m = 0
        ) |                         //   end of inner map()
        ( n ? 0 : T = 1,            //   if n = 0, set T to 1
          t -= m ),                 //   subtract m from t
        T = t = 4                   //   start with T = t = 4
      ) | t * T                     // end of outer map(); yield t * T
    )(1) > g``                      // +1 point if g(1) is greater than g(0)
  ) +                               // (we test this way because the scores are negative)
  S +                               // +1 point if we own the 7 of diamonds
  (n > 5)                           // +1 point if we own more than 5 diamonds
Arnauld
источник
2

05AB1E , 41 байт

39ÝsK‚εg9y@Oy0å•Dδ¿m(/d•₆вy.γT÷}è€àO)}`›O

Попробуйте онлайн или проверьте все контрольные примеры .

Костюмы DCHSсоответственно представлены 0123. Звания7A65432KJQ соответственно представлены 0123456789. Они считаются строками, а не целыми числами, как того требует задание (но в любом случае 05AB1E преобразует их в целые числа).

Как и в других решениях, мы добавляем большую константу (14) к каждому баллу примиеры, чтобы сделать ненужной проверку пропущенных мастей.

39Ý                      # range 0..39 (the list of all cards in the game)
   sK                    # remove all elements that appear in the input
      ‚                  # pair with the input: [player's hand, opponent's hand]

ε                     }  # map each hand to a list of its 4 subscores:
 g                       #  first subscore: length (number of cards)
 9y@O                    #  second subscore: count elements <= 9 (diamonds)
 y0å                     #  third subscore: is 0 (representing 7D) in the list
            y.γT÷}       #  group the hand by suit
 •Dδ¿m(/d•₆в      è      #  map each rank to its primiera score
                   ۈ    #  maximum primiera score in each suit
                     O   #  fourth subscore: the sum of those

`›                       # for each subscore: is player's > opponent's?
  O                      # sum
```
Grimmy
источник
2

MS SQL Server 2017 , 525 байт

CREATE FUNCTION f(@ NVARCHAR(MAX))RETURNS TABLE RETURN
SELECT q/21+IIF(d>6,2,IIF(d=6,1,0))+IIF(m=0,IIF(n=0 AND a>b,1,0),IIF(n=0 OR a>b,1,0))p
FROM(SELECT SUM(q)q,MAX(IIF(s='D',q,0))d,SUM(a)a,MIN(q)m,SUM(b)b,MIN(10-q)n
FROM(SELECT s,COUNT(k)q,MAX(IIF(r=k,v,0))a,MAX(IIF(r=k,0,v))b
FROM(SELECT LEFT(value,1)r,s,ASCII(RIGHT(value,1))-38 v
FROM STRING_SPLIT('7;,68,A6,5,4,3,2,Q0,J0,K0',','),(VALUES('D'),('C'),('H'),('S'))s(s))d
LEFT JOIN(SELECT LEFT(value,1)k,RIGHT(value,1)u FROM STRING_SPLIT(@,','))a
ON r+s=k+u GROUP BY s)t)t

Попробуйте это на db <> fiddle .

Андрей Одегов
источник
1

Сетчатка 0.8.2 , 334 байта

$
 ¶234567JQKA
r`.\G
$&C $&D $&H $&S 
+`((\w\w).*¶.*)\2 
$1
T`67AJQK`8960
%O$`(\w)(\w)
$2$1
m`^(?=(...)*)(.C )*(.D )*(.H )*(.S )*
$3;$#1 $#2 $#3 $#4 $#5;${2}${3}${4}$5
m`^(?=(9D))?...;
$#1;
(;(?!.*10).* 0.*;).*
$1
\d[C-S] 
1$&
19\w 
21$*@
\d+(\w )?
$*@
(@)?;(@*) @* (@*).*;(@*)¶@?;((?!\2))?@* @* ((?!\3))?.*;((?!\4))?.*
$#1$#5$#6$#7
1

Попробуйте онлайн! Ссылка включает в себя тестовые случаи. Объяснение:

$
 ¶234567JQKA
r`.\G
$&C $&D $&H $&S 

Создайте список всех 40 карт.

+`((\w\w).*¶.*)\2 
$1

Уберите карты, которые держит игрок.

T`67AJQK`8960

Замените каждый ранг по порядку сортировки, который на 9 7и на 10 меньше его значения для других карт.

%O$`(\w)(\w)
$2$1

Сортируйте карты по масти и рангу.

m`^(?=(...)*)(.C )*(.D )*(.H )*(.S )*
$3;$#1 $#2 $#3 $#4 $#5;${2}${3}${4}$5

Подсчитайте количество карт в каждой масти, а также захватите карту с наивысшим рейтингом в каждой масти, дважды захватив самый высокий бриллиант.

m`^(?=(9D))?...;
$#1;

Проверьте, был ли самый высокий алмаз 7.

(;(?!.*10).* 0.*;).*
$1

Удалите все старшие карты, если в одной из мастей нет карт.

\d[C-S] 
1$&
19\w 
21$*@
\d+(\w )?
$*@

Конвертируйте старшие карты в их одинарный счет и сложите их вместе. Также конвертируйте общее количество карт и длины мастей в одинарные.

(@)?;(@*) @* (@*).*;(@*)¶@?;((?!\2))?@* @* ((?!\3))?.*;((?!\4))?.*
$#1$#5$#6$#7

Наберите очки, если общее количество, алмазы или первобытность, выше.

1

Общая оценка.

Нил
источник
1

AWK , 235 байт

{s[9]=35;s[8]=32;s[7]=30;s[6]=29;s[5]=28;s[4]=27;s[3]=26;s[2]=s[1]=s[0]=24;a[$1 $2]=s[$1]}END{while(i++<4){D=0;for(j=0;j<10;j++){if(a[j i]<1){B[i]=s[j];D++}if(A[i]<a[j i])A[i]=a[j i]}x+=A[i];y+=B[i]}print(20<NR)+(D<5)+(1<a[9 4])+(y<x)}

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

Соответствует карте 1234 (4 - ромбы), значения - 0123456789. Эта программа преобразует контрольные примеры в принятый формат:

BEGIN{RS=", ";FS="";t[7]=9;t[6]=8;t["A"]=7;t[5]=6;t[4]=5;t[3]=4;t[2]=3;t["Q"]=2;t["J"]=1;t["K"]=0;u["D"]=4;u["C"]=1;u["H"]=2;u["S"]=3}{gsub("[\\[\"\\]]","",$0);print t[$1],u[$2]}

Моей целью было просто превзойти ведущую реализацию Python: D

Даниэль Лавин
источник
1

Python 3 , 249 245 239 238 байт

-4 байта благодаря @ovs

-6 байт благодаря @movatica

lambda C:sum([len(C)>20,'7D'in C,len([c for c in C if'E'>c[1]])>5,p(C)>p({n+s for n in'9876543210'for s in S}-C)])
p=lambda C:[not S.strip(''.join(C)),sum(max([(c[1]==s)*int('9gcdefil99'[int(c[0])],22)for c in C]+[0])for s in S)]
S='DcHS'

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

Черная Сова Кай
источник
1
2 байт меньше , с int('0734569c00'[int(x[0])],13)и if x[1]<'E'может быть записана в видеif'E'>x[1]
овс
all(s in''.join(C)for s in S)может быть сокращено до not S.strip(''.join(C))экономии 6 байт
movatica