ค้นหาการกำหนดค่ามิรเรอร์เพื่อจับคู่เลเซอร์กับปลายทาง


13

การให้คะแนนแบบอัปเดต : เนื่องจากความท้าทายนี้ยากกว่าที่ฉันคาดไว้ฉันจึงปรับการให้คะแนน โปรแกรมที่สามารถแก้ไขอินพุตมิรเรอร์เดียวคือคำตอบที่ถูกต้อง โปรแกรมที่ซับซ้อนมากขึ้นจะได้รับโบนัสคะแนน

มีปริศนามากมายใน PPCG เพื่อค้นหาเส้นทางเลเซอร์ในกล่องกระจก ในจิ๊กซอว์นี้คุณต้องสร้างกล่องมิเรอร์เพื่อจับคู่กับปลายทางเลเซอร์จำนวนหนึ่ง

คุณจะได้รับกล่องและข้อกำหนดที่เลเซอร์จะเข้าและออก โปรแกรมของคุณต้องวางกระจกสองด้าน N อย่างแน่นอนในกล่องเพื่อให้ตรงตามข้อกำหนด กระจกต้องทำมุม 45 องศา แต่สามารถเอียงไปข้างหน้าหรือเอียงกลับได้

อินพุต

โปรแกรมของคุณควรยอมรับกริดของกล่องผ่าน STDIN อาร์กิวเมนต์บรรทัดคำสั่งหรือไฟล์ในตัวอย่างรูปแบบต่อไปนี้:

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

คู่ตัวอักษร (อาจใช้ [a-zA-Z]) แสดงถึงอินพุต / เอาต์พุตสูงสุดเลเซอร์ 52 ภายในกล่องจะมี/กระจกN ขนาดของกล่องจะเท่ากับ 3 <= W, H <= 200 ตัวกล่องทำจาก+|-ตัวละคร อาจมีกระจกจำนวนเท่าใดก็ได้ในกล่องซึ่งรวมถึงศูนย์

เอาท์พุต

เอาต์พุตควรตรงกับอินพุตยกเว้น/อักขระอาจถูกย้ายและ / หรือเปลี่ยนเป็น\อักขระ โปรแกรมของคุณควรส่งสตริงมิเรอร์กล่องที่ถูกต้องไปยัง STDOUT หรือไฟล์ตามด้วยบรรทัดใหม่ที่เป็นตัวเลือก Impossible\nถ้าตำแหน่งของกระจกไม่สามารถตอบสนองข้อกำหนดการป้อนข้อมูลการส่งออก ตัวอย่างของการแก้ปัญหาที่เป็นไปได้:

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

ตัวอย่างการทดสอบ

การป้อนข้อมูล:

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

ตัวอย่างผลลัพธ์:

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

เกณฑ์การให้คะแนน (อัพเดท)

นี่คือรหัสกอล์ฟพร้อมโบนัส คุณควรเสนอชื่อพร้อมคำตอบของคุณว่าโปรแกรมของคุณสามารถแก้ไข (N) ได้กี่รายการ คะแนนของคุณคือความยาวของโปรแกรมของคุณในหน่วยไบต์โดยหารด้วย N สิ่งนี้จะช่วยให้ผู้คนสามารถเข้าร่วมด้วยโปรแกรมง่ายๆ

ช่องโหว่มาตรฐานไม่อนุญาต


3
ฟังดูเหมือนเป็นปัญหาหนักไม่ว่าจะเล่นกอล์ฟ
orlp

2
คำแนะนำ: กำลังดุร้ายไม่ได้เป็นตัวเลือก ; มันจะพาคุณเข้าสู่ยุคของจักรวาล 3 ครั้งที่ตัวเลือก 10k ต่อวินาทีสำหรับตัวอย่างที่ใหญ่กว่า
Sanchises

@sanchises ฉันคิดว่ามันจะใช้เวลานานมากเพราะกระจกเงาสามารถพลิกดังนั้นฉันคิดว่าคุณต้องมี* 2^30องค์ประกอบในที่นั่นเช่นกัน
VisualMelon

คำใบ้เพิ่มเติม: คุณจะต้องใช้ประโยชน์จากคุณสมบัติของตัวต่อเพื่อตัดพื้นที่การค้นหาของคุณ คุณอาจใช้การผสมผสานของการแก้ปัญหาบางส่วนหรือการปีนเขาจากการแก้ปัญหาบางส่วนที่ใกล้เคียงกับการแก้ปัญหาที่สมบูรณ์ ตอนนี้สามารถตอบได้ด้วยวิธีแก้ปัญหาที่ง่ายกว่าดังนั้นโปรแกรมที่แก้ปัญหาตัวต่อมิเรอร์หนึ่งหรือสองตัวก็ยินดีเช่นกัน
Logic Knight

คำตอบ:


2

C # - 897 862 ไบต์

พบข้อบกพร่องร้ายแรงด้วยการวางมิเรอร์ในสถานที่ที่ไม่สามารถทำได้ ตอนนี้มันใช้งานได้หวังว่า! นอกจากนี้ยังมีการเล่นกอล์ฟบางเบาไม่สามารถออกจากวงในขณะที่มี ... น่าอับอาย

โปรแกรมที่สมบูรณ์ใช้อินพุตจาก STDIN เอาต์พุตไปยัง STDOUT

มันสนุกมากมันแก้ปัญหาได้ดีด้วยปัญหา 7 คูณ 5 (และเมื่อคุณลบกระจกทำให้มันเป็นไปไม่ได้) ใช้เวลาประมาณ 1 ชั่วโมงเพื่อแก้ปัญหา 30 คูณ 5

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(",","|"));}}

7 จาก 5 ตัวอย่าง:

+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 จาก 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

Python, 671 654 ไบต์

ไม่ใช่วิธีแก้ปัญหา แต่เป็นความพยายามอ่านด้านล่าง

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.