该列表中有多少个二十一点序列?


21

您的任务是查找在12张卡的有序列表中可以找到多少个不同的21点序列。

二十一点序列被定义为连续的卡序列,其点的总和正好为21。点的计数根据下表进行:

Symbol | Name  | Points     Symbol | Name  | Points
-------+-------+--------    -------+-------+--------
   2   | Two   | 2             9   | Nine  | 9
   3   | Three | 3             T   | Ten   | 10
   4   | Four  | 4             J   | Jack  | 10
   5   | Five  | 5             Q   | Queen | 10
   6   | Six   | 6             K   | King  | 10
   7   | Seven | 7             A   | Ace   | 1 or 11
   8   | Eight | 8

输入项

使用上述符号的12个字符的字符串。我们不在乎卡的颜色,因此不提供它们。

例:

K6K6JA3Q4389

输出量

在输入字符串中可以找到的不同的21点序列的数量。

例:

K6K6JA3Q4389 包括两个不同的二十一点序列:

例

  • JA,其中A计为11分(10 + 11 = 21)
  • A3Q43,其中A计为1点(1 + 3 + 10 + 4 + 3 = 21)

所以答案是2

规则

  • 如果两个大酒杯序列包含不同的卡或不同顺序的相同卡,则认为它们是不同的。如果完全相同的序列出现在输入列表的不同位置,则必须仅计数一次。
  • 二十一点序列可能会相互重叠。
  • 每种卡依次显示最多12次。(我们假设这些卡是从至少3个不同的卡组中选取的。)
  • 如果在输入字符串中找不到二十一点序列,则必须返回0或任何其他虚假值。
  • 这是代码高尔夫球,因此最短的答案以字节为单位。禁止出现标准漏洞。

测试用例

提供这些序列仅供参考,但只需要输出它们的数量即可。

Input        | Output | Distinct sequences
-------------+--------+--------------------------------------------------------
3282486Q3362 | 0      | (none)
58A24JJ6TK67 | 1      | 8A2
Q745Q745Q745 | 1      | Q74
AAAAAAAAAAAA | 1      | AAAAAAAAAAA
T5AQ26T39QK6 | 2      | AQ, 26T3
JQ4A4427464K | 3      | A442, 44274, 7464
Q74Q74Q74Q74 | 3      | Q74, 74Q, 4Q7
37AQKA3A4758 | 7      | 37A, 37AQ, AQ, AQK, QKA, KA, A3A475
TAQA2JA7AJQA | 10     | TA, TAQ, AQ, QA, A2JA7, 2JA7A, JA, AJ, AJQ, JQA
TAJAQAKAT777 | 13     | TA, TAJ, AJ, JA, JAQ, AQ, QA, QAK, AK, KA, KAT, AT, 777

1
嗯,不应该将序列限制为5个以下的长度吗?
乔纳森·艾伦

@JonathanAllan很好。我认为那确实是赌场的极限。但这不是真正的二十一点游戏。相反,我选择将输入限制为12张卡,这样许多A不需要太多的计算时间。听起来还可以吗?
Arnauld

下一个挑战:查找具有最独特二十一点序列的12个字符的字符串:D
ETHproductions's

将输入限制为10张卡片会容易得多...
Neil

@Neil好吧,这将使“十一王牌”案不可能成为现实,但背后是否真的有重大的优化?我想您可能还有其他想法。
Arnauld

Answers:


6

果冻30 29 字节

1e×5,⁵Ḥ‘
O_48«26%⁴µSeÇ
ẆÇÐfQL

在线尝试!或签出测试套件

怎么样?

请注意,如果我们始终将ace的值设为1,则唯一有效的和为2111,如果序列中出现ace,则后者是可以接受的。

ẆÇÐfQL - Main link: string
Ẇ      - all non-empty contiguous sublists
  Ðf   - filter keep if...
 Ç     -     last link (2) as a monad ...is truthy
    Q  - unique results
     L - length

O_48«26%⁴µSeÇ - Link 2, isBlackjackSubtring: char array  e.g. ['A','2','8','Q']
O             - cast to ordinal values                        [ 65, 50, 56, 81]
 _48          - subtract 48                                   [ 17,  2,  8, 33]
     26       - 26
    «         - minimum (vectorises)                          [ 17,  2,  8, 26]
        ⁴     - 16
       %      - modulo                                        [  1,  2,  8, 10]
         µ    - monadic chain separation (call the result v)
          S   - sum(v)                                        21
            Ç - last link (1) as a monad link_1(v)            [11,21]
           e  - exists in?                                    1

1e×5,⁵Ḥ‘ - Link 1 validSums: value list (where A is 1, and {T,J,Q,K} are 10)
1e       - 1 exists in? (are there any aces? Yields 1 or 0)
  ×5     - multiply by 5 (5 or 0)
     ⁵   - 10
    ,    - pair ([5,10] or [0,10])
      Ḥ  - double ([10,20] or [0,20])
       ‘ - increment ([11,21] or [1,21])
         -                        ^
         -     note: if no ace is in the sequence it's sum can't be 1 anyway

7

Python 2,215字节

def b(s,a=[],r=range):
 S=map(lambda x:":">x>"1"and int(x)or 10-(x=="A")*9,s)
 for i in r(12):
  for j in r(13):
   if 21in[x*10+sum(S[i:j])for x in r(S[i:j].count(1)+1)]and s[i:j]not in a:a+=s[i:j],
 return len(a)

添加的评论:

def b(s,a=[],r=range):                                      # Define the function b and a list, a, which holds all the blackjack sequences
 S=map(lambda x:":">x>"1"and int(x)or 10-(x=="A")*9,s)      # Set S to the score of each card in b
 for i in r(12):                                            # Loop with i from 0 to 11
  for j in r(13):                                           # Loop with j from 0 to 12
   if 21in[x*10+sum(S[i:j])for x in r(S[i:j].count(1)+1)]\  # If 21 is included in all the possible sums that the scores between i and j in S can be
           and s[i:j]not in a:                              # And that sequence is not already included,
               a+=s[i:j],                                   # Append that sequence to a
 return len(a)                                              # Return the amount of elements in a

3

Python134130字节

lambda x:len({x[i:j]for i in range(12)for j in range(13)if sum(min(26,ord(c)-48)%16for c in x[i:j])in([11,21][~('A'in x[i:j]):])})

在线尝试!

怎么样?

一个未命名的函数,将长度为12的字符串作为x

x[i:j]是从第i + 1的串的切片到第j 字符。

切片采取这样的,我们必须通过遍历所有子列表来自i=0i=11for i in range(12),对于每一个我们从穿越j=0j=12for j in range(13)

(我们只需要j=i+1up,但是带有j<=i的slice 只是空字符串,因此我们可以从剥离4个字节for j in range(i+1,13)

对于具有正确总和的那些过滤器...

如果一个切片中有ace,则有效和为11和21,否则为21。'A'in x[i:j]向我们提供此信息并~(v)执行-1-v,我们将其用于切片[11,21]-因此,如果一个ace在我们获得的序列中[11,21][-2:],如果我们不获得[11,21][-1:],则分别得到[11,21][21]

本身需要治疗的总和A为1,数字作为其值,并且TJQ,和K为10。这种映射是通过首先铸造到序数来实现的:
" 2 3 4 5 6 7 8 9 T J Q K A"(无空格)变为
[50, 51, 52, 53, 54, 55, 56, 57, 84, 74, 81, 75, 65]减去48得到
[ 2, 3, 4, 5, 6, 7, 8, 9, 36, 26, 33, 27, 17],取min26个产率
[ 2, 3, 4, 5, 6, 7, 8, 9, 26, 26, 26, 26, 17],和mod(%)十六,这是
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 1]求和的sum(...)

将过滤后的结果放入的集合中{...},因此仅保留唯一的结果,长度len(...)即为计数


3

05AB1E39 38 37字节

'A1:vTy‚ydè})ŒvyO¸y1åiDT+ì}21å})¹ŒÏÙg

在线尝试!

说明

'A1:                  # replace A with 1 in input

v      }              # for each card
 Ty‚                  # pair 10 and the card
    yd                # check if the card is a digit
      è               # use this to index into the pair, giving 10 for JQK
        )             # wrap in list
                      # we now have a list of cards as numbers in range [1 ... 10]

Œv               }    # for each sublist
  yO¸                 # create a list with the sum of the sublist
     y1åi    }        # if the sublist contain 1
         DT+ì         # add sum+10 to the list
              21å     # check if 21 is in that list
                  )   # wrap in list
                      # we now have a list with 1 where the sublist sums to 21 and
                      # 0 otherwise

¹Œ                    # get sublists of the input
  Ï                   # keep only those which sum to 21
   Ù                  # remove duplicates
    g                 # count the number of lists

3

JavaScript(ES6),123字节

f=
t=>eval("for(s=new Set,i=0;t[i];i++)for(a=0,b=21,j=i;c=t[j++];b&&b-a*10||s.add(t.slice(i,j)))b-=+c||(c>'A'?10:a=1);s.size")
<input oninput=o.textContent=/[^2-9TJQKA]/.test(this.value)?'':f(this.value)><pre id=o>


伟大的想法,但这种回报0AAAAAAAAAAAA,而不是1。(A可以同时是1和11)
ETHproductions '17

通过组合我们的两个条目,您可以获得s=>eval("q=new Set;for(i=0;s[i];i++)for(t=A=0,j=i;c=s[j++];t==21|t==11&A&&q.add(s.slice(i,j)))t+=+c||(c<'B'?A=1:10);q.size")124个字节
ETHproductions

@ETHproductions从21开始似乎仍然为我节省了一个字节。
尼尔

@ETHproductions ...如果我发布正确的字节数也确实有帮助...
Neil

3

的JavaScript(ES6),144个 138 129 128 126 124字节

g=([c,...s],a=[],q=new Set)=>c?g(s,[...a,[,21]].map(([x,y,A])=>[x+=c,y-=+c||(c<'B'?A=1:10),A,y&&y^10*A||q.add(x)]),q):q.size

128的旧尝试:

s=>(q=new Set,f=s=>s?f(s.slice(1))&f(s.slice(0,-1))&[...s].map(c=>t+=-c||~(c<'B'?A=0:9),t=A=21)|t&&t-10*!A?q:q.add(s):q)(s).size

s.search`A`>-1可能是~s.search`A`
路加福音

@Luke,不,实际上,因为它返回的值例如-21&-2 == 0
ETHproductions

真正。也许设置t0.slice(0,-1)通话(保存2B)?
路加福音

@Luke我认为这不起作用,因为t全局变量不会起作用,并且由于对的调用而将其重置f(s.slice(0,-1))。但是我找到了解决方法s.search`A`>-1:-)
ETHproductions's

我很想知道打完高尔夫球后会得到什么。我现在似乎停留在113。
Arnauld

3

JavaScript(ES6),112字节

f=(s,x=[k=0])=>s?f(s.slice(1),x,[...s].map(c=>x[t+=+c||10^(c<'B'?a=11:0),b+=c]||t-21&&t-a?0:x[b]=++k,a=b=t=0)):k

此代码逻辑与ETHproductionsNeil的现有JS答案中使用的代码逻辑非常相似。但是它使用的是基本数组来跟踪遇到的二十一点序列,而不是Set

格式化和评论

f = (                     // given:
  s,                      //  - s = list of cards
  x = [k = 0]             //  - x = array of Blackjack sequences
) =>                      //  - k = number of distinct Blackjack sequences 
  s ?                     // if s is not empty:
    f(                    //   do a recursive call:
      s.slice(1),         //     starting at the next card in the list
      x,                  //     without re-initializing x[]
      [...s].map(         //   for each card 'c' in the list:
        c => x[           //
          t+ =            //   update the total number of points:
            +c ||         //     using the number of the card (for 2 ... 9)
            10 ^ (        //     or using 10 for all other cards
              c < 'B' ?   //     except the Ace which is
                a = 11    //     counted as 1 point and sets 'a' to 11
              :           //     (which means that a total number of points
                0         //     of 11 will be considered valid from now on)
            ),            //
          b += c          //   update the current sequence 'b'
        ] ||              //   if x[b] was previously stored as a Blackjack sequence
        t - 21 &&         //   or the total number of points is not equal to 21
        t - a ?           //   and not equal to 'a':
          0               //     do nothing
        :                 //   else:
          x[b] = ++k,     //     store the current sequence in x[] and increment k
        a = b = t = 0     //   initialization of all variables used in map()
      )                   //
    )                     //
  :                       // else:
    k                     //   return k

测试用例


我尝试了两次递归,在字符串中向后移动,随着每个字符的使用,累积计算每个可能的字符串……而最短的方法只是遍历每个片段。好东西!(如果我正确计算的话,使用Set似乎要长三个字节)
ETHproductions's

2

05AB1E40 39 38 37 36字节

-4感谢Emigna

Ç<çJŒÙ'@0:[Ž„èµJuS9:S>D1å2‚T*>sOå½]¾

在线尝试!

Ç<ç                                  # decrement characters by 1
   JŒÙ                               # get all unique substrings
      '@0:                           # replace @ (was A) with 0
          [Ž                      ]  # for everything on the stack
            „èµJuS9:                 # replace what was T,J,Q,K with 9
                    S>D              # increment all values
                       1å2‚T*>       # push [11,21] if there was an A, [1,21] otherwise
                              sO     # sum the values of the cards
                                å½   # increment the counter_variable if the sum 
                                     # is in the array
                                   ¾ # end loop and push (print) the counter_variable

我们需要进行减量->子字符串->增量操作,以使面部卡用一个数字表示。


解决两位数的好方法!您可以删除第一个字符串SÇ将其转换为字符代码列表。
Emigna

另外,"SIPJ"可能是„èµJu
Emigna

@Emigna谢谢。我以为有办法做到这一点,但在文档中找不到如何使用。
莱利

您可以再保存2个字节,将其重写为,Ç<çJŒÙ'@0:)vy„èµJuS9:S>D1å2‚T*>sOå}O然后比我的答案短1个字节:)
Emigna

@Emigna这是相同的字节数,更像是我的原始字节数。
莱利

1

+ UNIX实用程序,145个 142 141字节

for n in {9..155}
{ echo ${1:n%12:n/12};}|sort -u|sed 's/\(.\)/+\1/g;s/A/{1,11}/g;s/[J-T]/10/g;s/^/eval echo $[0/;s/$/]/'|sh|grep -c '\<21\>'

在线尝试!

测试运行:

for x in 3282486Q3362 58A24JJ6TK67 Q745Q745Q745 AAAAAAAAAAAA T5AQ26T39QK6 JQ4A4427464K Q74Q74Q74Q74 37AQKA3A4758 TAQA2JA7AJQA TAJAQAKAT777
  do
    echo -n "$x "
    ./21 "$x"
  done

3282486Q3362 0
58A24JJ6TK67 1
Q745Q745Q745 1
AAAAAAAAAAAA 1
T5AQ26T39QK6 2
JQ4A4427464K 3
Q74Q74Q74Q74 3
37AQKA3A4758 7
TAQA2JA7AJQA 10
TAJAQAKAT777 13

1

PHP,240字节

$a=str_split($argv[1]);foreach($a as$k=>$v)$n[$k]=$v=='A'?1:($v==0?10:$v);for($i=0;$i<=$k;$i++){$s=$a[$i];$r=$n[$i];for($j=$i+1;$j<=$k;$j++){$s.=$a[$j];$r+=$n[$j];if ($r==21||($r==11&&stristr($s,'A')))$f[]=$s;}}echo count(array_unique($f));

松散

$a = str_split($argv[1]);
foreach ($a as $k=>$v)
    $n[$k] = $v == 'A' ? 1 : ($v == 0 ? 10 : $v);
for ($i=0; $i<=$k; $i++) {
    $s = $a[$i];
    $r = $n[$i];
    for ($j=$i+1; $j<=$k; $j++) {
        $s .= $a[$j];
        $r += $n[$j];
        if ($r == 21 || ($r == 11 && stristr($s,'A')) )
            $f[] = $s;
    }
}
echo count(array_unique($f));

在这里尝试!


1
很奇怪,我可以说它在我的本地测试中奏效了,但看来您是对的。无论如何; 问题来自$i未声明的事实。添加了4个字节,它运行完美。
roberto06年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.