Моя игра Диффи выродилась?


23

Недавно я отправил на вопрос о Diffy играх, остались без ответа. Это хорошо, вопрос действительно сложный, но я хотел бы сделать более легкий вопрос об играх Диффи, чтобы мы могли начать игру.


Как работает Diffy

Скопировано из Find Diffy Games

Игра Diffy работает следующим образом: вы начинаете со списка неотрицательных целых чисел, в этом примере мы будем использовать

3 4 5 8

Тогда вы берете абсолютную разницу между соседними числами

 (8)  3   4   5   8
    5   1   1   3

Тогда вы повторяете. Вы повторяете, пока не поймете, что вступили в цикл. И тогда, как правило, игра начинается заново.

3 4 5 8
5 1 1 3
2 4 0 2
0 2 4 2
2 2 2 2
0 0 0 0
0 0 0 0

Большинство игр заканчиваются цепочкой всех нулей, что считается проигрышным состоянием, но в редких играх они зацикливаются на больших циклах.


задача

Учитывая начальное состояние игры Diffy, определите, достигнет ли игра в конечном итоге состояния всех нулей. Вы должны вывести значение «Истина» или «Ложь» для каждого из двух состояний. Который соответствует, который не имеет значения.

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


1
Формулировка задачи, кажется, подразумевает, что любая игра, которая не достигает состояния всех нулей, является поэтому периодической. Ранее периодическое определяется как включающее начальное состояние в повторяющейся последовательности. Означает ли это, что любая последовательность в конечном итоге достигает либо всех нулей, либо исходного состояния?
Trichoplax

3
Нет: добавление положительной константы в любое ненулевое периодическое состояние приводит к состоянию, которое не возвращается ни к самому себе, ни ко всем нулям. Например, 1 1 0является периодическим, 42 42 41таково и такое состояние.
Грег Мартин

3
Действительно, для конкретного задаваемого вопроса даже не нужно понятие «периодический». «В конечном итоге достигает состояния всех нулей» является автономным и ясным.
Грег Мартин

2
Я доказал частичную характеристику: если длина списка n нечетная, игра не обнуляется, если все числа не равны. Если длина является степенью 2, она всегда стремится к нулю.
xnor

3
Граница количества шагов для достижения нуля: список с nэлементами и максимумом mзанимает самое большее количество n * bit_length(m)шагов. Итак, n*mэто тоже верхняя граница. Более сильная верхняя граница t(n) * bit_length(m), где t(n)наибольшая степень 2, это фактор n.
xnor

Ответы:


27

Pyth, 6 байт

suaV+e

Тестирование

Эта программа очень учтивая. 0 (ложь) означает все нули, все остальное (правда) означает не все нули.

Как это работает:

suaV+e
suaV+eGGGQ    Variable introduction.
 u       Q    Apply the following function repeatedly to its previous result,
              starting with the input. Stop when a value occurs which has
              occurred before.
  aV          Take the absolute differences between elements at the same indices of
        G     The previous list and
    +eGG      The previous list with its last element prepended.
s             The repeated value is returned. Sum its entries. This is zero (falsy)
              if and only if the entries are all zero.

6
это удачное решение
Martijn Vissers

14

Mathematica, 52 байта

1>Max@Nest[Abs[#-RotateLeft@#]&,#,Max[1+#]^Tr[1^#]]&

Чистая функция, принимающая в качестве входных данных список неотрицательных целых чисел True или False.

Abs[#-RotateLeft@#]&это функция, которая выполняет один раунд игры с неповторимым характером. (Технически так и должно быть RotateRight, но окончательный ответ не затрагивается, и, эй, свободный байт.) Таким образом, Nest[...,#,R]выполняется Rраунд игры diffy, а затем 1>Max@определяется, все ли результаты равны нулю .

Как мы узнаем, сколько нужно пройти раундов игры R? Если mэто наибольшее значение во входных данных, обратите внимание, что мы никогда не получим целое число больше, чем mнезависимо от того, сколько раундов мы делаем. Общее количество списков длины lнеотрицательных целых чисел, ограниченных, mравно (m+1)^l. Таким образом, если мы проводим (m+1)^lраунды игры «уклончиво», мы к тому времени гарантированно увидим какой-то список дважды и, следовательно, будем в периодической части игры. В частности, игра заканчивается во всех нулях, если и только если результатом (m+1)^lраундов игры является список из всех нулей. Это выражение - то, что Max[1+#]^Tr[1^#]вычисляет.


6

Желе , 13 байт

Ṁ‘*L
ṙ1ạ
ÇÑ¡Ṁ

Выводит 0 (ложь), если будет достигнуто нулевое состояние, в противном случае возвращается истинное значение (положительное целое число).

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

Использует наблюдение, впервые сделанное Грегом Мартином , о том, что числа в массиве могут никогда не покинуть область [0, m], где m - максимальный элемент на входе, поэтому выполняется (m + 1) l циклов, где l - длина входа, хватай.

Как?

Ṁ‘*L - Link 1, number of rounds to perform: list a
Ṁ    - maximum of a
 ‘   - incremented
   L - length of a
  *  - exponentiate

ṙ1ạ - Link 2, perform a round: list x
ṙ1  - rotate x left by 1
  ạ - absolute difference (vectorises) with x

ÇÑ¡Ṁ - Main link: list a
  ¡  - repeat:
Ç    -     the last link (2) as a monad
 Ñ   -     the next link (1) as a monad times
   Ṁ - return the maximum of the resulting list

Может ли это быть улучшено с помощью xnor ?
Wheat Wizard

@WheatWizard Я думаю, что это будет стоить байта. (Возможно, можно получить более короткий метод, собирая все результаты, пока они не будут уникальными, но я не нашел его).
Джонатан Аллан

2

PHP, 144 байта

выведите 0 для всех нулей и любое положительное целое значение для true

<?for($r[]=$_GET[0];!$t;){$e=end($r);$e[]=$e[$c=0];for($n=[];++$c<count($e);)$n[]=abs($e[$c-1]-$e[$c]);$t=in_array($n,$r);$r[]=$n;}echo max($n);

Онлайн версия

расширенный

for($r[]=$_GET;!$t;){
    $e=end($r);  # copy last array
    $e[]=$e[$c=0]; # add the first item as last item
    for($n=[];++$c<count($e);)$n[]=abs($e[$c-1]-$e[$c]); # make new array
    $t=in_array($n,$r); # is new array in result array
    $r[]=$n; # add the new array
}
echo max($n); # Output max of last array

1
array_push? Но почему ?
Кристоф

1
также при использовании в $_GETкачестве входных данных вы должны предполагать, что он содержит строку.
Кристоф

1
@Christoph ?0[0]=1&0[1]=1&0[2]=0или ?0[]=1&0[]=1&0[]=0представляет собой массив строк, но это не имеет значения. Но вы правы, я мог бы сделать это короче, ?0=1&1=1&2=0почему бы не àrray_push` Я уверен, что вы или Титус найдете лучшие способы сократить это.
Йорг Хюльсерманн

1
array_push($e,$e[$c=0]);просто точно так же, как $e[]=$e[$c=0];и вы даже используете синтаксис уже ( $r[]=$n). Вы уже используете в maxнастоящее время , так что вы должны также заменить end($r)с , $nпотому что $nвсегда равно , end($r)когда эхо выполняется.
Кристоф

@Christoph Похоже, что вчера был не мой день. Спасибо. Вы привели меня к моей идее для новой записи в разделе советов
Jörg Hülsermann

2

R (3.3.1), 87 байт

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

z=scan();sum(Reduce(function(x,y)abs(diff(c(x,x[1]))),rep(list(z),max(z+1)^length(z))))

использует тот же факт Грег Мартин и использует встроенный diff, чтобы сделать диффузию


при условии, что граница xnor является правильной (из комментариев), это может быть на два байта короче, используя max (z) * length (z), но я не уверен в правильности
Giuseppe

1

Röda , 80 байт

f l...{x=[{peek a;[_];[a]}()|slide 2|abs _-_];[sum(x)=0]if[x in l]else{x|f*l+x}}

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

Ungolfed:

function f(l...) { /* function f, variadic arguments */
    x := [ /* x is a list of */
        { /* duplicate the first element of the stream to the last position */
            peek a /* read the first element of the stream */
            [_]    /* pull all values and push them */
            [a]    /* push a */
        }() |
        slide(2) | /* duplicate every element except first and last */
        abs(_-_)   /* calculate the difference of every pair */
    ]
    /* If we have already encountered x */
    if [ x in l ] do
        return sum(x) = 0 /* Check if x contains only zeroes */
    else
        x | f(*l+x) /* Call f again, with x appended to l */
    done
}

1

05AB1E , 13 байтов

Возвращает 1, если оно заканчивается нулями, и 0 в противном случае.

Z¹g*F¤¸ì¥Ä}_P

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

объяснение

Использует верхнюю границу раундов: max(input)*len(input)объясняется xnor в разделе комментариев.

Z              # get max(input)
 ¹g            # get length of input
   *           # multiply
    F          # that many times do:
     ¤         # get the last value of the current list (originally input)
      ¸        # wrap it
       ì       # prepend to the list
        ¥      # calculate deltas
         Ä     # calculate absolute values
          }    # end loop
           _   # negate each (turns 0 into 1 and everything else to 0)
            P  # calculate product

1

J, 22 байта

Возвращает 0(что эффективно falseв J) для вырожденной игры, оканчивающейся на все нули. Возвращает 1( true), если n-я итерация содержит ненулевое число, где n равно наибольшему целому числу в исходной последовательности, умноженному на длину списка. Смотрите ответ Грега Мартина, объясняющий, почему это так.

*>./|&(-1&|.)^:(#*>./)

Перевод:

  • Какой знак *
  • наибольшую ценность >./
  • когда вы повторяете следующее столько раз, сколько ^:( )
  • длина списка, #умноженная *на наибольшее значение в списке>./ :
    • принять абсолютное значение |& в
    • разница между списком (- ) и
    • список повернут на один 1&|.

Примеры:

   *>./|&(-1&|.)^:(#*>./) 1 1 0
1
   *>./|&(-1&|.)^:(#*>./) 42 42 41
1
   *>./|&(-1&|.)^:(#*>./) 3 4 5 8
0
   *>./|&(-1&|.)^:(#*>./) 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1
0

1
Это не то, что утверждает Грег Мартин. Тем не менее, xnor имеет лучшие границы в комментариях выше (но все же не только самое большое целое число). Самое простое - умножить наибольшее значение на длину.
Эрджан Йохансен,

Хороший улов. Я не уделял достаточно внимания. Я исправлю решение.
датчанин

1

JavaScript (ES6), 95 92 90 байт

f=(a,b=(Math.max(...a)+1)**(c=a.length))=>b?f(a.map((v,i)=>v-a[++i%c]),b-1):a.every(v=>!v)

объяснение

Рекурсивная функция, которая вызывает себя до тех пор, пока счетчик (который начинается с максимального значения в списке плюс единица в степени длины списка [ = (max + 1)**length]) не равен нулю. При каждом вызове счетчик уменьшается, и когда он достигает нуля, все элементы в списке проверяются на ноль. Если все они равны нулю, программа возвращается true, и в falseпротивном случае.


1

PHP, 123 115

for($a=$_GET,$b=[];!in_array($a,$b);){$b[]=$c=$a;$c[]=$c[0];foreach($a as$d=>&$e)$e=abs($e-$c[$d+1]);}echo!max($a);

принимая ввод через HTTP get, например, ?3&4&5&8сохраняет несколько байтов.

Печатает 1, если он достигает всех нулей или вообще ничего.


for($e=$argv,$r=[];!in_array($e,$r);$q=$e[0]){$e[0]=end($e);$r[]=$e;foreach($e as$k=>&$q)$q=abs($q-$e[$k+1]);}echo!max($e);

принимает список аргументов через командную строку. У меня такое чувство, что это можно сделать еще глубже (глядя на @Titus).


1

Python 3.6, 101 байт

def f(t):
 x={}
 while x.get(t,1):x[t]=0;t=(*(abs(a-b)for a,b in zip(t,t[1:]+t[:1])),)
 return any(t)

Принимает кортеж чисел и возвращает False, если оно заканчивается нулями, и True, если оно повторяется.


0

JavaScript (ES6), 84 83 байта

В противном случае возвращается trueигра, заканчивающаяся на все нули false.

f=(a,k=a)=>k[b=a.map((n,i)=>Math.abs(n-a[(i||a.length)-1]))]?!+b.join``:f(k[b]=b,k)

Тест

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.