Connect 4: Найди подделку!

34

Банк был взломан, и у всех местных мафиозных головорезов есть необычное алиби: они были дома, играя в Connect 4! Чтобы помочь в расследовании, вас просят написать программу для проверки всех досок Connect 4, которые были изъяты, чтобы проверить, что позиции действительно являются позициями в действующей игре Connect 4 и не были спешно собраны вместе как только полиция постучала в дверь.

Правила подключения 4: игроки Rи Yпо очереди бросают плитки своего цвета в столбцы сетки 7x6. Когда игрок бросает плитку в столбец, он падает, чтобы занять самую низкую незаполненную позицию в этом столбце. Если игроку удается получить горизонтальный, вертикальный или диагональный ряд из четырех плиток своего цвета на доске, то он выигрывает, и игра немедленно заканчивается.

Например (с Rзапуском), следующая позиция Connect 4 невозможна.

| | | | | | | |
| | | | | | | |
| | | | | | | |
| | |R| | | | |
| | |Y| | | | |
|R| |Y| | | | |

Ваша программа или функция должны принимать плату Connect 4 и возвращать либо

  • Ложное значение, указывающее, что позиция невозможна или
  • Строка чисел от 1 до 7, что указывает на одну возможную последовательность ходов , ведущих к этой позиции (столбцы пронумерованы , 1чтобы 7слева направо, и так последовательности 112, например, указывает на красный движение в колонке 1, а затем желтый ход в столбце с 1последующим красным движением в столбце 2). Вы можете выбрать нумерацию столбцов, отличную от 1234567, если хотите, если вы указали в своем решении. Если вы хотите вернуть список в другом формате; например, в качестве массива [2, 4, 3, 1, 1, 3], это тоже хорошо, если легко увидеть, что движется.

Вы можете выбрать чтение доски в любом разумном формате, включая использование букв, отличных от Rи Yдля игроков, но вы должны указать, какой игрок идет первым. Вы можете предположить, что доска всегда будет 6х7 с двумя игроками.

Вы можете предположить, что полученные вами позиции, по крайней мере, физически возможно создать на стандартной плате Connect 4; то есть, что не будет «плавающих» фигур. Вы можете предположить, что доска будет непустой.

Это код гольф, поэтому самый короткий ответ выигрывает. Применяются стандартные лазейки.

Примеры

| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | --> 1234567 (one possible answer)
| | | | | | | |
|R|Y|R|Y|R|Y|R|

| | | | | | | |
| | | | | | | |
| | | | | | | |
| | |R| | | | | --> false
| | |Y| | | | |
|R| |Y| | | | |

| | | | | | | |
| | |Y| | | | |
| | |R| | | | |
| | |Y| | | | | --> 323333 (only possible answer)
| | |R| | | | |
| |Y|R| | | | |

| | | | | | | |
| | | | | | | |
| | | | | | | |     
| | | | | | | | --> false (this is the position arising after
| |Y|Y|Y|Y| | |     the moves 11223344, but using those moves
| |R|R|R|R| | |     the game would have ended once R made a 4)

| | | | | | | |
| | | | | | | |
|Y| | | | | | |     
|R|Y| | | | | | --> 2134231211 (among other possibilities)
|R|R|Y| | | | |
|Y|R|R|Y| | | |

| | | | | | | |
| | | | | | | |
|Y| | | | | | |     
|R|Y| | | | | | --> false (for example, 21342312117 does not
|R|R|Y| | | | |     work, because Y has already made a diagonal 4)
|Y|R|R|Y| | |R|

| | | | | | | |
| | | | | | | |
| | | | | | | |     
| | | | | | | | --> 112244553 or similar
|Y|Y| |Y|Y| | |
|R|R|R|R|R| | |
Джон Гауэрс
источник
Джон, из любопытства, ты знаешь, существует ли алгоритм не грубой силы?
Иона

Ответы:

9

Желе , 57 байт

ŒṪŒ!µ0ịŒṬ¬a³ZU,Ɗ;ŒD$€Ẏṡ€4Ḅo1%15;Ḋ€ṢṚ$Ƒƙ$Ȧȧœị³$2R¤ṁ$ƑµƇṪṪ€

Принимает матрицу, где 0незаполнен, 1воспроизводится первым и 2воспроизводится вторым. Возвращает список из 1-индексированных столбцов, пустой, если обнаружена подделка.

Попробуйте онлайн! (слишком неэффективно для более чем 7 штук, чтобы запустить менее чем за минуту)

Заметка:

  1. Предполагается, что «плавающие» фрагменты отсутствуют (исправьте это, добавив ZṠṢ€Ƒȧ+6 байт)
  2. Предполагается, что пустая доска является подделкой
Джонатан Аллан
источник
11

JavaScript (ES6),  202 194 187  183 байта

Принимает входные данные в виде матрицы с для красного, для желтого и для пустого. Возвращает строку с 0-индексированными ходами (или пустую строку, если решения не существует). Красные начинают игру.240

m=>(p=[...'5555555'],g=(c,s=o='')=>/2|4/.test(m)?['',0,2,4].some(n=>m.join``.match(`(1|3)(.{1${n}}\\1){3}`))?o:p.map((y,x)=>m[m[y][x]--^c||p[g(c^6,s+x,p[x]--),x]++,y][x]++)&&o:o=s)(2)

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

Как?

Рекурсивная функция пытается заменить все и во входной матрице на и соответственно.g2413

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

Строка следующего доступного слота для каждого столбца сохраняется в .yxp[x]

комментарии

m => (                            // m[] = input matrix
  p = [...'5555555'],             // p[] = next row for each column
  g = (c,                         // g = recursive function taking c = color,
          s = o = '') =>          //     s = current solution, o = final output
    /2|4/.test(m) ?               // if the matrix still contains at least a 2 or a 4:
      ['', 0, 2, 4]               //   see if we have four consecutive 1's or 3's
      .some(n =>                  //   by testing the four possible directions
        m.join``                  //   on the joined matrix, using
        .match(                   //   a regular expression where the number of characters
          `(1|3)(.{1${n}}\\1){3}` //   between each occurrence is either 1, 10, 12 or 14
        )                         //   (horizontal, diagonal, vertical, anti-diagonal)
      ) ?                         //   if we have a match:
        o                         //     abort and just return the current value of o
      :                           //   else:
        p.map((y, x) =>           //     for each cell at (x, y = p[x]):
          m[                      // 
            m[y][x]--             //       decrement the value of the cell
            ^ c ||                //       compare the original value with c
            p[                    //       if they're equal:
              g(                  //         do a recursive call with:
                c ^ 6,            //           the other color
                s + x,            //           the updated solution
                p[x]--            //           the updated row for this column
              ),                  //         end of recursive call
              x                   //         then:
            ]++,                  //         restore p[x]
            y                     //         and restore m[y][x]
          ][x]++                  //         to their initial values
        ) && o                    //     end of map(); yield o
    :                             // else:
      o = s                       //   we've found a solution: copy s to o
)(2)                              // initial call to g() with c = 2
Arnauld
источник
Заметьте, что я спросил: «Можем ли мы предположить, что пустая доска не будет использоваться в качестве входных данных?» - если мы должны справиться с этим, то ваш код будет нуждаться в настройке.
Джонатан Аллан
я не знаю почему, f([ [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,2,0,2,0,0], [0,2,2,0,2,2,0], [1,1,1,1,1,1,1] ])заканчивается 0 и f([ [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,2,0,2,0,0], [2,2,2,0,2,2,1], [1,1,1,1,1,1,1] ])должно быть правдой
Науэль Фуйе
@NahuelFouilleul Спасибо за сообщение об этом. Я исправил код, добавил эти тесты.
Арнаулд
2

Python 2 , 295 285 байт

def f(a):
 if 1-any(a):return[]
 p=sum(map(len,a))%2
 for i in R(7):
	if a[i][-1:]==`p`:
	 b=a[:];b[i]=b[i][:-1];L=f(b)
	 if L>1>(`1-p`*4in','.join([J((u[j]+' '*14)[n-j]for j in R(7))for n in R(12)for u in[b,b[::-1]]]+b+map(J,zip(*[r+' '*7for r in b])))):return L+[i]
R=range;J=''.join

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

-10 спасибо Джо Кингу .

Input представляет собой список строк, представляющих столбцы; с «1» для красного и «0» для желтого. Строки не дополняются. Итак, (фальшивый) случай:

| | | | | | | |
| | | | | | | |
|Y| | | | | | |
|R|Y| | | | | |
|R|R|Y| | | | |
|Y|R|R|Y| | |R|

вводится как:

[
  '0110',
  '110',
  '10',
  '0',
  '',
  '',
  '1'
]

Выход - это список индексов столбцов, с 0 индексами, которые могут составить плату; или Noneесли это не верно.

Принимает пустую доску как действительную (возвращает пустой список []вместо None).

Этот подход рекурсивен от последнего хода к первому ходу: основываясь на паритете общего количества предпринятых ходов, мы удаляем либо последний ход красных, либо последний ход желтых (или проваливаем, если это невозможно); проверьте получившуюся доску, чтобы увидеть, есть ли у противника 4-в-ряд (в этом случае неудача, потому что игра уже должна была остановиться); в противном случае повторяйте процедуру до тех пор, пока доска не станет пустой (что действительно).

Код «4 в ряд» - самая расплывчатая часть. Все диагональные строки для матрицы bгенерируются:

[
    ''.join(
        (u[j]+' '*14)[n-j] for j in range(7)
    )
    for u in[b,b[::-1]]for n in range(12) 
]

которая сначала перечисляет «наклонные» диагонали, а затем «наклонные».

Час Браун
источник