레이저 대상과 일치하는 미러 구성 찾기


13

업데이트 된 점수 : 이 도전이 예상보다 어렵 기 때문에 점수를 조정했습니다. 단일 미러 입력을 해결할 수있는 프로그램이 올바른 답입니다. 보다 정교한 프로그램은 점수에 보너스를받습니다.

거울 상자에서 레이저 경로를 찾기 위해 PPCG에 몇 가지 퍼즐이 있습니다. 이 퍼즐에서는 여러 레이저 대상에 맞게 거울 상자 를 만들어야 합니다.

레이저가 들어오고 나가는 상자와 사양이 제공됩니다. 프로그램은 사양에 맞게 상자에 정확히 N 개의 양면 거울을 배치해야합니다. 미러는 45도 각도를 가져야하지만 전방 경사 또는 후방 경사 일 수 있습니다.

입력

프로그램은 STDIN, 명령 행 인수 또는 다음 형식 예제의 파일을 통해 상자 그리드를 승인해야합니다.

+--G--+     +abcde+
G     |     f/////d
|    /|     a//   c
+-----+     f     |
            +-b-e-+

문자 쌍 ([a-zA-Z]이 사용될 수 있음)은 최대 52 개의 레이저의 입력 / 출력을 나타냅니다. 상자 안에는 N 개의 /거울 이 있습니다 . 상자 크기는 3 <= W, H <= 200입니다. 상자는 +|-문자로 구성됩니다. 상자에 0을 포함하여 여러 개의 거울이있을 수 있습니다.

산출

/문자가 이동 및 / 또는 \문자 로 변경 될 수 있다는 점을 제외하고 출력은 입력과 일치해야 합니다. 프로그램은 올바른 미러 박스 문자열을 STDOUT 또는 파일로 보내야하며, 새 줄은 선택 사항입니다. 입력 배치를 충족 할 수있는 미러 배치가 없으면 output을 출력하십시오 Impossible\n. 가능한 솔루션의 예 :

+--G--+     +abcde+
G  /  |     f \ \ d
|     |     a/ \  c
+-----+     f / //|
            +-b-e-+

테스트 예

입력:

+abcdefghijklmnopqrstuvwxyA-+
|///////////////            |
|///////////////            |
|                           |
+-Abcdefghijklmnopqrstuvwxya+

출력 예 :

+abcdefghijklmnopqrstuvwxyA-+
|\                         \|
|/                        / |
|\\\\\\\\\\\\\\\\\\\\\\\\\\ |
+-Abcdefghijklmnopqrstuvwxya+

스코어링 (업데이트 됨)

이것은 보너스가있는 코드 골프입니다. 프로그램이 몇 개의 미러를 풀 수 있는지를 답으로 지정해야합니다 (N). 당신의 점수는 N으로 나눈 바이트 단위의 프로그램 길이입니다. 이것은 사람들이 간단한 프로그램으로 입장 할 수있게하지만 더 많은 야망 프로그래머에게 보너스를줍니다.

표준 허점은 허용되지 않습니다.


3
골프와 상관없이 어려운 문제인 것 같습니다.
orlp

2
힌트 : 무차별 대입 은 옵션이 아닙니다 . 더 큰 예를 들어 초당 10k 옵션으로 3 개의 우주 나이가 필요합니다.
Sanchises

@sanchises 나는 어떤 거울이 이성을 상실 할 수 있습니다 나는 당신이 필요가 있다고 생각 그래서, 더 큰 거래를 취할 것입니다 생각 * 2^30뿐만 아니라 거기에 구성 요소를
VisualMelon

추가 힌트 : 검색 공간을 정리하려면 퍼즐의 속성을 활용해야합니다. 전체 솔루션에 가까운 부분 솔루션의 부분 솔루션 또는 언덕 등반 조합을 사용할 수도 있습니다. 이제 더 간단한 솔루션으로 대답하는 것이 유효하므로 하나 또는 두 개의 미러 퍼즐을 해결하는 프로그램도 환영합니다.
로직 나이트

답변:


2

C # -897 862 바이트

거울을 놓을 수없는 곳에 심각한 버그가 있음을 발견했습니다. 이제 잘 작동합니다! 또한 약간의 가벼운 골프를 쳤다, 거기에서 while 루프를 떠날 수 없었다. .. 부끄러운.

완전한 프로그램은 STDIN에서 입력을 받아 STDOUT으로 출력합니다.

이것은 많은 재미였습니다 .7 x 5 문제에 잘 대처하고 (거울 중 하나를 제거하면 불가능 해집니다) 30 x 5를 해결하는 데 약 1 시간이 걸렸습니다.

using Q=System.Console;class P{static int w,L;static string S(char[]M,int t,int r,int i,int d,int[]B){var s="";if(r<0)return s;M=(char[])M.Clone();B=(int[])B.Clone();B[i]=1;for(i+=d;M[t]<48|t==i;i=t+(d=t<w?w:t>L-w?-w:t%w<1?1:-1))if(++t>=L){for(i=0;++i<L&r>0;)if(B[i]<1&M[i]<33){M[i]='.';r--;}return r<1?new string(M):s;}int c=M[i];if(c>32)s=c>47|c<46?s=c==M[t]?S(M,t,r,t,0,B):s:S(M,t,r,i,c<47?w/d:-w/d,B);else if((s=S(M,t,r,i,d,B))==""&B[i]<1){M[i]='.';s=S(M,t,r-1,i,w/d,B);if(s==""){M[i]='/';s=S(M,t,r-1,i,-w/d,B);}}return s;}static void Main(){string a,A="",R=A;for(;(a=Q.ReadLine())!=null;A+=a)L+=(w=a.Length);var G=A.ToCharArray();int r=0,i=L;for(;i>0;G[i]=G[i]=='|'?',':G[i])if(G[--i]==47|G[i]==92){r++;G[i]=' ';}a=S(G,0,r,1,w,new int[L]);if(a=="")R="Impossible\n";else for(;i<L;i+=w)R+=a.Substring(i,w)+"\n";Q.Write(R.Replace(".","\\").Replace(",","|"));}}

7x5 예 :

+abcde+
f/////d
a//   c
f     |
+-b-e-+

+abcde+
f   \ d
a/  //c
f/ \ /|
+-b-e-+

불가능한 버전 :

+abcde+
f ////d
a//   c
f     |
+-b-e-+

Impossible

다른 것 (프로그램은 원래 거울 레이아웃을 보지 않습니다) :

+a----+
|//// |
|/////|
|/////|
+----a+

+a----+
| /\\\|
|\\\\\|
|\\/\\|
+----a+

30 x 5 솔루션 :

+abcdefghijklmnopqrstuvwxyA-+
| \\\\\\\\\\\\\\\\\\\\\\\\ \|
| /                       //|
|\                         \|
+-Abcdefghijklmnopqrstuvwxya+

각 레이저 소스를 차례로보고 유효한 경로를 만들고 (가능한 경우) 다음 경로로 이동합니다. 보고있는 레이저 소스 (대상), 배치 할 미러 수, "현재"셀, 이동 방향 및 각 셀을 알아야하는 매우 간단한 깊이 우선 검색입니다. 이미 방문했습니다 (이미 어딘가에 거울을 두지 않습니다). 마지막 3 개는 현재 대상의 경로를 조립하는 데 사용되며 대상이 변경 될 때 재설정됩니다. 일단 모든 레이저가 연결되면, 계속해서 비워 둘 필요가없는 틈새를 채 웁니다 (방문하는 모든 곳을 알아야하는 또 다른 이유).

루트를 구축 할 때 미러를 삽입하는 것보다 "앞으로"진행하는 것이 좋으며, 그렇게 할 때는 "\"미러를 선호합니다. 위의 "다른 것"예에서 가장 잘 보입니다. 아래의 첫 번째 셀을 건너 뜁니다. 최상위 'a'인 경우 솔루션으로 솔루션을 찾을 수 있으면 "\"를 채우고 그렇지 않으면 "/"(자연스럽게 첫 번째 셀을 건너 뛰면 솔루션을 찾을 수없는 경우)를 채 웁니다. 역 추적하고 대신 거울을 배치하십시오).

using Q=System.Console;

class P
{
    static int w,L;

    // M is cur grid
    // t is target edge thing (0->L)
    // r is mirrors remaining
    // i is pos
    // d is dir
    static string S(char[]M,int t,int r,int i,int d,int[]B)
    {
        var s="";

        if(r<0) // no mirrors left
            return s;

        // clone everything
        M=(char[])M.Clone();
        B=(int[])B.Clone();

        B[i]=1; // can't write to this

        for(i+=d; // move i
            M[t]<48|t==i; // only if target is something sensible (increment if i==t)
            i=t+(d=t<w?w:t>L-w?-w:t%w<1?1:-1)) // reflect, should be fine for w=3
            if(++t>=L) // run off the end
            {
                for(i=0;++i<L&r>0;) // don't need I any more (count through everything)
                    if(B[i]<1&M[i]<33) // not been here & it's open space
                    {
                        M[i]='.'; // doesn't matter
                        r--;
                    }
                return r<1?new string(M):s; // none remaining ? victory : defeat
            }

        int c=M[i];
        if(c>32) // not boring
            s=c>47|c<46? // hit edge
                s=c==M[t]? // hit the correct thing
                    S(M,t,r,t,0,B): // i+0=t, tells it to increment t
                    s
            :S(M,t,r,i,c<47?w/d:-w/d,B); // mirror
        else // boring
            if((s=S(M,t,r,i,d,B))==""&B[i]<1) // fwd
            {
                M[i]='.'; // use . instead of \
                s=S(M,t,r-1,i,w/d,B); // \
                if(s=="")
                {
                    M[i]='/';
                    s=S(M,t,r-1,i,-w/d,B); // /
                }
            }

        return s;
    }

    static void Main()
    {
        string a,A="",R=A; // R is free
        for(;(a=Q.ReadLine())!=null;A+=a) // read input
            L+=(w=a.Length); // note width, accumulate length

        var G=A.ToCharArray();

        int r=0,i=L; // count mirrors (I refuse to make these static)
        for(;i>0; // end on i=0
            G[i]=G[i]=='|'?',':G[i]) // replace | with ,
            if(G[--i]==47|G[i]==92) // remove and count mirrors
            {
                r++;
                G[i]=' '; // storing G[i] doesn't seem to save anything
            }

        // search
        a=S(G,0,r,1,w,new int[L]);

        if(a=="") // defeat
            R="Impossible\n";
        else // victory
            for(;i<L;i+=w) // for each line
                R+=a.Substring(i,w)+"\n";

        Q.Write(R.Replace(".","\\").Replace(",","|")); // swap back | and \
    }
}

좋은 해결책. 새로운 점수 시스템에 따르면 최소 917/7 = 131을 기록합니다.
Logic Knight

2

파이썬, 671654 바이트

해결책이 아니라 시도는 아래를 읽으십시오.

import random as R
def V(F):
 for S,_x,_y in (F[0],0,1),(F[-1],0,-1),([L[0] for L in F],1,0),([L[-1] for L in F],-1,0):
  for i,C in enumerate(S):
   if not C in '+-|':
    x=_x;y=_y
    if not x: X=i;Y=y
    elif not y: Y=i;X=x
    while F[Y][X] != C:
     if F[Y][X]=='\\':x,y=y,x
     if F[Y][X]=='/':a=x+y;x,y=x-a,y-a
     X+=x;Y+=y
     try:
      if F[Y][X] in '+-|':return False
     except:
      return False
 return True
F=open(input()).read().split('\n')
while 1:
 _=[F[0]]+['\n'.join([L[0]+''.join([R.choice(' \\/')for i in range(len(F[0])-2)])+L[-1] for L in F[1:-1]])]+[F[-1]]
 if V(_):
  for l in _: print l
  break

나는 솔루션에 만족하지 않기 때문에 이것을 최대로 골프하지 않았다. 사이드 라인에서 찾은 각 문자 V의 필드 F를 걸어 주어진 솔루션의 유효성을 검사합니다 C. 솔루션은 무작위로 생성됩니다. 추악하고 entry1에서는 작동하지만 다른 항목에는 많은 시간이 걸립니다. 무작위로 해결책을 시도하기 때문에 주어진 문제에 대한 실제 해결책이라고 생각하지 않습니다. 그러나 다른 사람들에게 도움이 될 수 있습니다.

운영: echo "entry1.txt" | python script.py


1
새로운 스코어링 시스템에서는 이것이 유효한 솔루션이지만 제수 보너스를 얻지 못합니다 (2 개 이상의 미러로 문제를 해결할 수없는 경우). 잘못된 구성을 미리 잘라내어 이것을 최적화 할 수 있다고 생각합니다 (예 : 가장자리에 문자가있는 각 열 또는 행에는 적어도 하나의 미러가 있어야합니다-일치하는 문자가 서로 반대되지 않는 한).
Logic Knight
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.