Визначте, чи існує хід у грі Bejeweled / match 3


20

Фон

У Bejeweled та подібних іграх гравець повинен поміняти будь-які дві сусідні дорогоцінні камені (без діагоналей) у сітці із дорогоцінними каменями розміром 8х8, щоб відповідати трьом однаковим кольором поспіль. Самоцвіти можуть відповідати горизонтально або вертикально. Ігровий процес триває до тих пір, поки не існує жодного ходу, який можна зробити внаслідок чого три поспіль, після чого гра закінчена.

Завдання

Мета - написати програму, яка визначає, чи гра 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 Стовпці теж. Коли я вживаю фразу "три підряд", я маю на увазі, що вони повинні бути вишиковані в горизонтальному або вертикальному напрямку.
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-х рядів горизонтально та вертикально, як заявляє ОП, вони ніколи не будуть присутні - якщо ви хочете додати ці тести ще в додатку 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 для regex
DankMemes

Н-мм, без модифікатора в JS, .щоб відповідати будь-якому символу, включаючи новий рядок? У Perl комбінований регулярний вираз - це лише 129 байт-рядок (який, ліниво, я компілював з Regexp :: Assemble ), тому вся програма Perl становить близько 150 байт.
користувач2846289

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

3

Пітон 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 one-liner - це весело! )


3
Оголошено за незрозумілі розуміння :)
Олександр-Бретт

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. Використовуйте регекс материнського завантаження, щоб дізнатися, чи є відповідність у першому стовпчику * - якщо так, поміняйте весь рядок на "так" (закінчення програми)
  3. Стріліть перший символ із кожного стовпця та перейдіть до 2, якщо ми це зробили
  4. Якщо ми цього не зробили (рядок порожній) замініть весь рядок на "ні"

1

Ruby, 201 байт

Я був розчарований, що не бачив жодного рішення цього великого виклику, в якому не використовуються регулярні вирази або грубі сили (хоча вони чудові), тому я написав його. Він приймає дані про STDIN.

Ядровий арифметичний алгоритм походить від цього фантастичного відповіді на @leander на грі Stack Development Game.

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

Необурені та пояснення

->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 цілих чисел, по одному для кожного рядка, трактуючи відповідні цифри як 1s, а всі інші як 0s у двійковому рядку. Наприклад, візьміть рядок 12231123. У першій ітерації це стане двійковим рядком 10001100(усі 1 стають — er, stay — 1s, а всі інші цифри стають 0s), що є десятковим числом 140. У другій ітерації стає тим самим рядком 01100010(всі 2s стають 2s і всі інші цифри стають 0s) або десятковими 98.

Він одночасно здійснює друге перетворення, яке є таким же, як і перше, але з дошкою, поверненою на 90 градусів. Це дозволяє нам використовувати ту саму логіку для створення горизонтальних сірників, що й вертикальні. Для простоти він об'єднує дві дошки в одну довгу з нулем на початку, середній (для розділення двох дощок) і кінець для оббивки.

Другий крок - пошук можливих відповідностей, які ви можете побачити в each_cons(3).any?блоці. Трансформовані рядки (які зараз є 8-бітовими цілими числами) перевіряються (перекриваються) групами з трьох рядків ( x , y , z ) за допомогою побітової арифметики. Кожну групу перевіряють, чи може бути відповідність у рядку y , або зміщенням фрагмента у рядку y, або переміщенням шматка у у від x або z . Оскільки є нульовий "рядок" до і після початкових і повернутих рядків дощок, нам не доведеться перевіряти, чи ми знаходимося в першому чи останньому рядку дошки.

Якщо не знайдено збігів, це продовжується до наступної ітерації.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.