매트릭스에서 뱀 찾기


32

도전

이진 행렬과 이진 문자열이 주어지면, 이진 문자열이 행렬의 어느 지점에서나 이진 문자열을 형성하기 위해 임의의 후속 지점에서 어떤 방향으로 움직일 수 있는지 확인하십시오. 즉, 매트릭스 내부에서 문자열을 접을 수 있습니까?

끈은 90도 또는 180 도만 접을 수 있으며 (가장자리 연결 : Manhattan Distance 1) 어느 시점에서나 겹칠 수 없습니다.

다음 예제를 보자.

Matrix:

010101
111011
011010
011011

Snake: 0111111100101

이것은 진실한 테스트 사례입니다. 뱀이 다음 위치에서 접힌 것을 볼 수 있습니다.

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

규칙

  • 표준 허점 적용
  • 원하는 경우 문자열의 길이와 행렬의 너비와 높이를 입력으로 사용할 수 있습니다
  • 이진 행렬과 이진 문자열을 여러 줄로 된 문자열 / 문자열 / 줄 바꿈 된 문자열 / 다른 문자열이나 문자열로 사용할 수 있습니다.
  • 여러 인수 대신 차원을 평면 배열로 사용할 수 있습니다
  • 프로그램은 1 분 안에 최대 길이 10의 문자열로 5 x 5 행렬을 완료해야합니다

한계

  • 행렬은 반드시 정사각형 일 필요는 없습니다
  • 문자열이 비어 있지 않습니다
  • 문자열은 길이 1이 될 수 있습니다
  • 문자열은 사용 가능한 것보다 많은 제곱을 포함하지 않습니다 (즉, len(string) <= width(matrix) * height(matrix)

테스트 사례

Truthy

01010
10101
01010
10101
01010

0101010101010101010101010



01110
01100
10010
10110
01101

011111000110100



0

0



10
01

1010



100
010
001

100010001

거짓

00000
00000
00000
00000
00000

1



10101
01010
10101
01010
10101

11



100
010
001

111



10001
01010
00100
01010
10001

1000100010001000101010100


4
또는 : 이진 보글! 또한 몇 가지 테스트 사례를 추가 할 수 있습니까?
요나

1
이 상황에서 평평하고 날카 롭고 둥근 것은 무엇을 의미합니까? 정사각형은 너비와 높이가 같지 않거나 배열이 들쭉날쭉하다는 의미입니까?
Tahg

지구상에서 원형 배열
Conor O'Brien

답변:


13

파이썬 2 , 275 271 264 249 바이트

  • 대체하여 4 바이트를 저장 -1하여 H하나 개의 슬라이싱 연산을 제거 ( [:]).
  • Halvard Hummel 덕분에 7 바이트가 절약되었습니다 . [:]여러 대상 할당을 사용하여 방문한 항목에 값 v not in "01"( S=S[1:];M[y][x]=H;-> S=M[y][x]=S[1:];)을 제공하고 3 진 if / else에서 간단한 논리 또는 ( any(...)if S else 1-> not S or any(...))로 전환 하는 또 다른 슬라이싱 작업 ( )을 제거 합니다 .
  • 진실거짓에 대한 정의를 어느 정도 확장한다면 ,이 257 바이트 길이의 솔루션을 허용 할 수 있습니다 . ZeroDivisionError뱀이 발견되면 예외 ( )가 발생하고 찾을 []뱀이 없을 때 빈 목록 ( )이 리턴 됩니다.
  • user202729 덕분에 14 바이트를 절약했습니다 . 두 배열 딥 카피 골프
  • 바이트를 저장했습니다. golfed not S orS<[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])

온라인으로 사용해보십시오!

설명

행렬을 2 차원 문자열 목록 ( "0"또는 또는 "1")으로, 뱀을 1 차원 목록으로, 행렬 차원을 2 개의 정수로 취하는 Lambda 함수 .
람다 함수는 뱀의 첫 번째 요소와 일치하는 항목을 행렬에서 검색합니다. 발견 된 모든 일치에 대해, 그것은 H매트릭스의 깊은 사본, 뱀의 사본 없음, 매트릭스 치수 및 경기 위치를 호출 합니다.

H이 호출 되면 S'첫 번째 항목을 제거 하고 지정된 위치의 행렬 항목을 이외의 것으로 설정 "0", "1"합니다. 경우 S길이가 제로이다 ', 그것은 반환 True; 재귀 적으로 호출되면서 뱀은 매트릭스 어딘가에서 발견되었습니다. 길이가 0이 아닌
경우 S4 개의 기본 방향을 반복하여 해당 위치가 행렬에 있는지 테스트하고 해당 위치의 행렬 요소를 첫 번째 요소와 비교하고 S일치하는 경우 재귀 적으로 호출합니다.
H의 반환 값은 스택 프레임에 퍼지고, 적어도 하나의 함수가 가능한 뱀을 발견했는지 항상 확인합니다.

형식화 된 출력

뱀 슬리 더의 경로를 출력하도록 프로그램을 보강했습니다 (있는 경우). 질문과 동일한 ASCII 출력 디자인을 사용합니다. TIO 링크 .



1
@HalvardHummel 감사합니다; 불필요한 슬라이싱 작업을 발견하기 위해 특히.
Jonathan Frech

@ user202729 생각하세요 m[:]for~> m*1for? 작동 할 수 있습니다.
Jonathan Frech

@ user202729 감사합니다. 링크 된 팁은 딥 카피가 필요하다고 생각했습니다.
Jonathan Frech

9

자바 스크립트 (ES6) 138 134

@Neil과 크게 다르지 않지만 다른 무엇을 할 수 있습니까?

입력 : 행렬을 여러 줄 문자열, 이진 문자열, 너비 (줄 바꿈 제외)

NB : 재귀 함수의 논리 r는 몇 바이트를 절약하기 위해 약간 반전됩니다.

(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))

덜 골프

(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))
)

테스트

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>


6

자바 스크립트 (ES6), 149 바이트

(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)))

행렬을 개행으로 구분 된 문자열로, 뱀을 문자열로, 너비를 정수로 취합니다. @JonathanFrech의 답변을 느슨하게 기반으로합니다.


4

매쓰, 180 156 141 153 138 136 104 바이트

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

입력 예

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

설명

  1. GridGraph@{##4}A는 Graph치수 가장자리 연결된 인접 정점과 정점의 격자 객체 {##4}이고 - {#4,#5}또는 {width,height}.
  2. 우리는 반복 처리를 통해 모든 시작 정점 x(번호 11##4 = width*height) 모든 끝나는 정점 y, 그리고 모든 경로 p최대 길이의 #3에서 xy.
  3. 이러한 각 경로 ""<>Part[Join@@#,p]에 대해 매트릭스의 해당 문자를 추출하여 문자열에 넣습니다.
  4. 우리는 또한 행렬 자체를 포함하는데, 그 문자는 길이가 1 인 모든 문자열입니다.
  5. 우리는이 문자열 중 하나가 일치하는지 확인합니다. s이것은 우리가 구축 한 매우 다차원적인 목록이기 때문에 모든 수준에서 검색합니다.

주 : 교체 #3에 의해 {#3-1}에서 FindPath우리는 오직 딱 맞는 길이의 경로를 찾을 그래서, 속도 측면에서 큰 개선이 -하지만 4 바이트 이상 비용이 든다.


-24 바이트 : 사물의 치수를 입력으로 사용

-15 바이트 : 사용 StringPart하고 StringJoin제대로

+12 바이트 : 길이 1의 경우 수정

-15 바이트 : ...

-2 바이트 : 행렬의 크기를 배열로 입력으로 사용

-32 바이트 : Table경로를 반복 하여 사용 하면 사용을 피할 수 Function있으며 사용 MemberQ[...,s,All]하면 길이가 1 인 뱀을 다룰 때 테이블에 행렬을 붙일 수 있습니다.


3

C # (.NET 코어) , 346 (341) 336 (302) 297 바이트

(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;}}

온라인으로 사용해보십시오!

p증분 을 골퍼하여 5 바이트 절약

뱀 길이를 잡고 꼬리에서 시작하여 불필요한 공간을 제거하여 5 바이트 절약

챌린지를 올바르게 읽고 행렬의 높이와 너비를 취할 수 있음을 알면 34 바이트가 절약됩니다.

5 바이트가 절약되고 단일 요소 테스트 사례가 실패했으며 수정이 유익했습니다.

언 골프

(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; 
    }
}

골프 시작은 불필요한 공백을 모두 제거하는 것입니다.
Jonathan Frech

if(...)return true;-> return ...;.
Jonathan Frech

@JonathanFrech Agreed, 그러나 나는 그것을 다시 얻을 기회가 생길 때까지 (내일) 다른 사람들이 좀 더 쉽게 읽을 수 있도록 그것을 그대로 두었습니다.
Ayb4btu

@JonathanFrech 작동하지 않습니다 b[y,x]. 어느 시점에서 재설정해야합니다. (내 답변에 귀하의 이름을 잘못 입력하여 죄송합니다.)
Neil

나는 의미했다 if(N(x,y,0)>0)return 0<1;; 의 첫 등장 return.
Jonathan Frech

1

코 틀린 , 413 바이트

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)}}}

미화

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) } }
}

테스트

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")
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.