让我们玩Rummikub!


11

注意:这与游戏Rummikub的变体有关


背景与规则

Rummikub是一款基于图块的游戏。有四种颜色:红色,橙色,蓝色和黑色。对于每种颜色,有13个磁贴(标记为1到13),并且还有2个与颜色无关的小丑,因此共有54件。在Rummikub的这种变体中,每位玩家获得14个磁贴,并且每局必须再获得一个磁贴,然后每回合再丢一枚,这样磁贴数是恒定的。玩家看不到彼此的瓷砖。目标是对图块进行分组,以使所有块至少属于一组(请参见下文)。当玩家将所有棋子分组时,他们放下棋盘并露出棋子。然后其他人检查所有组合是否有效,如果有效,则玩家赢得该回合。

瓷砖如何分组?

组只有两种类型:

  • 多色组:

    • 它们由3或4个图块组成。
    • 它们仅包含编号相同的图块。
    • 所有的瓷砖都是不同的颜色。
    • 范例:RED 9, BLUE 9, BLACK 9
  • 单色组:

    • 它们至少包含3个图块。
    • 它们不能包含超过13个图块。
    • 它们仅包含具有升序排列的不同连续编号的图块。
    • 所有图块都具有相同的颜色。
    • 1 有的图块可能不会位于标有的图块之后13
    • 范例:RED 5, RED 6, RED 7

等等,小丑们做什么?

小丑可以代替游戏中的任何一块。例如,我们的第一个例子可以成为 JOKER, BLUE 9, BLACK 9RED 9, JOKER, BLACK 9RED 9, BLUE 9, JOKER。这同样适用于我们的其他示例。但是,一个人可能不会将两个Joker放在同一组中,因此JOKER, ORANGE 8, JOKER禁止类似的事情。


任务

给定一个Rummikub切片组,确定它是否有效。您可以确保不会出现重复的图块,除了两个小丑,而且您输入的图块是有效的(例如,60不会出现类似的内容)。

输入输出

您可以采用任何标准方法输入并提供输出。

一些有效的输入格式:字符串列表,元组列表,嵌套列表,字符串或您认为合适的其他任何格式。颜色可以作为字符串(例如:)"Blue","Red", etc.,字符串的缩写(请区分蓝色和黑色图块)或与颜色对应的整数。说到Jokers,您应该提及程序将其作为输入接收的方式。如果选择字符串,则可能会有类似的内容RED 9, JOKER, ...,如果选择可以包含的元组(9,"RED"), ("JOKER")或类似的内容。如果有帮助,您可能会收到该小丑的颜色(这不会影响程序的输出)。例如,您可能有("JOKER","RED")("JOKER","BLUE"),但这不应以任何方式影响输出。

关于输出,适用于标准规则。

工作的例子

让我们举个例子,希望可以使它更容易理解。给定如下一组,其中每个元组代表一个图块:

[(9,“ RED”),(9,“ ORANGE”),(“ JOKER”),(9,“ BLACK”)]

这将返回真实值,因为输入有效。在这种情况下,小丑将替代(9, "BLUE"),它们形成了一个多色组。

如果可以给您以下小组:

[(9,“ BLUE”),(9,“ ORANGE”),(9,“ RED”),(9,“ BLACK”),(“ JOKER”)]

这将是无效的,因此您的程序应返回假值,因为没有多余的空白可供小丑替换,因为多色组中的最大纸牌数为4。

其他测试用例

这些是针对扩展的测试套件的,它涵盖了几乎所有可能的情况:

输入->输出 

[(1,“蓝色”),(2,“蓝色”),(3,“蓝色”),(4,“蓝色”),(5,“蓝色”),(6,“蓝色”)]]- >诚实

[(6,“ BLUE”),(6,“ RED”),(6,“ BLACK)]->真实

[(5,“黑色”),(6,“黑色”),(7,“黑色”),(8,“黑色”),(9,“黑色”),(10,“黑色”),( “ JOKER”),(12,“ BLACK”)]->真实 

[(“ JOKER”),(3,“ BLUE”),(3,“ RED”)]->真实

[(8,“ BLACK”),(2,“ RED”),(13,“ BLUE”)]->虚假

[(4,“ RED”),(3,“ RED”),(5,“ RED”)]->虚假

[(5,“ BLACK”),(6,“ BLACK)]->虚假

[(“ JOKER”),(5,“ RED”),(“ JOKER”)]->虚假

[(4,“ RED”),(5,“ RED”),(6,BLUE“)]->虚假

[(4,“ RED”),(“ JOKER”),(5,“ RED”)]->虚假

[(12,“ BLACK”),(13,“ BLACK),(1,” BLACK“)]->虚假

这是,因此每种语言中以字节为单位的最短代码胜出!



偷窃是rummikub最好的部分。即使没有,这看起来也是一个有趣的挑战。
约西亚

[]有效输入吗?
V. Courtois

@ V.Courtois当然。
Xcoder先生17年

1
@ V.Courtois 一个人可能不会在同一个组中放置两个 Joker ,因此两个包含2个Joker的输入是虚假的。
Xcoder先生17年

Answers:


6

APL(Dyalog),58字节

将颜色列表(1-4)作为右参数,并将数字列表作为左参数。表示小丑号(⍳4),它等同(1 2 3 4)于表示它可以是任何一个。同样,其颜色也表示(⍳13)可能是1到13之间的任何数字。

{(3≤≢⍺)∧((s⍵)∧⍺≡∪⍺)∨((s←{1∊≢∘∪¨⊃,¨/⍵})⍺)∧∨/∊(⊃,¨/⍵)⍷¨⊂⍳13}

在线尝试!

算法

存在三个条件,其中后两个条件分别具有两个条件:

  1. 行程长度必须大于或等于3

和其他

    1. 一个数字AND

    2. 独特的色彩

要么

    1. 单一颜色AND
    2. 序号

为了使运行有效。

阅读顺序

3≤3小于或等于≢⍺瓦片数

   s⍵ 所有数字都相同

  

   ⍺≡∪⍺ 颜色是独特的

要么

   1∊1是≢∘∪¨独特的⊃,¨/展开 颜色的数量

  

   ∨/在所有⊃,¨/⍵展开的数字中至少存在⍷¨⊂一个,在⍳131到13中找到一个

完整代码说明

{} 匿名函数,其中左参数为右参数

3.2。

⍳13 数字1到13

()⍷¨找到以下每个运行的起始位置:

  ,¨/⍵ 连接数字的每个元素(为每个Joker值创建一个运行)

   披露(因为/降低排名)

  ε NLIST(扁平化)

∨/ 或减少(即是真的吗?)

()∧ 并且:

3.1

  ()⍺ 在颜色列表上应用以下功能的结果:

   s←{...... }小号(对于小号 AME),这是下面的匿名函数(参数):

    ,¨/⍵ 连接每个元素(为每个Joker值创建一个运行)

     披露(因为/降低排名)

    ≢∘∪¨ 每个列表中唯一元素的数量

    1∊ 是一个会员吗?(即是否有所有相同的列表?)

()∨或:

2.2。

  ∪⍺ 独特的色彩

  ⍺≡ 与颜色相同(即它们是唯一的)

  ()∧ 并且:

2.1。

   s⍵ 数字都一样

  ()∧并且

1。

   ≢⍺ 颜色数(即瓷砖数)

   3≤ 三个小于或等于那个


1
哇,APL似乎是应对这一挑战的绝佳工具
Xcoder先生17年

3

果冻41 40 38 36字节

EȧI=1ȦȯE
0,W€yµZç/ɓQ⁼⁸ȧ
L>2ȧ4p13ðç€Ṁ

在线尝试!(带有测试套件页脚)

将输入作为(color, value)常规0磁贴和小丑的数组。颜色以整数表示(尽管我不确定当前代码是否重要)。

输出1(真实)或0(虚假)。

说明

L>2ȧ4p13ðç€Ṁ    Main link, checks if a sequence is valid. Args: sequence
L                 Get the length of the sequence.
 >2               Check if it's at least 3 tiles.
   ȧ4             And: yield 4 if it is, 0 otherwise.
     p13          Cartesian product: yield all possible tiles if
                  result was 4, empty array otherwise.
        ð         Begin a new dyadic chain with args (tiles, sequence).
         ç€       Call the first helper link for each tile with args (tile, sequence).

0,W€yµZç/ɓQ⁼⁸ȧ    First helper link, checks if a sequence is valid if jokers
                  are substituted for the given tile. Args: tile, sequence
0,                  Make a pair [0, tile].
  W€                Turn that into [[0], [tile]].
    y               Map all 0's (jokers) into tile in the sequence.
     µ              Begin a new monadic chain with args (sequence).
      Z             Transpose to get list [colors, values].
       ç/           Call the second helper link with args (colors, values).
         ɓ          Begin a new dyadic chain with args (sequence, valid).
          Q         Remove duplicate tiles from the sequence.
           ⁼⁸       Check if the sequence is unchanged (i.e. there were no duplicates).
             ȧ      And with the output of the second helper.

EȧI=1ȦȯE    Second helper link, checks if a sequence is valid assuming no duplicates.
            Args: colors, values
E             Check if all the colors are the same.
 ȧ            Logical and with the values array.
              Yields the values if they were, 0 if not.
  I           Find the differences between each value.
              Yields [] if the colors differed.
   =1         See if each difference is equal to 1.
              Yields [] if the colors differed.
     Ȧ        Check if the list was nonempty and all values were truthy.
              Yields 1 for valid mono-colors, 0 otherwise.
      ȯ       Logical or with the values array.
              Yields 1 for valid mono-colors, the values otherwise.
       E      Check if all the values are the same. For valid mono-colors
              this tests if all items of [1] are equal (obviously true).
              Yields 1 for valid sequences, 0 otherwise.

我认为您必须输出一致的真实/错误。
亚当

@Adám编辑,所幸没有影响字节数。
PurkkaKoodari

2

Python 2中371个370 362 341 329 325字节

  • @ Mr.Xcoder保存1个字节:str.split()代替list literal
  • 保存8个字节:的简写 len(x)-1
  • 保存19个字节:J O BK B R用于Joker, Orange, Black, Blue, Red文字
  • @ Mr.Xcoder还保存了12个字节,谢谢!
  • 由于@ Mr.Xcoder,另外还有4个字节
def f(x):
 j=sum("J"in i for i in x);z=len(x)-1
 if j>1or z<2:return False
 if j<1:return(all(i[0]==x[0][0]for i in x)and sum(i[1]==x[0][1]for i in x)<2)or(all(i[1]==x[0][1]for i in x)and sum(int(x[m+1][0])==int(x[m][0])+1for m in range(z))==z)
 return any(f([[k,(i+1,j)]["J"in k]for k in x])for j in'RBbO'for i in range(13))

在线尝试!




1
实际上,这节省了比我想象的要多得多的字节:329
Xcoder先生17年

1
325个字节。对不起,很晚的改进。
Xcoder先生17年

1

Javascript(ES6),286个字节

var testcases = [[{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"},{n:4,c:"BLUE"},{n:5,c:"BLUE"}, {n:6,c:"BLUE"}],[{n:6,c:"BLUE"},{n:6,c:"RED"},{n:6,c:"BLACK"}],[{n:5,c:"BLACK"},{n:6,c:"BLACK"},{n:7,c:"BLACK"},{n:8,c:"BLACK"},{n:9,c:"BLACK"},{n:10,c:"BLACK"},{n:0,c:"JOKER"},{n:12,c:"BLACK"}],[{n:0,c:"JOKER"},{n:3,c:"BLUE"},{n:3,c:"RED"}],[{n:8,c:"BLACK"},{n:2,c:"RED"},{n:13,c:"BLUE"}],[{n:4,c:"RED"}, {n:3,c:"RED"}, {n:5,c:"RED"}],[{n:5,c:"BLACK"}, {n:6,c:"BLACK"}],[{n:0,c:"JOKER"},{n:5,c:"RED"},{n:0,c:"JOKER"}],[{n:4,c:"RED"},{n:5,c:"RED"},{n:6,c:"BLUE"}],[{n:4,c:"RED"},{n:0,c:"JOKER"},{n:5,c:"RED"}],[{n:12,c:"BLACK"},{n:13,c:"BLACK"},{n:1,c:"BLACK"}],[{n:11,c:"BLACK"},{n:12,c:"BLACK"},{n:0,c:"JOKER"}],[{n:1,c:"BLACK"},{n:2,c:"BLACK"},{n:3,c:"BLACK"},{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"}]];

g=a=>a.length
j=a=>a.n==0
l=(x,y)=>x.c==y.c||j(x)||j(y)
a=s=>g(s)>2&&([q=[0],x=s[0],s.map(y=>q[0]+=x==y||((l(x,y)||x.n==y.n)&&!(j(x)&&j(y)))&&(([n=s.indexOf(y),n<1||([x=s[n-1],!l(x,y)||y.n>0&&x.n<y.n])[1]||(n<g(s)-1&&x.n+1<s[n+1].n)||(n==g(s)-1&&y.n==0&&x.n<13)])[1])?1:0)])[0][0]==g(s)

testcases.forEach(H=>console.log(a(H)));

(请注意,上面的测试用例还包含两个不在问题中的测试用例:它们分别为true和false:有关可读性,请参见ungolf版本。)

粗加工:

 Using first tile x:
   For each tile y:
     count for x: can group with y
 return: x matches n tiles, where n is the number of tiles

笑话用0数字表示(负数也可以);这样可以使输入结构保持一致(同时具有颜色和值),并且不必依赖于检查是否c=="JOKER"节省了7个字节。

可能会删除一些括号,可能无法将其装箱q为数组(我尝试过将其保留为0或导致了鼻恶魔)。

取消高尔夫:

var testcases = [
[{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"},{n:4,c:"BLUE"},{n:5,c:"BLUE"}, {n:6,c:"BLUE"}],//true
[{n:6,c:"BLUE"},{n:6,c:"RED"},{n:6,c:"BLACK"}],//true
[{n:5,c:"BLACK"},{n:6,c:"BLACK"},{n:7,c:"BLACK"},{n:8,c:"BLACK"},{n:9,c:"BLACK"},{n:10,c:"BLACK"},{n:0,c:"JOKER"},{n:12,c:"BLACK"}],//true
[{n:0,c:"JOKER"},{n:3,c:"BLUE"},{n:3,c:"RED"}],//true
[{n:8,c:"BLACK"},{n:2,c:"RED"},{n:13,c:"BLUE"}],//false
[{n:4,c:"RED"}, {n:3,c:"RED"}, {n:5,c:"RED"}],//false
[{n:5,c:"BLACK"}, {n:6,c:"BLACK"}],//false
[{n:0,c:"JOKER"},{n:5,c:"RED"},{n:0,c:"JOKER"}],//false
[{n:4,c:"RED"},{n:5,c:"RED"},{n:6,c:"BLUE"}],//false
[{n:4,c:"RED"},{n:0,c:"JOKER"},{n:5,c:"RED"}],//false
[{n:12,c:"BLACK"},{n:13,c:"BLACK"},{n:1,c:"BLACK"}],//false
[{n:11,c:"BLACK"},{n:12,c:"BLACK"},{n:0,c:"JOKER"}],//true
[{n:1,c:"BLACK"},{n:2,c:"BLACK"},{n:3,c:"BLACK"},{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"}]
];

g=a=>a.length
i=(a,v)=>a.indexOf(v)
j=x=>x.n==0
m=(x,y)=>
       (l(x,y)||x.n==y.n)
    &&!(j(x)&&j(y))
l=(x,y)=>x.c==y.c||j(x)||j(y)
c=(a,v)=>([n=i(a,v),
      n<1
    ||([x=a[n-1],!l(x,v)||v.n>0&&x.n<v.n])[1]
    ||(n<g(a)-1&&x.n+1<a[n+1].n)
    ||(n==g(a)-1&&v.n==0&&x.n<13)])[1]
a=s=>g(s)>2&&([q=[0],x=s[0],s.map(y=>q[0]+=x==y||m(x,y)&&c(s,y)?1:0)])[0][0]==g(s)

testcases.forEach(H=>console.log(a(H)));

我研究的版本可以使逻辑正确。一次性lambda排成一行;这是它们的对应功能:

g() -> string.length
i() -> indexof
j() -> isJoker
m() -> do tiles match
l() -> do colors match
c() -> same-color isConsecutiveOrder
a() -> main lambda

1

C#(.NET Core),198字节

using System.Linq;(C,N)=>{int l=C.Length,j=C.Count(x=>x<1),c=C.Distinct().Count(),n=N.Distinct().Count(),u=N.Min();foreach(var x in N)u*=0<(u&x)?2:0;return l>2&((u>0&n==l&c<2+j)|(n<2+j&c==l&l<5));};

将图块的颜色和上面的数字作为单独的整数列表。只要每种颜色都有不同的整数并且Jokers表示为0,该映射的细节就无关紧要。

输入数字的格式非常特殊。一个数字需要输入的数字n是2 ^ n,而用来表示笑话的数字应该是(2 ^ 14)-1。u&x如果图块x的值等于u或说笑话者,这将使按位求值并求值为u。

C#(.NET Core),200字节

using System.Linq;(C,N)=>{int l=C.Length,j=N.Count(x=>x<1),c=C.Distinct().Count(),n=N.Distinct().Count(),u=N.Min();foreach(var x in N)u=u==x|x<1?u+1:0;return l>2&((u>0&n==l&c<2+j)|(n<2+j&c==l&l<5));};

2字节长的解决方案,不折衷于输入。事实证明,在一个难于处理的地方为小丑提供一种特殊情况并没有比我为之骄傲的聪明按位操作时间长很多。这里的小丑是(0,0),其他数字与预期的一样,并且颜色表示任何4个值,这些值通过C#的默认比较彼此不同(具体来说,Linq Distinct()操作必须将相同颜色的值视为“不不同”以及将不同颜色的值表示为“不同”)。

某些语言可能会用到的某些语言,在某些语言中u*=!u++^x*x是等效的u=u==x|x<1?u+1:0;u ^ x为0且u == x,且0是任何int为0的倍数,因此,如果C#没有使按位运算的优先级低于其,则u == x或x == 0的u ^ x * x将为0数学的。如果没有显式强制转换,C#也无法将int解释为bool。一种语言,尝试更难做工种可能的值转换0,并not 0falsetrue申请前!,虽然给他们,然后回到一个int时解释!false为1和!true为0。所有这一切说,我不能保证其他语言实际上受益于算法的其余部分,因此它可能甚至无法解决。


1

Scala,491477个字符,491477个字节

这个挑战很有趣。谢谢。

var c=Seq("O","B","b","R")
t match{case _ if t.length<3=>false
case _ if t.exists(x=>x._1==0)=>{var b=false
if(t.filter(q=>q._1!=0).exists(q=>q._1==0))b else{for(y<-1 to 13)for(u<-c)b=b|f(t.takeWhile(q=>q._1!=0)++:(y,u)+:t.reverse.takeWhile(q=>q._1!=0).reverse)
b}}
case _::(x,_)::_ if t.forall(_._1==x)=>true
case _ if t.forall(_._2==c(0))|t.forall(_._2==c(1))|t.forall(_._2==c(2))|t.forall(_._2==c(3))=>(t(0)._1 to t(0)._1+t.length-1).toList equals t.map(_._1)
case _=>false}

因此,f在第4行是一个递归调用,在这里我尝试用其他所有图块替换“ JOKER”。请参阅tio以获取更清晰的代码视图。我选择将2个元组(Int,String)的序列作为输入- t在我的代码中调用,请参见tio-因此“ JOKER”由2个元组(0,“ JOKER”)表示。

编辑:由于注释节省了14个字节,我将OB b R设置为ORANGE BLACK BLUE RED。

在线试用!

编辑:-2个字节,(case _ ifs的情况下删除无用


您不能使用O,B,b,R而不是ORANGE,BLUE,BLACK,RED保存字节吗?我不知道Scala的工作方式,但我认为可以。
Xcoder先生17年

我试过了; 实际上,这样做可以节省字节(一串字符串)。它的确是var (O,B,b,R)=("ORANGE","BLACK","BLUE","RED")和调用为O B b R,总共49个字节;其中var c=Seq("ORANGE","BLACK","BLUE","RED")和调用c(...)总计58个字节。但是第一种情况允许for(u<-c)代替for(u<-Seq(O,B,b,R)),所以成本不是-9而是+2。感谢您的尝试。
V. Courtois

@ V.Courtois我相信Xcoder先生的建议是使用var c=Seq("O","B","b","R")这些字符作为输入,而不是完整的颜色字符串。如原始帖子中所述,“颜色可以用作...字符串的缩写”。
卡米尔·德拉科里

哦〜我明白你的意思了,谢谢你们@
V. Courtois
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.