Давайте играть в Руммикуб!

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 9, RED 9, JOKER, BLACK 9или RED 9, BLUE 9, JOKER. То же самое относится и к нашему другому примеру. Однако нельзя ставить двух джокеров в одну группу, поэтому подобные вещи JOKER, ORANGE 8, JOKERзапрещены.


задача

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

Ввод, вывод

Вы можете получить ввод и предоставить вывод любым стандартным методом.

Некоторые допустимые форматы ввода: список строк, список кортежей, вложенные списки, строки или все, что вы считаете подходящим. Цвета могут быть приняты как строки (например:) "Blue","Red", etc., как сокращения строк (пожалуйста, выделите синие и черные плитки), или как целые числа, соответствующие цвету. Когда дело доходит до джокеров, вы должны упомянуть, как ваша программа получает их в качестве входных данных. Если вы выбираете Strings, у вас может быть что-то вроде RED 9, JOKER, ..., если вы выбираете кортежи, которые вы можете иметь, (9,"RED"), ("JOKER")или что-то подобное. Если это поможет, вы можете получить цвет для этого Джокера (который не должен влиять на вывод вашей программы). Например, вы можете иметь ("JOKER","RED")или ("JOKER","BLUE"), но это никак не должно влиять на вывод.

Что касается вывода, применяются стандартные правила для .

Отработанные примеры

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

[(9, «КРАСНЫЙ»), (9, «ОРАНЖЕВЫЙ»), («ДЖОКЕР»), (9, «ЧЕРНЫЙ»)]

Это должно вернуть истинное значение, потому что ввод действителен. В этом случае джокер подставляет (9, "BLUE"), и они образуют многоцветную группу.

Если бы вам дали следующую группу:

[(9, «СИНИЙ»), (9, «ОРАНЖЕВЫЙ»), (9, «КРАСНЫЙ»), (9, «ЧЕРНЫЙ»), («ДЖОКЕР»)]

Это было бы недопустимо, и поэтому ваша программа должна возвращать ложное значение, потому что джокеру ничего не осталось заменить, потому что максимальное количество карт в многоцветной группе равно 4.

Дополнительные тестовые случаи

Они предназначены для расширенного набора тестов, который охватывает практически все возможные ситуации:

Вход -> Выход 

[(1, «СИНИЙ»), (2, «СИНИЙ»), (3, «СИНИЙ»), (4, «СИНИЙ»), (5, «СИНИЙ»), (6, «СИНИЙ»)]] - > правда

[(6, «СИНИЙ»), (6, «КРАСНЫЙ»), (6, «ЧЕРНЫЙ)] -> правда

[(5, "черный"), (6, "черный"), (7, "черный"), (8, "черный"), (9, "черный"), (10, "черный"), ( "ДЖОКЕР"), (12, "ЧЕРНЫЙ")] -> правда 

[("Джокер"), (3, "СИНИЙ"), (3, "КРАСНЫЙ")] -> правда

[(8, «ЧЕРНЫЙ»), (2, «КРАСНЫЙ»), (13, «СИНИЙ»)] -> ложь

[(4, «КРАСНЫЙ»), (3, «КРАСНЫЙ»), (5, «КРАСНЫЙ»)] -> ложь

[(5, «ЧЕРНЫЙ»), (6, «ЧЕРНЫЙ)] -> ложь

[("ДЖОКЕР"), (5, "КРАСНЫЙ"), ("ДЖОКЕР")] -> ложь

[(4, «КРАСНЫЙ»), (5, «КРАСНЫЙ»), (6, СИНИЙ »)] -> ложь

[(4, «КРАСНЫЙ»), («ДЖОКЕР»), (5, «КРАСНЫЙ»)] -> ложь

[(12, «ЧЕРНЫЙ»), (13, «ЧЕРНЫЙ), (1,« ЧЕРНЫЙ »)] -> ложь

Это , поэтому выигрывает самый короткий код в байтах на каждом языке!

Мистер Xcoder
источник
Связанные
Питер Тейлор
Кража - лучшая часть руммикуба. Даже без этого это выглядит как забавный вызов.
Иосия
Является ли [] действительным вводом?
В. Куртуа
@ V.Courtois Конечно.
г-н Xcoder
1
@ V.Courto, нельзя ставить двух джокеров в одну группу , поэтому два входа, содержащие 2 джокера, ложны.
мистер Xcoder

Ответы:

6

APL (Dyalog) , 58 байт

Принимает список цветов (1-4) в качестве правого аргумента и список чисел в качестве левого аргумента. Обозначается номер Джокера, (⍳4)который эквивалентен тому, (1 2 3 4)что он может быть любым из них. Аналогично, его цвет обозначен, (⍳13)чтобы указать, что это может быть любое из чисел от 1 до 13.

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

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

Алгоритм

Есть три условия, из которых два последних имеют два условия каждое:

  1. Пробег должен иметь длину, большую или равную 3

И ЛИБО

    1. одно число И

    2. уникальные цвета

ИЛИ

    1. один цвет И
    2. порядковые номера

для того, чтобы пробег был действительным.

Порядок чтения

3≤3 меньше или равно ≢⍺количеству плиток

а также

   s⍵ все числа одинаковы

   а также

   ⍺≡∪⍺ цвета уникальны

или

   1∊1 входит ≢∘∪¨в число уникальных ⊃,¨/расширенных  цветов

   а также

   ∨/среди всех ⊃,¨/⍵расширенных числовых прогонов существует хотя бы один, ⍷¨⊂встречающийся в ⍳131-13

Полное объяснение кода

{} Анонимная функция, где левый аргумент и правый аргумент

3.2.

⍳13 цифры от 1 до 13

(... )⍷¨найти стартовые позиции каждого из следующих запусков:

  ,¨/⍵ объединить каждый элемент чисел (создает прогон для каждого значения Джокера)

   раскрыть (потому что /снижает рейтинг)

  ε NLIST (Flatten)

∨/ ИЛИ сокращение (т. Е. Правда ли?)

()∧ И:

3,1

  ()⍺ Результат применения следующей функции в списке цветов:

   s←{}S (для s ame), которая является следующей анонимной функцией ( является ее аргументом):

    ,¨/⍵ объединить каждый элемент (создает прогон для каждого значения джокера)

     раскрыть (потому что /снижает рейтинг)

    ≢∘∪¨ количество уникальных элементов в каждом списке

    1∊ один член? (т. е. есть ли какие-либо списки всех одинаковых?)

()∨ИЛИ

2.2.

  ∪⍺ уникальные цвета

  ⍺≡ идентичны цветам (т.е. они уникальны)

  ()∧ И:

2.1.

   s⍵ цифры все одинаковые

  ()∧И

1.

   ≢⍺ количество цветов (то есть количество плиток)

   3≤ три меньше или равно этому

Адам
источник
1
Вау, похоже, APL - отличный инструмент для решения этой задачи
г-н Xcoder
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.
PurkkaKoodari
источник
Я думаю, что вы должны вывести последовательную правду / ложь.
Адам
@ 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 байтов, спасибо !!
  • Еще 4 байта благодаря @ Mr.Xcoder
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))

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

officialaimm
источник
2
370 байт
г-н Xcoder
1
Это на самом деле экономит гораздо больше байтов, чем я думал: 329 .
мистер Xcoder
1
325 байт . Извините за очень позднее улучшение.
г-н Xcoder
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)));

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

Грубый процесс:

 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 или вызывало назальные демоны ).

Ungolfed:

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

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

g() -> string.length
i() -> indexof
j() -> isJoker
m() -> do tiles match
l() -> do colors match
c() -> same-color isConsecutiveOrder
a() -> main lambda
Draco18s больше не доверяет SE
источник
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));};

Принимает цвета плиток и цифры на них как отдельные списки целых чисел. Специфика этого отображения не имеет значения, если каждый цвет имеет различное целое число, а джокеры представлены как 0.

Формат ввода чисел довольно особенный, хотя. Число, которое нужно ввести для числа, nравно 2 ^ n, а число, используемое для представления джокера, должно быть (2 ^ 14) -1. Это позволяет побитово и u&xоценивать u, если тайл x имеет значение, равное 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 # (в частности, Distinct()операция Linq должна рассматривать значения для того же цвета как «не отличные»). и значения для разных цветов как «разные»).

Нечто, что могло бы быть полезным для других языков, u*=!u++^x*xбыло бы эквивалентно u=u==x|x<1?u+1:0в некоторых языках; u ^ x равно 0 тогда и только тогда, когда u == x, и 0 раз любое int равно 0, поэтому u ^ x * x будет равно 0 для u == x или x == 0, если C # не делает побитовые операции меньшим приоритетом, чем математические. C # также не может интерпретировать int как bools без явного приведения. Язык, который старается сделать так, чтобы типы работали, может преобразовывать значения в 0и not 0до falseи trueпосле применения !к ним, а затем при возвращении к int интерпретировать !falseкак 1 и !trueкак 0. Все это говорит, что я не могу гарантировать, что другой язык на самом деле будет извлечь выгоду из остальной части алгоритма, так что он может даже не придумать.

Камил Дракари
источник
1

Scala, 491 477 символов, 491 477 байтов

Этот вызов был веселым; Спасибо.

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.

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

EDIT: -2 байта, удалены ненужные (условия Вокруг case _ ifс

В. Куртуа
источник
Вы не можете использовать O,B,b,Rвместо того, ORANGE,BLUE,BLACK,REDчтобы сохранить байты? Я понятия не имею, как работает Scala, но я думаю, что вы можете.
г-н Xcoder
Я старался; фактически он сохраняет байты таким образом (последовательность строк). Это делает 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 Я полагаю, что мистер Xcoder предложил использовать var c=Seq("O","B","b","R")эти символы в качестве входных данных, а не полные строки для цвета. Как уже упоминалось в оригинальном сообщении, «цвета могут быть приняты как ... строковые сокращения».
Камиль Дракари
ооо ~ я понимаю, что ты имеешь в виду, спасибо @ вам обоим
В. Куртуа