Menemukan Ular dalam Matriks

32

Tantangan

Diberikan matriks biner dan string biner, tentukan apakah string biner itu dapat ditemukan mulai dari titik mana saja dalam matriks dan bergerak ke segala arah pada titik selanjutnya untuk membentuk string biner. Artinya, dapatkah string ditemukan terlipat di dalam matriks?

Tali hanya dapat dilipat pada 90 derajat atau 180 derajat (koneksi tepi; Manhattan Distance 1) dan tidak dapat tumpang tindih dengan sendirinya di titik mana pun.

Contoh

Mari kita ambil contoh berikut:

Matrix:

010101
111011
011010
011011

Snake: 0111111100101

Ini adalah kasus uji kebenaran. Kita bisa melihat ular terlipat di posisi berikut:

0-1 0 1 0 1
  |
1 1 1-0 1 1
  | | |   |
0 1 1 0-1-0
  | |
0 1-1 0 1 1

Aturan

  • Celah Standar Berlaku
  • Anda dapat mengambil panjang string dan lebar dan tinggi matriks sebagai input jika Anda mau
  • Anda dapat menggunakan matriks biner dan string biner sebagai string multiline / array string / string yang tergabung dengan baris baru / string apa pun yang tergabung dan string
  • Anda dapat mengambil dimensi sebagai susunan datar alih-alih beberapa argumen
  • Program Anda harus menyelesaikan untuk setiap matriks 5 x 5 dengan string hingga panjang 10 dalam waktu kurang dari satu menit

Keterbatasan

  • Matriksnya tidak harus persegi
  • String tidak akan kosong
  • String bisa panjang-1
  • String tidak akan mengandung lebih banyak kotak daripada yang tersedia (yaitu, len(string) <= width(matrix) * height(matrix)

Uji Kasus

Sejujurnya

01010
10101
01010
10101
01010

0101010101010101010101010



01110
01100
10010
10110
01101

011111000110100



0

0



10
01

1010



100
010
001

100010001

Palsu

00000
00000
00000
00000
00000

1



10101
01010
10101
01010
10101

11



100
010
001

111



10001
01010
00100
01010
10001

1000100010001000101010100
HyperNeutrino
sumber
Sandbox Post (Dihapus)
HyperNeutrino
4
Atau: Binary Boggle! Juga, dapatkah Anda menambahkan beberapa lagi test case?
Jonah
1
Apa arti datar, tajam, dan bulat dalam konteks ini? Apakah tidak persegi berarti bahwa lebar dan tinggi mungkin tidak sama, atau array dapat bergerigi?
Tahg
apa yang di bumi adalah array bulat
Conor O'Brien
Terkait
Martin Ender

Jawaban:

13

Python 2 , 275 271 264 249 byte

  • Menyelamatkan empat byte dengan mengganti -1dengan Hdan menghapus satu operasi mengiris ( [:]).
  • Disimpan tujuh byte berkat Halvard Hummel ; menghapus operasi slicing lain ( [:]), menggunakan penugasan multi-target untuk memberikan entri yang dikunjungi nilai v not in "01"(S=S[1:];M[y][x]=H; -> S=M[y][x]=S[1:];) dan beralih dari terner jika / selain ke logika sederhana atau ( any(...)if S else 1-> not S or any(...)).
  • Jika Anda agak memperpanjang definisi Anda tentang truthy dan falsey , Anda bisa membiarkan ini solusi jangka 257 byte . Ini menimbulkan pengecualian ( ZeroDivisionError) ketika ular ditemukan dan mengembalikan daftar kosong ( []) ketika tidak ada ular yang ditemukan, yang merupakan dua perilaku berbeda.
  • Disimpan empat belas byte berkat pengguna202729 ; bermain golf dua array dalam
  • Disimpan satu byte; golf not S orke S<[1]or~ S==[]or.
lambda M,S,w,h:any(H(eval(`M`),S,w,h,x,y)for y in range(h)for x in range(w)if S[0]==M[y][x])
def H(M,S,w,h,x,y):S=M[y][x]=S[1:];return S<[1]or any(H(eval(`M`),S,w,h,x+X,y+Y)for X,Y in[(~0,0),(1,0),(0,~0),(0,1)]if~0<x+X<w>0<=y+Y<h!=S[0]==M[y+Y][x+X])

Cobalah online!

Penjelasan

Fungsi Lambda yang mengambil dalam matriks sebagai daftar string dua dimensi (salah satu "0"atau "1"), ular sebagai daftar satu dimensi dan dimensi matriks sebagai dua bilangan bulat.
Fungsi lambda mencari matriks untuk entri yang cocok dengan elemen pertama ular. Untuk setiap kecocokan yang ditemukan, ia memanggilH dengan salinan yang dalam dari matriks, tidak ada salinan dari ular, dimensi matriks dan posisi pertandingan.

Ketika Hdipanggil, ia menghapus Sentri pertama dan mengatur entri matriks posisi yang diberikan ke sesuatu yang lain selain "0", "1". Jika S'panjang adalah nol, itu akan kembali True; karena ia menyebut dirinya secara rekursif, ular itu ditemukan di suatu tempat dalam matriks.
Jika S'panjangnya bukan nol, ia akan melewati empat arah mata angin, menguji apakah posisi itu dalam matriks, membandingkan elemen matriks' pada posisi itu dengan elemen pertama Sdan - jika cocok - menyebut dirinya secara rekursif.
HNilai kembali disalurkan ke atas bingkai tumpukan, selalu memeriksa apakah setidaknya satu fungsi menemukan kemungkinan ular.

Output Terformat

Saya telah menambahkan program saya untuk juga menampilkan jalur slithers ular (jika ada). Ia menggunakan desain keluaran ASCII yang sama dengan pertanyaan. TIO link .

Jonathan Frech
sumber
264 bytes
Halvard Hummel
1
@HalvardHummel Terima kasih; terutama untuk melihat operasi pengirisan berlebihan.
Jonathan Frech
@ user202729 Menurut Anda m[:]for~> m*1for? Mungkin bekerja
Jonathan Frech
@ user202729 Terima kasih, tip yang terhubung berfungsi karena saya pikir ini membutuhkan salinan yang dalam.
Jonathan Frech
9

JavaScript (ES6), 138 134

Tidak jauh berbeda dengan @ Neil, tapi apa lagi itu?

Input: matriks sebagai string multi baris, string biner, lebar (tidak termasuk baris baru)

NB: logika dalam fungsi rekursif ragak terbalik untuk menyimpan beberapa byte

(m,s,w)=>[...m].some((c,p,m,r=(p,o)=>s[m[p]=r,o]&&([~w,-~w,1,-1].every(d=>m[d+=p]!=s[o]||r(d,o+1))&&(m[p]=s[o-1])))=>c==s[0]&&!r(p,1))

Kurang golf

(m,s,w)=>(
  m=[...m],
  r= (p, o) => 
    (m[p] = -w, s[o])
    && (
         [~w, -~w, 1, -1].every( d =>
            m[d+=p] != s[o] || r(d, o+1)
         )
         && (m[p]=s[o-1])
    ),
  m.some((c,p) =>c == s[0] && !r(p,1))
)

Uji

var F=
(m,s,w)=>[...m].some((c,p,m,r=(p,o)=>s[m[p]=r,o]&&([~w,-~w,1,-1].every(d=>m[d+=p]!=s[o]||r(d,o+1))&&(m[p]=s[o-1])))=>c==s[0]&&!r(p,1))

// this slightly modified version tracks the path
var Mark=
(m,s,w)=>(m=[...m]).some((c,p,m,r=(p,o)=>s[m[p]=-o,o]&&([~w,-~w,1,-1].every(d=>m[d+=p]!=s[o]||r(d,o+1))&&(m[p]=s[o-1])))=>c==s[0]&&!r(p,1))
?m.map((c,p)=>c<-1?'.───│┘└.│┐┌.│'[((m[p-1]-c)**2<2)+((m[p+1]-c)**2<2)*2+((m[p+~w]-c)**2<2)*4+((m[p-~w]-c)**2<2)*8]:c<0?'*':c).join``:''

function go()
{
  O.textContent =F(M.value, S.value, M.value.search('\n'))+'\n\n'
  +Mark(M.value, S.value, M.value.search('\n'))
}

go()
#M {width:100px; height:100px }
<textarea id=M>010101
111011
011010
011011</textarea><br>
<input id=S value='0111111100101' oninput='go()'>
<button onclick='go()'>go</button>
<pre id=O></pre>

edc65
sumber
6

JavaScript (ES6), 149 byte

(m,s,w)=>[...m].some((c,i)=>c==s[0]&&g(m,s,i),g=(m,s,i)=>!(s=s.slice(1))||[~w,-1,1,-~w].some(o=>m[o+=i]==s[0]&&g(m.slice(0,i)+' '+m.slice(i+1),s,o)))

Mengambil matriks sebagai string yang dibatasi-baris baru, ular sebagai string dan lebar (sebagai integer). Secara longgar didasarkan pada jawaban @ JonathanFrech.

Neil
sumber
4

Mathematica, 180 156 141 153 138 136 104 byte

MemberQ[#|Table[""<>Part[Join@@#,p],{x,1##4},{y,1##4},{p,FindPath[GridGraph@{##4},x,y,#3,All]}],#2,All]&

Contoh input

[{{"1","1","1","1","1"},{"0","0","0","0","0"}},"10011001",8,5,2]

Penjelasan

  1. GridGraph@{##4}adalah Graphobjek untuk kisi-kisi simpul dengan simpul-simpul yang berdekatan yang dihubungkan oleh tepian, dengan dimensi {##4}- yaitu, {#4,#5}atau {width,height}.
  2. Kami mengulangi semua simpul awal x(dinomori 1ke 1##4 = width*height), semua simpul akhir y, dan semua jalur ppanjang paling banyak #3dari xhingga y.
  3. Untuk setiap jalur seperti itu, ""<>Part[Join@@#,p]ekstrak karakter yang sesuai dari matriks dan menempatkannya ke dalam string.
  4. Kami juga menyertakan matriks itu sendiri, yang karakternya adalah semua string dengan panjang 1 yang dapat ditemukan di dalamnya.
  5. Kami melihat apakah salah satu dari string ini cocok s, mencari di semua level karena ini adalah daftar yang sangat multidimensi yang telah kami buat.

Catatan: Mengganti #3dengan {#3-1}dalam FindPath, sehingga kami hanya menemukan jalur dengan panjang yang tepat, merupakan peningkatan besar dalam hal kecepatan - tetapi biaya 4 byte lebih banyak.


-24 byte: mengambil dimensi benda sebagai input

-15 byte: menggunakan StringPartdan StringJoinbenar

+12 byte: memperbaiki casing panjang-1

-15 byte: ...

-2 byte: mengambil ukuran dari matriks sebagai input sebagai array

-32 bytes: menggunakan Tableuntuk beralih di jalan memungkinkan kita menghindari menggunakan Function, dan menggunakan MemberQ[...,s,All]memungkinkan kita hanya semacam menempelkan matriks ke atas meja ketika berhadapan dengan ular panjang 1.

Misha Lavrov
sumber
3

C # (.NET Core) , 346 341 336 302 297 byte

(m,h,w,s,l)=>{for(int y=0;y<h;y++)for(int x=0;x<w;x++)if(N(x,y,l-1))return 0<1;return 1<0;bool N(int x,int y,int p){if(p<0)return 0<1;if(y<0|x<0|y==h|x==w||m[y,x]>1||s[p]!=m[y,x])return 1<0;int g=m[y,x];m[y,x]=2;if(N(x,y-1,--p)||N(x-1,y,p)||N(x,y+1,p)||N(x+1,y,p))return 0<1;m[y,x]=g;return 1<0;}}

Cobalah online!

5 byte disimpan dengan pmenambahkan golf

5 byte disimpan dengan mengambil panjang ular dan mulai dari ekornya, dan menghilangkan ruang yang tidak perlu

34 byte disimpan dengan membaca tantangan dengan benar dan melihat saya dapat memperhitungkan tinggi dan lebar matriks

5 byte disimpan, kasus uji elemen tunggal gagal, dan perbaikannya bermanfaat

Tidak disatukan

(m,h,w,s,l)=>{
    // Go through every potential starting point
    for(int y=0; y<h; y++)
        for(int x=0; x<w; x++)
            if(N(x,y,l-1)) // start the recursive steps
                return 0<1; // return true if N returns true, otherwise check the next element

    return 1<0; // return false as the snake doesn't fit into the matrix

    // C#7 local function in a Func
    bool N(int x, int y, int p)
    {
        // if there is no more snake to fit return true
        if(p<0)
            return 0<1;

        // if m element has part of the snake or 
        // snake part doesn't match matrix element then return false
        if(y<0 | x<0 | y==h | x==w || m[y,x]>1 || s[p] != m[y,x])
            return 1<0;

        // hold the current matrix element
        int g=m[y,x];
        // set the current matrix element to 2 to indicate it has a part of the snake
        m[y,x]=2;

        // check each of the four neighbours and recurse down that neighbour 
        // except if they are outside the matrix
        if(N(x,y-1,--p) ||
           N(x-1,y,p) ||
           N(x,y+1,p) ||
           N(x+1,y,p))
               return 0<1; // return true if remainder of the snake fits into the matrix

        // if snake doesn't fit then set the matrix element as not having part of the snake
        m[y,x]=g;
        // return false to indicate this neighbour direction doesn't fit the snake
        return 1<0; 
    }
}
Ayb4btu
sumber
Awal bermain golf adalah menghapus semua spasi yang tidak perlu ...
Jonathan Frech
if(...)return true;-> return ...;.
Jonathan Frech
@JonathanFrech Setuju, tetapi saya membiarkannya seperti itu untuk memungkinkan orang lain membacanya sedikit lebih mudah sampai saya mendapatkan kesempatan untuk kembali ke sana (besok pagi).
Ayb4btu
@JonathanFrech Tidak berfungsi, b[y,x]perlu diatur ulang di beberapa titik. (Juga maaf karena salah mengeja nama Anda dalam jawaban saya.)
Neil
Maksud saya if(N(x,y,0)>0)return 0<1;; penampilan pertama return.
Jonathan Frech
1

Kotlin , 413 byte

var x:(Array<Array<Char>>,String)->Boolean={b,s->fun f(s:String,x:Int,y:Int):Boolean{if(b[x][y]!=s[0])
return 0>1
if(s.length<2)
return 1>0
val v=b[x][y]
b[x][y]='Z'
try{return(-1..1).map{x+it}.flatMap{t->(-1..1).map{y+it}.map{t to it}}.filter{(X,Y)->(x-X)*(x-X)+(y-Y)*(y-Y)==1&&X in b.indices&&Y in b[0].indices&&f(s.substring(1),X,Y)}.any()}finally{b[x][y]=v}}
b.indices.any{x->(0..b[0].size-1).any{f(s,x,it)}}}

Yg diperindahkan

var x: (Array<Array<Char>>, String) -> Boolean = { b, s ->
    fun f(s: String, x: Int, y: Int): Boolean {
        if (b[x][y] != s[0])
            return 0 > 1
        if (s.length < 2)
            return 1 > 0
        val v = b[x][y]
        b[x][y] = 'Z'
        try {
            return (-1..1).map{ x + it }
                    .flatMap { t -> (-1..1).map{y+it}.map { t to it } }
                    .filter { (X, Y) ->
                        (x - X)*(x - X) + (y - Y)*(y - Y) == 1 &&
                                X in b.indices && Y in b[0].indices &&
                                f(s.substring(1), X, Y) }
                    .any()
        } finally {
            b[x][y] = v
        }
    }
    b.indices.any { x -> (0..b[0].size - 1).any { f(s, x, it) } }
}

Uji

var x:(Array<Array<Char>>,String)->Boolean={b,s->fun f(s:String,x:Int,y:Int):Boolean{if(b[x][y]!=s[0])
return 0>1
if(s.length<2)
return 1>0
val v=b[x][y]
b[x][y]='Z'
try{return(-1..1).map{x+it}.flatMap{t->(-1..1).map{y+it}.map{t to it}}.filter{(X,Y)->(x-X)*(x-X)+(y-Y)*(y-Y)==1&&X in b.indices&&Y in b[0].indices&&f(s.substring(1),X,Y)}.any()}finally{b[x][y]=v}}
b.indices.any{x->(0..b[0].size-1).any{f(s,x,it)}}}

data class Test(val board: String, val snake: String, val output: Boolean)

val tests = listOf(
        Test("""01010
            |10101
            |01010
            |10101
            |01010""", "0101010101010101010101010", true),
        Test("""01110
            |01100
            |10010
            |10110
            |01101""", "011111000110100", true),
        Test("""0""", "0", true),
        Test("""10
            |01""", "1010", true),
        Test("""100
            |010
            |001""", "100010001", true),
        Test("""00000
            |00000
            |00000
            |00000
            |00000""", "1", false),
        Test("""10101
            |01010
            |10101
            |01010
            |10101""", "11", false),
        Test("""100
            |010
            |001""", "111", false),
        Test("""10001
            |01010
            |00100
            |01010
            |10001""", "1000100010001000101010100", false)
)

fun main(args: Array<String>) {
    tests.filter {(board, snake, expected) ->
        val boardR = board.trimMargin().lines().map { it.toCharArray().toTypedArray() }.toTypedArray()
        val result = x(boardR, snake)
        result != expected
    }.forEach { throw AssertionError(it) }
    println("Test Passed")
}
jrtapsell
sumber