¿Cuál es el puntaje de mi mano Scopa?

14

Me gustan los desafíos de los juegos de cartas, así que hice este para el juego de cartas italiano Scopa. Mi familia ha estado jugando este juego desde tiempos inmemoriales. Tiene un sistema de puntuación muy interesante que debería ser divertido para el golf. Publicaré una respuesta en R para comenzar la diversión, y estoy seguro de que la gente mejorará.

El desafío: calcular el número de puntos anotados en una ronda de Scopa, dadas las cartas que el jugador capturó durante la ronda como entrada.

Hay 40 cartas en un mazo de Scopa. Si estás usando un mazo internacional, eliminas los 8, 9 y 10, dejando A, 2,3,4,5,6,7, Q, J, K en cada palo. 1 Hay dos jugadores o asociaciones, y después de cada ronda, todas las cartas terminan siendo capturadas por uno u otro de los dos jugadores. El puntaje se cuenta de la siguiente manera (más información aquí ):

  • El jugador con más cartas gana 1 punto.
  • El jugador con más diamantes (o monedas si usa el mazo italiano) obtiene 1 punto.
  • El jugador con el 7 de diamantes (o monedas), conocido como sette bello o beautiful seven, obtiene 1 punto.
  • El jugador con el primiera más alto obtiene 1 punto. El puntaje principal de un jugador es la suma de los puntajes de la carta de mayor valor que el jugador capturó en cada palo (ver la tabla a continuación). Si no tienes al menos una carta en cada palo, pierdes por defecto incluso si tu puntaje excede el puntaje de tu oponente. En el caso extremadamente raro de que ninguno de los jugadores tenga al menos una carta en cada palo, el jugador con el total de primiera más alto gana el punto. 2

Tabla de puntajes primiera

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

Por lo tanto, un jugador puede anotar como máximo 4 puntos en una ronda. 3 Si hay un empate, que es posible para tarjetas, diamantes o primiera , nadie gana el punto.

Es importante darse cuenta de que, dado que cada carta debe ser capturada por uno de los dos jugadores, puede inferir qué cartas debe haber tomado el otro jugador, incluso si solo sabe qué cartas tomó un jugador. Tendrá que hacer esto para puntuar correctamente primiera .

Reglas de desafío

Entrada

Su código debe tomar como entrada las cartas capturadas por un solo jugador durante una ronda de Scopa.

La entrada debe estar en formato de cadena, en el que un personaje representa el rango de cada carta y un personaje su palo. Esto elimina la laguna potencial de pasar laspuntuaciones primarias directamente como entrada. La conversión de los rangos de cartas apuntajes primarios debe hacerse en el programa. Sin embargo, puede optar por utilizar una sola cadena separada por espacios o comas, una matriz de cadenas o cualquier otro formato. Por ejemplo, si elige codificar rangos como76A5432QJKy se adapta comoDCHSpodría usar entradas como['7D', '6H', 'QD', 'JS']o'7D,6H,QD,JS'.

Salida

Un número entero de 0 a 4 que representa la puntuación del jugador.

Victorioso

¡La respuesta más corta en bytes gana!

Casos de prueba

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

Puntuaciones 4 : 1 punto por> 20 cartas, 1 punto por> 5 diamantes, 1 punto por el 7 de diamantes y 1 punto por anotar 78 en primiera (7,7,7,5 donde el oponente tiene 7,6,5, K para 64)

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

Puntuaciones 0 : <= 20 cartas, <= 5 diamantes, no 7 de diamantes, y solo puntúa 69 en primiera (7,7,4,3 donde el oponente tiene 7,7,6, K por 70)

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

Puntajes 3 : 1 punto por> 20 cartas, 1 punto por> 5 diamantes, 1 punto por 7 de diamantes. La primiera sería 63 (7,7,7) y el oponente solo puede anotar 51 (7, Q, Q, Q) pero como esta mano no tiene espadas, pierde el punto por defecto.

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

Puntajes 3 : <= 20 cartas, 1 punto por> 5 diamantes, 1 punto por 7 de diamantes. El primiera solo obtiene 51 (7, Q, Q, Q) y el oponente puede obtener 63 (7,7,7), pero como la mano del oponente no tiene diamantes, esta mano gana el punto primiera por defecto.

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

Puntajes 3 : <= 20 cartas, 1 punto por> 5 diamantes, 1 punto por 7 de diamantes. Aunque esta mano no tiene espadas, aún gana primiera por un puntaje de 63 a 57 (7,7,7 versus 7,6,6) porque la mano del oponente no tiene diamantes.

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

Puntajes 2 : <= 20 cartas, 1 punto por> 5 diamantes, 1 punto por 7 de diamantes. Esta mano no tiene espadas, y la mano del oponente no tiene diamantes. El oponente gana primiera por un puntaje de 63 a 41 (7,7,7 versus 7, Q, Q).

[] (matriz vacía)

Puntuaciones 0


1: Al menos en nuestra familia, Jack supera a Queen en Scopa, pero esto es irrelevante para fines de puntuación.

2: He estado jugando a este juego desde la infancia y nunca he visto que eso suceda, ¡pero es mejor que tu código pueda manejar ese caso!

3: Hay puntos de bonificación por "barridos" anotados durante la ronda que estoy ignorando a los efectos de este desafío.

qdread
fuente
1
¿Cada rango tiene que estar representado por un personaje distinto?
Pomo de la puerta
@Doorknob No, no necesariamente, pero al menos en la solución en la que estoy trabajando me pareció necesario tener un personaje único para cada rango para obtener todos los casos de prueba correctos.
qdread
@ Grimy buena captura. gracias
qdread

Respuestas:

6

Rubí, 156 153 bytes

->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}

Pruébalo en línea!

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

Esto se usa ;865432000para representar 76A5432QJKrespectivamente, y los trajes están en minúsculas. (La elección de los caracteres se debe a que restar 38 de cada uno da su valor principal, pero en realidad nunca lo hacemos porque solo importa la diferencia relativa).

No verificamos si a ninguno de los jugadores le falta un palo porque es innecesario, ya que todas las cartas se cuentan como 38 más su valor real, si a alguien le falta un palo, la puntuación más alta que puede obtener es (21 + 38) * 3 = 177, que es menor que (10 + 38) * 3 + 21 + 38 = 203, el puntaje más bajo que puede obtener el otro jugador. No podemos hacer que los dos jugadores pierdan un número desigual de palos distintos de cero, porque a un jugador solo le pueden faltar 0, 1 o 2 palos, y si a alguien le faltan 2 palos, tienen todas las cartas de los otros 2 palos.

Pomo de la puerta
fuente
4

R, 320 298 265 238 229 224 211 209 179 bytes

Esta es una solución principalmente debido a @digEmAll, en forma de una función.

Pruébalo en línea!

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)

A continuación se muestra el mejor de mis viejos intentos mediocres de 209 bytes.

editar: jugar golf aliasing algunas funciones, luego tomando la idea de Doorknob de agregar una constante a la puntuación en lugar de verificar los palos.

próxima edición: se deshizo de la redundancia y luego incorporó algunas mejoras de Giuseppe

próxima edición: -2 bytes gracias a digEmAll

Soy terrible en esto, así que estoy seguro de que alguien puede mejorar en esto si les importa tomarse el tiempo. Me siento como el sapplyyfunction son muy largos y podría deshacerme de ellos, pero no puedo entender cómo. Las entradas son cadenas de dos caracteres en la notación estándar.

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
fuente
1
Es posible que pueda obtener ayuda en la sala de chat de golf R , ¡digEmAll es incluso un compañero italiano!
Giuseppe
1
Solo un consejo, pero si puede intercambiar un punto y coma solo una nueva línea (que parece ser un byte en R), es un intercambio gratuito que hace que su respuesta sea más legible. Además, echa un vistazo a Try It Online, que es un corredor de código en línea si no lo has hecho. No es obligatorio, pero de nuevo, agradable de usar. Incluso puede generar publicaciones
CGCC
1
253 bytes : no estoy totalmente seguro de que esto funcione, ya que estaba probando la mayoría de las veces los juegos de golf habituales, pero siéntase libre de probar y avisarme.
Giuseppe
1
209
digEmAll
2

JavaScript (ES6),  171  163 bytes

Toma datos como un conjunto de tarjetas, utilizando su representación estándar.

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)

Pruébalo en línea!

Comentado

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
fuente
2

05AB1E , 41 bytes

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

Pruébelo en línea o verifique todos los casos de prueba .

Los trajes DCHSestán representados respectivamente por 0123. Rangos7A65432KJQ están representados respectivamente por 0123456789. Esos se toman como cadenas, no enteros, como lo requiere el desafío (pero 05AB1E los convierte en enteros cuando sea necesario de todos modos).

Como en otras soluciones, agregamos una constante grande (14) a cada puntaje primiera para hacer innecesaria la verificación de los trajes faltantes.

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
```
Mugriento
fuente
2

MS SQL Server 2017 , 525 bytes

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

Pruébalo en db <> fiddle .

Andrei Odegov
fuente
1

Retina 0.8.2 , 334 bytes

$
 ¶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

Pruébalo en línea! El enlace incluye casos de prueba. Explicación:

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

Crea una lista de las 40 cartas.

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

Retira las cartas que tiene el jugador.

T`67AJQK`8960

Reemplace cada rango por su orden de clasificación, que es 9 para 7y 10 menos que su valor para otras cartas.

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

Ordenar las cartas por palo y rango.

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

Cuente el número de cartas en cada palo y también capture la carta mejor clasificada en cada palo, capturando el diamante más alto dos veces.

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

Compruebe si el diamante más alto fue el 7.

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

Elimina todas las cartas más altas si uno de los palos no tiene cartas.

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

Convierta las cartas más altas a su puntaje unario y sumelas. También convierta el número total de tarjetas y longitudes de palo a unario.

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

Gana puntos si el total, diamantes o primiera, es mayor.

1

Total de la puntuación.

Neil
fuente
1

AWK , 235 bytes

{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)}

Pruébalo en línea!

Los trajes se asignan a 1234 (4 son diamantes), los valores se asignan a 0123456789. Este programa transforma los casos de prueba en el formato aceptado:

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]}

Mi objetivo era simplemente vencer a la implementación líder de Python: D

Daniel LaVine
fuente
1

Python 3 , 249 245 239 238 bytes

-4 bytes gracias a @ovs

-6 bytes gracias a @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'

Pruébalo en línea!

Black Owl Kai
fuente
1
2 bytes menos con int('0734569c00'[int(x[0])],13)y if x[1]<'E'se puede escribir comoif'E'>x[1]
ovs
all(s in''.join(C)for s in S)se puede acortar a not S.strip(''.join(C)), ahorrando 6 bytes
movatica