Trova una configurazione speculare per abbinare le destinazioni laser


13

PUNTEGGI AGGIORNATI : poiché questa sfida è più difficile di quanto mi aspettassi, ho modificato il punteggio. Un programma in grado di risolvere un singolo input mirror è una risposta valida. Programmi più sofisticati ottengono un bonus per il loro punteggio.

Ci sono stati diversi enigmi su PPCG per trovare un percorso laser in una scatola di specchi. In questo puzzle, devi creare una scatola di specchi per abbinare un numero di destinazioni laser.

Ti viene data una scatola e una specifica in cui i laser devono entrare e uscire. Il tuo programma deve posizionare esattamente N specchi a doppia faccia nella scatola per soddisfare le specifiche. Gli specchi devono essere inclinati di 45 gradi ma possono essere inclinati in avanti o all'indietro.

Ingresso

Il programma dovrebbe accettare una griglia di riquadri tramite STDIN, argomento della riga di comando o file nei seguenti esempi di formato:

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

Le coppie di lettere ([a-zA-Z] possono essere utilizzate) indicano l'ingresso / uscita di un massimo di 52 laser. All'interno della scatola ci saranno N /specchi. Le dimensioni del riquadro saranno 3 <= W, H <= 200. Il riquadro è composto da +|-caratteri. Potrebbe esserci un numero qualsiasi di mirror nella casella incluso zero.

Produzione

L'output deve corrispondere all'input, ad eccezione dei /caratteri che possono essere spostati e / o modificati in \caratteri. Il programma dovrebbe inviare una stringa box mirror corretta a STDOUT o un file, trascinando la nuova riga facoltativa. Se nessun posizionamento dei mirror può soddisfare le specifiche di input, output Impossible\n. Esempi di possibili soluzioni:

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

Esempio di test

Ingresso:

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

Esempio di output:

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

Punteggio (AGGIORNATO)

Questo è code-golf con bonus. Dovresti nominare con la tua risposta quanti mirror il tuo programma può risolvere (N). Il tuo punteggio è la lunghezza del tuo programma in byte diviso per N. Ciò consente alle persone di entrare con un semplice programma, ma premia un numero maggiore di programmatori di ambizioni con un bonus.

Scappatoie standard non consentite.


3
Sembra un problema difficile, indipendentemente dal golf.
orlp

2
Suggerimento: la forza bruta non è un'opzione ; ti serviranno 3 età dell'universo a 10k opzioni al secondo per l'esempio più grande.
Sanchises,

@sanchise Penso che ci vorrà molto più tempo, dato che qualsiasi mirror può essere capovolto, quindi penso che tu abbia bisogno di un * 2^30componente anche lì
VisualMelon

Suggerimento extra: dovrai sfruttare le proprietà del puzzle per potare il tuo spazio di ricerca. È inoltre possibile utilizzare combinazioni di soluzioni parziali o arrampicata in salita da soluzioni parziali vicine a una soluzione completa. Ora è valido rispondere con soluzioni più semplici, quindi anche i programmi che risolvono uno o due puzzle specchio sono i benvenuti.
Logic Knight,

Risposte:


2

C # - 897 862 byte

Trovato un bug serio con esso che mette gli specchi in posti che non possono essere. Ora funziona, si spera! Ho anche fatto un po 'di golf leggero, non potevo lasciare il ciclo lì dentro ... vergognoso.

Programma completo, prende input da STDIN, output a STDOUT.

Questo è stato molto divertente, risolve bene il problema 7 per 5 (e quando rimuovi uno dei mirror, rendendolo impossibile), ci sono voluti circa 1 ora per risolvere il 30 per 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 per 5 Esempio:

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

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

Versione impossibile:

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

Impossible

Qualcosa di diverso (il programma non guarda il layout originale del mirror):

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

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

Soluzione 30 per 5:

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

Osserva a turno ciascuna sorgente laser e crea un percorso valido per essa (se possibile), quindi passa alla successiva. È una ricerca di profondità piuttosto semplice, che deve sapere quale sorgente laser (target) sta guardando, quanti specchi rimarrà per posizionarlo, la cella corrente è "a", la direzione in cui si muove e ogni cella è già visitato (in modo che non metta uno specchio da qualche parte è già stato). Gli ultimi 3 vengono utilizzati per assemblare il percorso per la destinazione corrente e al ripristino quando la destinazione cambia. Una volta collegati tutti i laser, va avanti e riempie tutti gli spazi vuoti che non devono essere lasciati vuoti (un'altra ragione per cui ha bisogno di sapere ovunque sia visitata).

Quando costruisce percorsi, preferisce andare "in avanti" rispetto all'inserimento di un mirror, e quando lo fa, favorisce un mirror "\" - questo è meglio visibile nell'esempio "qualcosa di diverso" sopra, dove salta la prima cella sotto il top-most 'a', quindi compila continuamente un "\" se riesce a trovare una soluzione con una, altrimenti un "/" (naturalmente, se saltare la prima cella risulta impossibile riuscire a trovare una soluzione, allora tornare indietro e provare invece a mettere uno specchio lì).

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

Bella soluzione. Secondo il nuovo sistema di punteggio ottieni almeno 917/7 = 131.
Logic Knight

2

Python, 671 654 byte

Non una soluzione, ma un tentativo, leggi sotto.

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

Non ho giocato a golf al massimo, dal momento che non sono soddisfatto della soluzione. Vconvalida una determinata soluzione camminando sul campo Fper ogni personaggio Cche trova a bordo campo. Le soluzioni sono generate a caso. È brutto, funziona per entry1, ma richiede molto tempo per le altre voci. Dal momento che cerca soluzioni casuali, non considero questa una soluzione effettiva per il problema dato; ma potrebbe aiutare gli altri.

Correre: echo "entry1.txt" | python script.py


1
Con il nuovo sistema di punteggio, questa è una soluzione valida ma non ottiene un bonus divisore (a meno che non sia in grado di risolvere problemi con 2 o più mirror). Penso che potresti ottimizzarlo eliminando le configurazioni non valide in precedenza (ad esempio: ogni colonna o riga con una lettera sul bordo deve avere almeno un mirror - a meno che le lettere corrispondenti non siano una di fronte all'altra).
Logic Knight,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.