Определите, существует ли ход в игре Bejeweled / match 3


20

Фон

В Bejeweled и подобных играх игрок должен поменять местами любые два смежных камня (без диагоналей) в сетке камней 8x8, чтобы соответствовать трем одинаковым цветам подряд. Драгоценные камни могут быть сопоставлены по горизонтали или вертикали. Игровой процесс продолжается до тех пор, пока не будет выполнено ни одного хода, что приведет к трем подряд, после чего игра заканчивается.

задача

Цель состоит в том, чтобы написать программу, которая определяет, не закончена ли игра Bejeweled. Другими словами, он должен проверить, есть ли возможный ход, который делает по крайней мере три подряд. Может быть более трех драгоценных камней подряд, и это все еще действительный ход.

вход

Ваша программа должна принимать через стандартный ввод 8x8 представление сетки Bejeweled. Каждый из семи цветов драгоценных камней будет представлен цифрой от 1 до 7. Каждая строка будет содержать одну строку, и будет введено 8 строк, каждая из которых состоит из 8 цифр. Смотрите примеры. Вы можете предположить, что входные данные всегда будут следовать этому формату и никогда не будут содержать три подряд.

Выход

Затем программа должна вывести (на стандартный вывод) yesили в noзависимости от того, существует или нет хотя бы одно допустимое движение, которое привело бы к трем или более драгоценным камням в строке. Ваша программа не должна выводить ничего, кроме одного экземпляра yesили no.

правила

Ваша программа не должна использовать какие-либо внешние файлы или ресурсы, аргументы командной строки или требовать определенного имени файла. Программа с наименьшим количеством байтов в исходном коде выигрывает.

Примеры

Входные данные:

12314131
13224145
54762673
61716653
61341144
23453774
27645426
75575656

Выход: yes

Входные данные:

35261546
76421754
15743271
62135642
35617653
64565476
54427254
15635465

Выход: no

См . Ответ MT0 ниже для дополнительных тестовых случаев.


Это просто строки или столбцы тоже.
TheDoctor

@TheDoctor Columns тоже. Когда я использую фразу «три в ряд», я имею в виду, что они должны быть расположены в горизонтальном или вертикальном направлении.
bdr9

@ bdr9 Вы можете отредактировать это в
Джон Дворжак

@JanDvorak Готово.
bdr9

Также может потребоваться изменить, если разрешено 4+ в строке.
Джастин

Ответы:


12

Исходное решение: JavaScript - 261 255 228 227 179 153 символов

/(\d)(\1(\d|.{6}|.{9})|(\d|.{6}|.{9})\1|.{7}\1(.|.{9})|(.|.{9})\1.{7}|(.{7,9}|.{17})\1.{8}|.{8}\1(.{7,9}|.{17}))\1/.test(s.replace(/\n/g,'A'))?'yes':'no'

Предполагая, что проверяемая строка находится в переменной s(чтобы сделать ее функцией, fдобавьте f=s=>ее в начало кода или, в противном случае, получите ввод из приглашения, а затем замените sна prompt()).

Выходы есть на консоль.

3- е решение: JavaScript (ECMAScript 6) - 178 символов

p=x=>parseInt(x,36);for(t="2313ab1b8a2a78188h9haj9j8iaiir9r",i=v=0;s[i];i++)for(j=0;t[j];v|=s[i]==s[i+a]&s[i]==s[i+b]&i%9<8&(b>3|(i+b-a)%9<8))a=p(t[j++]),b=p(t[j++]);v?'yes':'no'

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

Строка Base-36 "2313ab1b8a2a78188h9haj9j8iaiir9r"дает пары смещений для проверки - то есть в 23результате пары проверяется, идентичен ли i- й символ (i + 2) -ому символу и (i + 3) -ому символу (эквивалент регулярного выражения). (.).\1\1- с некоторыми дополнительными проверками, чтобы убедиться, что неидентичный символ не является новой строкой).

2- е решение: JavaScript (ECMAScript 6) - 204 символа

p=x=>parseInt(x,18);g=a=>a?a>1?"(.|\\n){"+a+"}":".":"";f=(x,a,b)=>RegExp("(.)"+g(a)+"\\1"+g(b)+"\\1").test(x);for(t="10907160789879h8",i=v=0;t[i];v|=f(s,x,y)||f(s,y,x))x=p(t[i++]),y=p(t[i++]);v?'yes':'no'

Создает несколько регулярных выражений (подробнее см. Ниже) с использованием пар значений, взятых из строки Base-18, 10907160789879h8и принимает ORвсе тесты. Чтобы еще больше его уменьшить, вы можете заметить, что регулярные выражения идут парами, где одно является «обратным» другому (игнорируя регулярные выражения для 3-в-ряд по горизонтали и вертикали, так как OP заявляет, что они никогда не будут присутствовать - если вы хотите добавить эти тесты обратно в дополнение к 0088строке Base-18).

объяснение

Начните с 16 регулярных выражений, охватывающих все возможные конфигурации допустимых ходов:

REs=[
    /(\d)\1\1/,                 // 3-in-a-row horizontally
    /(\d).\1\1/,                // 3-in-a-row horizontally after left-most shifts right
    /(\d)\1.\1/,                // 3-in-a-row horizontally after right-most shifts left
    /(\d)(?:.|\n){9}\1\1/,  // 3-in-a-row horizontally after left-most shifts down
    /(\d)(?:.|\n){7}\1.\1/, // 3-in-a-row horizontally after middle shifts down
    /(\d)(?:.|\n){6}\1\1/,  // 3-in-a-row horizontally after right-most shifts down
    /(\d)\1(?:.|\n){6}\1/,  // 3-in-a-row horizontally after left-most shifts up
    /(\d).\1(?:.|\n){7}\1/, // 3-in-a-row horizontally after middle shifts up
    /(\d)\1(?:.|\n){9}\1/,  // 3-in-a-row horizontally after right-most shifts up
    /(\d)(?:.|\n){7,9}\1(?:.|\n){8}\1/, // 3-in-a-row vertically (with optional top shifting left or right)
    /(\d)(?:.|\n){7}\1(?:.|\n){9}\1/,   // 3-in-a-row vertically after middle shifts right
    /(\d)(?:.|\n){9}\1(?:.|\n){7}\1/,   // 3-in-a-row vertically after middle shifts left
    /(\d)(?:.|\n){8}\1(?:.|\n){7}\1/,   // 3-in-a-row vertically after bottom shifts right
    /(\d)(?:.|\n){8}\1(?:.|\n){9}\1/,   // 3-in-a-row vertically after bottom shifts left
    /(\d)(?:.|\n){17}\1(?:.|\n){8}\1/,  // 3-in-a-row vertically after top shifts down
    /(\d)(?:.|\n){8}\1(?:.|\n){17}\1/,  // 3-in-a-row vertically after bottom shifts up
];

( Примечание: регулярные выражения для 3-х в ряд по горизонтали (0- й ) и вертикальной (часть 9- го ) не имеют значения, так как OP заявляет, что входные данные, соответствующие этим, никогда не будут присутствовать. )

Тестирование каждого из этих входных данных определит, можно ли найти действительный ход этой конфигурации.

Тем не менее, регулярные выражения могут быть объединены, чтобы получить эти 6:

/(\d)(?:.|(?:.|\n){9}|(?:.|\n){6})?\1\1/            // Tests 0,1,3,5
/(\d)\1(?:.|(?:.|\n){9}|(?:.|\n){6})?\1/            // Tests 0,2,6,8
/(\d)(?:.|\n){7}\1(?:.|(?:.|\n){9})\1/              // Tests 4,10
/(\d)(?:.|(?:.|\n){9})\1(?:.|\n){7}\1/              // Tests 7,11
/(\d)(?:(?:.|\n){7,9}|(?:.|\n){17})\1(?:.|\n){8}\1/ // Tests 9,14
/(\d)(?:.|\n){8}\1(?:(?:.|\n){7,9}|(?:.|\n){17})\1/ // Tests 9a,12,13,15

Затем они могут быть объединены в одно регулярное выражение:

/(\d)(?:.|(?:.|\n){9}|(?:.|\n){6})?\1\1|(\d)\2(?:.|(?:.|\n){9}|(?:.|\n){6})?\2|(\d)(?:.|\n){7}\3(?:.|(?:.|\n){9})\3|(\d)(?:.|(?:.|\n){9})\4(?:.|\n){7}\4|(\d)(?:(?:.|\n){7,9}|(?:.|\n){17})\5(?:.|\n){8}\5|(\d)(?:.|\n){8}\6(?:(?:.|\n){7,9}|(?:.|\n){17})\6/

Который просто должен быть проверен на входе.

Тестовые случаи

Некоторые тестовые случаи, которые другие люди могут найти полезными (не соответствует формату ввода, в котором используются только цифры 1-7, но это легко исправить и это только сетка 8x4 - так как это минимум, необходимый для проверки всех допустимых входных данных ).

В формате карты из входной строки, с которой из 16 регулярных выражений выше соответствует.

Tests={
    "12345678\n34567812\n56781234\n78123456": -1, // No Match
    "12345678\n34969912\n56781234\n78123456": 1,    // 3-in-a-row horizontally after left-most shifts right 
    "12345678\n34567812\n59989234\n78123456": 2,    // 3-in-a-row horizontally after right-most shifts left
    "12345978\n34567899\n56781234\n78123456": 3,    // 3-in-a-row horizontally after left-most shifts down
    "12345978\n34569892\n56781234\n78123456": 4,    // 3-in-a-row horizontally after middle shifts down
    "12345678\n34967812\n99781234\n78123456": 5,    // 3-in-a-row horizontally after right-most shifts down
    "12399678\n34967812\n56781234\n78123456": 6,    // 3-in-a-row horizontally after left-most shifts up
    "12345678\n34597912\n56789234\n78123456": 7,    // 3-in-a-row horizontally after middle shifts up
    "12345998\n34567819\n56781234\n78123456": 8,    // 3-in-a-row horizontally after right-most shifts up
    "12945678\n34597812\n56791234\n78123456": 9,    // 3-in-a-row vertically after top shifts right
    "12349678\n34597812\n56791234\n78123456": 9,    // 3-in-a-row vertically after top shifts left
    "12345978\n34569812\n56781934\n78123456": 10,   // 3-in-a-row vertically after middle shifts right
    "92345678\n39567812\n96781234\n78123456": 11,   // 3-in-a-row vertically after middle shifts left
    "12945678\n34967812\n59781234\n78123456": 12,   // 3-in-a-row vertically after bottom shifts right
    "12349678\n34569812\n56781934\n78123456": 13,   // 3-in-a-row vertically after bottom shifts left
    "12395678\n34567812\n56791234\n78193456": 14,   // 3-in-a-row vertically after top shifts down
    "12345698\n34567892\n56781234\n78123496": 15,   // 3-in-a-row vertically after bottom shifts up
    "12345678\n34567899\n96781234\n78123456": -1,   // No match - Matches (.)\1.\1 but not 3 in a row
    "12345679\n99567812\n56781234\n78123456": -1,   // No match - Matches (.).\1\1 but not 3 in a row
};

Редактировать 1

Заменить \ds на .- сохраняет 6 символов.

Редактировать 2

Заменить (?:.|\n)с [\s\S]и удалены дополнительными не-захватом групп и обновленными обратными ссылками (в соответствии с рекомендацией м-Бюттнером ) и добавленными в да / нет выхода.

Редактировать 3

  • Добавлено решение ECMAScript 6 для построения отдельных регулярных выражений из строки Base-18.
  • Убрал тесты для 3-в-ряд по горизонтали (как предложено m-buettner ).

Редактировать 4

Добавлено другое (более короткое) решение и еще два несоответствующих теста.

Редактировать 5

  • Укороченное оригинальное решение заменив символы новой строки нецифровым символом (согласно предложению VadimR ).

Редактировать 6

  • Укороченное оригинальное решение путем объединения битов регулярного выражения (как предложено VadimR ).

1
Отличное решение! Я бы не подумал, что регулярное выражение может работать. Пожалуйста, включите ?'yes':'no'в свой счет символов для справедливости, потому что это в требованиях, и все остальные используют его.
bdr9

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

Вау. +1 за регулярное выражение
DankMemes

Ч-мм, в JS нет модификатора для .соответствия любому символу, включая перевод строки? В Perl объединенное регулярное выражение - это всего лишь 129-байтовая строка (которая, будучи ленивой, я скомпилировал с помощью Regexp :: Assemble ), поэтому вся программа на Perl составляет около 150 байтов.
user2846289

1
@VadimR Спасибо, но вы можете пойти еще дальше, заменив .{8}|.{9}на .{8,9}и .{7}|.{8}с.{7,8}
MT0

3

Python 383

Всего одна * строка Python!

a=[list(l)for l in raw_input().split('\n')];z=any;e=enumerate;c=lambda b:z(all(p==b[y+v][x+u]for(u,v)in o)for y,r in e(b[:-2])for x,p in e(r[:-2])for o in [[(0,1),(0,2)],[(1,0),(2,0)]]);print z(c([[q if(i,j)==(m,n)else a[m][n]if(i,j)==(y+1,x+1)else p for j,p in e(r)]for i,r in e(a)])for y,t in e(a[1:-1])for x,q in e(t[1:-1])for n,m in((x+u,y+v)for u,v in[(1,0),(1,2),(0,1),(2,1)]))

* Ну, с точкой с запятой, но это все еще нетривиально в Python (однострочники Python - это весело! )


3
Upvoted для непонятных постижений :)
Александро-Brett

2

Node.js - Наивное решение - 905 байт

Ну, пока нет ответов, поэтому я выложу очень наивное решение в Node.js

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

Гольф (с компилятором google closure) (некоторые хакерские штуки там, такие как! 0 и! 1; я даже не уверен, что он сделал с моим свопом XOR)

Array.prototype.a=function(){for(var f=[],d=0;d<this.length;d++)f[d]=this[d].a?this[d].a():this[d];return f};for(var a=[],b=0;8>b;b++)a[b]=[];for(b=2;b<process.argv.length;b++)for(var c=process.argv[b].split(""),e=0;e<c.length;e++)a[b-2][e]=parseInt(c[e],10);function h(){for(var d=l,f=0;f<d.length-2;f++)for(var g=0;g<d[f].length-2;g++){var k=d[f][g];if(k==d[f+1][g]&&k==d[f+2][g]||k==d[f][g+1]&&k==d[f][g+2])return!0}return!1}function m(){console.log("yes");process.exit()}for(b=0;b<a.length;b++)for(e=0;e<a[b].length;e++){var l=a.a();0!=b&&(l[b-1][e]^=l[b][e],l[b][e]^=l[b-1][e],l[b-1][e]^=l[b][e],h()&&m(),l=a.a());b!=a.length-1&&(l[b+1][e]^=l[b][e],l[b][e]^=l[b+1][e],l[b+1][e]^=l[b][e],h()&&m(),l=a.a());0!=e&&(l[b][e-1]^=l[b][e],l[b][e]^=l[b][e-1],l[b][e-1]^=l[b][e],h()&&m(),l=a.a());e!=a[b].length-1&&(l[b][e+1]^=l[b][e],l[b][e]^=l[b][e+1],l[b][e+1]^=l[b][e],h()&&m(),l=a.a())}console.log("no");

Обратите внимание, что я написал все это на своем мобильном телефоне, и у меня нет времени, чтобы проверить это или что-то еще. Прокомментируйте, если вы обнаружите какие-либо ошибки, я проверю это позже.

Предварительно гольф-версия для чтения человеком

// set it up
Array.prototype.clone = function() {
    var arr = [];
    for( var i = 0; i < this.length; i++ ) {
        if( this[i].clone ) {
             arr[i] = this[i].clone();
        } else {
             arr[i] = this[i];
        }
    }
};
var board=[];
for(var i=0;i<8;i++)board[i]=[];
for(var i=2;i<process.argv.length;i++){
    var row=process.argv[i].split("");
    for(var j=0;j<row.length;j++)board[i-2][j]=parseInt(row[j], 10);
}
// function to test
function testBoard(arr){
    for(var i=0;i<arr.length-2;i++){
        for(var j=0;j<arr[i].length-2;j++){
            var val=arr[i][j];
            if(val==arr[i+1][j] && val==arr[i+2][j])return true;
            if(val==arr[i][j+1] && val==arr[i][j+2])return true;
        }
    }
    return false;
}
// functions to exit
function yay(){console.log("yes");process.exit();}
function nay(){console.log("no");}
// super slow naive solution time
for(var i=0;i<board.length;i++){
    for(var j=0;j<board[i].length;j++){
        var newboard=board.clone();
        if(i!=0){
            newboard[i-1][j]=newboard[i-1][j]^newboard[i][j];// whoa, it's a
            newboard[i][j]=newboard[i-1][j]^newboard[i][j];  // cool algorithm
            newboard[i-1][j]=newboard[i-1][j]^newboard[i][j];// at least this 
                                                             // isn't all naive
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
        if(i!=board.length-1){
            newboard[i+1][j]=newboard[i+1][j]^newboard[i][j];
            newboard[i][j]=newboard[i+1][j]^newboard[i][j];
            newboard[i+1][j]=newboard[i+1][j]^newboard[i][j];
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
        if(j!=0){
            newboard[i][j-1]=newboard[i][j-1]^newboard[i][j];
            newboard[i][j]=newboard[i][j-1]^newboard[i][j];
            newboard[i][j-1]=newboard[i][j-1]^newboard[i][j];
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
        if(j!=board[i].length-1){
            newboard[i][j+1]=newboard[i][j+1]^newboard[i][j];
            newboard[i][j]=newboard[i][j+1]^newboard[i][j];
            newboard[i][j+1]=newboard[i][j+1]^newboard[i][j];
            if(testBoard(newboard))yay();
            newboard=board.clone();
        }
    }
}
nay();

Ха, я пропустил первый пост на 10 минут. Хотя вроде как ...
DankMemes

Ах, точно такой же метод, который я использовал (наивный, но маленький код!). +1 за то, что был гораздо более наглядным, чем я
KSab

Интересно, есть ли более эффективный алгоритм ...
DankMemes

2

Perl, 114 96 95 93 92 87 86 85 байт

Включает + для -a0p

Запустите с помощью ввода на STDIN:

bejeweled.pl
12314131
13224145
54762673
61716653
61341144
23453774
27645426
75575656
^D

bejeweled.pl:

#!/usr/bin/perl -a0p
$i/s%.%chop$F[$i++&7]%eg>3|/(.)((.|\H{6}|\H{9})\1|\H{7}\1.)\1/||redo;$_=$1?yes:n.o

Это объединяет горизонтальное регулярное выражение в одном направлении с вращением

Объяснение:

В этом решении я буду многократно вращаться и выполнять следующие 4 теста:

/(.).\1\1/,      // 3-in-a-row horizontally after left-most shifts right
/(.)\C{9}\1\1/,  // 3-in-a-row horizontally after left-most shifts down
/(.)\C{7}\1.\1/, // 3-in-a-row horizontally after middle shifts down
/(.)\C{6}\1\1/,  // 3-in-a-row horizontally after right-most shifts down

Где \C"любой символ" (в отличие от .этого включает перевод строки). За исключением того, что \Cэто устарело и приводит к предупреждениям, поэтому я использую \H(не горизонтальное пространство) вместо этого, который достаточно хорош, чтобы захватить все цифры и новую строку.

После 4 оборотов пройдут все 16 необходимых тестов.

-p                            Read lines from STDIN, print $_ at the end
-0                            No line ending => slurp ALL of STDIN
-a                            Split $_ into @F. Since there are no spaces
                              on the rows this means each element of @F is
                              1 row

    s%.%chop$F[$i++&7]%eg     Replace each row by the removed last column
                              This is therefore a left rotation. Very short
                              but at the cost of using @F. To make sure that
                              @F gets refilled from $_ each time I won't be
                              able to use while, until, eval or do$0 for the
                              loops but have to use redo. That costs a few
                              bytes but less than having to do my own split
$i/                      >3   The previous regex replacement always
                              returns 64 and each time through the loop $i is
                              increased by 64. So if this division reaches
                              4 all rotations have been done

/(.)((.|\H{6}|\H{9})\1|\H{7}\1.)\1/ This is the 4 regexes mentioned above
  ||redo                      Stop the loop if the regex matches or we
                              rotated 4 times
$_=$1?yes:n.o                If the regex matched $1 will be one of the
                              color digits (which cannot be 0) and this will
                              assign "yes" to $_. If the regex didn't match
                              in 4 times $1 will get its value from the last
                              succesful regex in scope which will be the one
                              from the rotation, but that one doesn't have
                              any () so $1 will be unset. So in case there
                              is no move $_ will be set to "no" (which needs
                              to be constructed because "no" is a keyword)

1

Python3, 314B

import itertools as T,copy
r=[]
K=range(8)
J=[list(input())for w in K]
P=T.product
f=lambda A:["yes"for b in[A[m][n:]for m,n in P(K,K[:6])]if b[0]==b[1]==b[2]]
for i,j,x in P(K,K,[0,1]):
 t=j+1-x
 if i+x<8and t<8:B=copy.deepcopy(J);B[i][j],B[i+x][t]=B[i+x][t],B[i][j];r+=f(B)+f(list(zip(*B)))
r+=["no"]
print(r[0])

Измените 8, 5 в строке 6 и 8 в строке 9 для обработки произвольно больших входных размеров; Также не имеет значения, что представляет собой каждое значение, поэтому вы можете указать его:

absdefgh
sdkljahs
lsdfjasd
fjdhsdas
dkjhfasd
sdfhaskd
sdkfhkas
weriuwqe

и он вернется yes.

Аннотации

import itertools as T,copy 
            # itertools.product is going to save us lots of for loops
r=[]        # result
K=range(8)  # we can use range(8) everywhere, so this saves more than the usual R=range
J=[list(input())for w in K] 
            # input handling: keep everything as a length-1 string to avoid map(int,input())
P=T.product
f=lambda A:["yes"for b in[A[m][n:]for m,n in P(K,K[:6])]if b[0]==b[1]==b[2]] 
            # check the condition horiontally only. K[:6] is the same as range(5)
            # A[m][n:n+3] would be neater, but not actually needed
for i,j,x in P(K,K,[0,1]): 
            # <3 itertools.product! 3 for-loops without it.
            # NB we're only going right and downwards
 t=j+1-x
 if i+x<8and t<8: 
            # don't want out-of-bounds errors at the edges
  B=copy.deepcopy(J) 
            # preserve the reference array
  B[i][j],B[i+x][t]=B[i+x][t],B[i][j] 
            # do the switch
  r+=f(B)+f(list(zip(*B))) 
            # do the test. you could end up with lots of 'yes's in r.
            # zip(*B) takes the transpose, so that f checks the columns too
r+=["no"]   # happens to ensure that r is nonempty
print(r[0]) # only prints no if r was empty before the last line

1

GNU sed 255 + 2 = 257B

Я думал, что это будет не так хорошо, как Python, но сейчас: - / У меня сегодня не было доступа к интернету, поэтому я занялся решением этой проблемы в sed :). Должен вызываться с флагом -r, т.е. sed -rf command.sed < inputя добавил 2 к своему счету.

:a
$!N
s/\n/ /g
ta
:b
/^((\w)(\w\2\2|\2\w\2|\w\2\w* \w\2|\2\w* \w\w\2|\w* (\2\w* \w* \2|\w* \2\w* \2|\w\2\2|\w\2\w* \2|\2\w* \w\2|\w\2\w* \w\2))|\w((\w)(\w* \6\w\6|\6\w* \6|\w* (\6\w \w\6|\w\6\w* \6|\6\w* \6))|\w(\w)\w* \9\9))/c\yes
s/\w(\w*)/\1/g
tb
c\no

Как это устроено:

  1. Считать сетку в одну строку разделенных пробелами символов
  2. Используйте регулярное выражение motherload, чтобы узнать, есть ли совпадение в первом столбце * - если да, поменяйте местами всю строку на «да» (завершение программы)
  3. Уберите первый символ из каждого столбца и перейдите к 2, если мы сделали
  4. Если мы этого не сделали (строка пуста), замените всю строку на «нет»

1

Рубин, 201 байт

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

Ядро побитового арифметического алгоритма получено из этого фантастического ответа @leander на Game Stack Exchange .

s=$<.read
$><<(?1..?9).any?{|n|a=[0]*19
s.scan(n){i=$`.size
a[i/9+1]+=2**(i%9)
a[i%9+10]+=2**(i/9)}
a.each_cons(3).any?{|x,y,z|q=y&y<<1
l=q<<1
q>>=2
y&(l<<1|q>>1)|(q|l|(y&y<<2)>>1)&(x|z)>0}}?"yes":"no"

Рубиновая лямбда, 181 байт

Здесь это как лямбда, которая берет строку и возвращает trueили false:

->s{(?1..?9).any?{|n|a=[0]*19
s.scan(n){i=$`.size
a[i/9+1]+=2**(i%9)
a[i%9+10]+=2**(i/9)}
a.each_cons(3).any?{|x,y,z|q=y&y<<1
l=q<<1
q>>=2
y&(l<<1|q>>1)|(q|l|(y&y<<2)>>1)&(x|z)>0}}}

Смотрите его на repl.it: https://repl.it/ColJ/2

Ungolfed & объяснение

->s{
  (?1..?9).any? {|n|
    a = [0] * 19

    s.scan(n) {
      i = $`.size
      a[i/9+1] += 2**(i%9)
      a[i%9+10] += 2**(i/9)
    }

    a.each_cons(3).any? {|x,y,z|
      q = y & y << 1
      l = q << 1
      q >>= 2
      y & (l << 1 | q >> 1) |
        (q | l | (y & y << 2) >> 1) &
        (x | z) > 0
    }
  }
}

Код перебирает цифры от «1» до «9». Каждая итерация имеет два отдельных шага:

Первым шагом является преобразование платы, которое вы можете увидеть в s.scan(n)блоке в не раскрашенном коде. Он преобразует доску в массив из 8 целых чисел, по одному для каждой строки, обрабатывая совпадающие цифры как 1 и все остальные как 0 в двоичной строке. Например, взять строку 12231123. В первой итерации она становится двоичной строкой 10001100(все 1 становятся-эр, остаются-1, а все остальные цифры становятся 0), что является десятичным числом 140. Во второй итерации эта же строка становится 01100010(все 2 становятся 2 и все остальные цифры становятся 0) или десятичными 98.

Он одновременно выполняет второе преобразование, которое совпадает с первым, но с поворотом доски на 90 градусов. Это позволяет нам использовать ту же логику для горизонтальных совпадений, что и вертикальные. Для простоты он объединяет две платы в одну длинную с нулем в начале, серединой (для разделения двух плат) и концом для заполнения.

Второй шаг - поиск возможных совпадений, которые вы можете увидеть в each_cons(3).any?блоке. Преобразованные строки (которые теперь являются 8-разрядными целыми числами) проверяются в (перекрывающихся) группах по три строки ( x , y , z ) с использованием побитовой арифметики. Каждая группа проверяется, чтобы увидеть, можно ли найти совпадение в строке y , либо сместив фигуру в строке y, либо сместив фигуру в y из x или z . Поскольку перед и после строк с исходной и повернутой досками есть нулевой «ряд», нам не нужно проверять, находимся ли мы в первом или последнем ряду доски.

Если совпадений не найдено, оно продолжается до следующей итерации.

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