Não. Até. Piscar


50

insira a descrição da imagem aqui

Sua vida pode depender disso. Não pisque. Nem pisque. Pisque e você está morto. Eles são rápidos. Mais rápido do que você pode acreditar. Não vire as costas, não desvie o olhar e não pisque! Boa sorte.

Anjos chorando são uma raça alienígena que não pode se mover enquanto é observada por outro ser (até outro anjo). Eles se alimentam enviando suas vítimas de volta no tempo. Você ( o médico ) está preso em uma sala com alguns e precisa chegar ao seu TARDIS.


Tarefa

Escreva um programa que, dada uma representação ASCII de uma sala retangular, produza um caminho que o levará à segurança. Se algum anjo puder atacar - a qualquer momento durante o seu progresso - esse caminho não será seguro. Um anjo pode atacar se conseguir vê-lo sem ser visto por você ou por outro anjo.

Entrada

Entrada é duas partes. Primeiro, a direção que você está seguindo (NSEW). Em seguida, nas linhas seguintes, uma representação da sala, mostrando os locais de início / fim e a localização / face de todos os Anjos.

A amostra abaixo mostra que existe um anjo voltado para o oeste e você começa para o sul.

S
..........
....D.....
..........
..........
..........
..........
..........
..........
.........W
..........
...T......
  • . - Espaço vazio
  • D - O médico (posição inicial)
  • T - O TARDIS (posição final)
  • N,S,E,W - Um anjo, de frente para a direção especificada (norte, sul, leste, oeste)

Linha de visão

Você pode ver qualquer espaço a 45 graus da direção em que está voltado. A linha de visão é obstruída se houver outra entidade ao longo de uma diagonal direta horizontal, vertical ou 45 graus. Qualquer outra diagonal não obstrui a visualização. A linha de visão dos anjos funciona da mesma maneira. Por exemplo, a seguir, -representa seu campo de visão, supondo que você esteja voltado para o sul.

........
...D....
..---...
.-----..
-------.
---N----
---.--N-
---.----

Resultado

A saída é uma sequência que representa o caminho que você seguirá para sair. Se houver vários caminhos seguros, escolha qualquer um. Se nenhum caminho estiver seguro, faça a saída 0. Se o mapa estiver malformado, faça o que quiser, incluindo falhas. Considere-o malformado se a sala não for retangular, não houver saída etc. Se não houver Anjos, não será mal formado, simplesmente fácil.

Para cada etapa, você pode fazer uma de duas coisas: mover-se em uma direção NSEW ou girar para uma direção NSEW (sem alterar as posições). Para mover, basta imprimir a letra nessa direção. Para virar para enfrentar uma direção, faça a saída Fseguida pela letra apropriada. Por exemplo, a seguinte saída:

SSFESSSSSSSW

é um caminho seguro para a amostra fornecida na seção de entrada. Você se move para o sul duas vezes, enfrenta o leste para manter o anjo à vista, depois se move para o sul mais sete vezes e para o oeste uma vez para entrar na TARDIS.

Casos de teste

1) Você pode dar a volta no anjo voltado para o leste para chegar ao TARDIS. A menos que você pise diretamente entre eles, eles travam um ao outro no lugar, então não importa para que lado você esteja diante.

W
...D....
........
........
........
.E.....W
........
........
...T....

2) Você perde. Não há como passar por eles. Eles podem se ver até você se colocar entre eles. Nesse ponto, você não pode enfrentar os dois e pronto. É melhor fechar os olhos e acabar logo com isso.

S
...D....
........
........
........
E......W
........
........
...T....

Ganhando

Aplicam-se regras e brechas de golfe padrão , menos bytes ganhos. Em breve, tentarei obter mais casos de teste, mas fique à vontade para sugerir o seu.

Imagem e citações do Doctor Who.


podemos usar uma biblioteca para encontrar um caminho através de um gráfico?
Sparr

@Sparr Sim, mas qualquer coisa necessária para carregar / incluir a biblioteca deve ser adicionada à contagem de bytes.
Geobits 31/07

2
Obviamente, use um manipulador de vórtice!
TheDoctor

4
@ TheDoctor Jack levou a dele com ele, e você pode ver que ele não está em nenhum dos mapas ( J).
Geobits 6/08/08

1
@ Timmy Qualquer uma das definições padrão pode ser usada.
Geobits

Respostas:


6

Python - 559 565 644 633

M=input()
I=1j
Q={"S":I,"N":-I,"E":1,"W":-1}
A=[]
e=enumerate
for y,l in e(M[2:].split()):
 for x,c in e(l):
    P=x+y*1j
    if c=="D":D=(P,Q[M[0]])
    elif c=="T":T=P
    elif c!=".":A+=[(P,Q[c])]
def s(D,h,r=[]):
 def L(X,p,d):
    S=[p+d*(i+j*I)for i in range(x+y)for j in range(-i+1,i)if j]
    for f in[1,1+I,1-I]:
     i=0
     while i<x+y>1>(S[-1]in[a[0]for a in[D]+A]+[T])*i:i+=1;S+=[p+i*f*d]
    return X[0]in S
 if y>=D[0].imag>=(D[0]in[a[0]for a in A])<all(any(L(a,*b)for b in[D]+A)for a in A if L(D,*a))>(D in r)<=D[0].real<=x:
    r+=[D]
    if D[0]==T:print h;exit()
    for n in"SWEN":s((D[0]+Q[n],D[1]),h+n,r);s((D[0],Q[n]),h+"F"+n,r)
s(D,"")
print"0"

A entrada deve ser fornecida assim:

"W\n...D....\n........\n........\n........\nE......W\n........\n........\n...T....\n"

Essencialmente, é essa abordagem aplicada para encontrar todos os estados (posição e direção) que o médico pode alcançar com segurança, armazenando como chegou lá e imprimindo o caminho em caso de sucesso. Posições e direções são realizadas com números complexos.

Provavelmente eu poderia guardar alguns caracteres usando a aritmética complexa de números de Sage, mas isso seria extremamente longo.

Primeiro, pensei que poderia salvar seis caracteres, fazendo com que o médico se transformasse em uma direção específica depois de chegar ao Tardis, mas percebi que isso poderia resultar em soluções erradas. Também primeiro li mal as regras.

Aqui está uma versão praticamente não destruída:

Map = input()

I = 1j
string_to_dir = {"S":I,"N":-I,"E":1,"W":-1}

Angels = []
Pos = 0
direction = string_to_dir[Map[0]]
for y,line in enumerate(Map[2:].split()):
    for x,char in enumerate(line):
        Pos = x+y*1j
        if char == "D":
            Doctor = (Pos, direction)
        elif char == "T":
            Tardis = (Pos, direction)
        elif char != ".":
            Angels += [(Pos,string_to_dir[char])]

reachables = []

def display(LoS, Doctor):
    string = ""
    for y,line in enumerate(Map[2:].split()):
        for x,char in enumerate(line):
            if x+y*1j == Doctor[0]:
                string += "D"
            elif x+y*1j in LoS:
                if char in ".D":
                    string += "*"
                else:
                    string += "X"
            elif char != "D":
                string += char
            else:
                string += "."

        string += "\n"
    print string

def LoS(angel,Doctor):
    p,d = angel
    Sight = []
    for i in range(x+y):
        for j in set(range(-i+1,i))-{0}:
            Sight += [p+d*i+d*j*I]
    for line in [d, (1+I)*d, (1-I)*d]:
        for i in range(1,x+y):
            Pos = p + i*line
            Sight += [Pos]
            if Pos in [angel[0] for angel in Angels+[Doctor, Tardis]]:
                break
    return Sight

def search(Doctor, history):
    global reachables

    Sight = sum([LoS(angel, Doctor) for angel in [Doctor]+Angels],[])

    if (
                all(angel[0] in Sight for angel in Angels if Doctor[0] in LoS(angel, Doctor))
            and not (Doctor in reachables)
            and (0<=Doctor[0].imag<=y)
            and (0<=Doctor[0].real<=x)
            and (Doctor[0] not in [angel[0] for angel in Angels])
        ):

        reachables += [Doctor]

        if Doctor[0] == Tardis[0]:
            print history
            exit()
        for new_direction in "SWEN":
            search((Doctor[0]+string_to_dir[new_direction], Doctor[1]), history + new_direction)
            search((Doctor[0], string_to_dir[new_direction]), history + "F" + new_direction)

search(Doctor, "")
print "0"

Casos de teste

Caso de teste 1:

SSSFSWWWSSSSFWEFSEFWE

Caso de teste 2:

0

Caso de teste do VisualMelon:

SSFWSSSSSFSWWSSWWWFWEEEEFSEFWEFSE

1
Não testei seu código, mas parece que você colou a saída do caso de teste 1 duas vezes! Também ficaria interessado em ver o que o seu programa produz se você o alimentar no meu caso de teste proposto.
VisualMelon

@VisualMelon: Obrigado por detectar e integrei o caso de teste.
precisa saber é o seguinte

10

C # 1771 2034 1962 1887 1347 bytes

Reescreveu a verificação de bloqueio do LOS em um loop, tornando-o muito mais organizado e cerca de 450 bytes mais curto

using C=System.Console;using T=System.Math;struct P{int x,y,d;static void Main(){int v=C.ReadLine()[0],w,h,i,o=0,x=0,y=0,O,E,F,e=46;var R=C.In.ReadToEnd().Replace("\r","");var M=new int[w=R.IndexOf("\n"),h=(R.Length+1)/(w+1)];for(;o<h;o++)for(i=0;i<w;i++)if((M[i,o]=R[o+o*w+i])==68)M[x=i,y=o]=e;System.Func<int,int,int,bool>S=null;S=(X,Y,D)=>{var Z="SSSE_WNNNE_W___E_W";int I=0,H=0,L=0,J=Y,K=M[X,Y],B;M[X,Y]=D>0?D:K;for(H=0;H<9;H++)for(I=X,J=Y;H!=4&(I+=H%3-1)<w&I>=0&(J+=H/3-1)<h&&J>=0;){if(((B=M[I,J])==Z[H]|B==Z[H+9])&(D<1||!S(I,J,0)))goto W;if(B!=e)break;}for(B=I=-1;++I<w;B=1)for(J=0;J<h;J++)if(I!=X&J!=Y&(((B=M[I,J])==87&I>X&(H=T.Abs(J-Y))<I-X)|(B==69&I<X&H<X-I)|(B==78&J>Y&(L=T.Abs(I-X))<J-Y)|(B==83&J<Y&L<Y-J))&(D<1||!S(I,J,0)))goto W;W:M[X,Y]=K;return B>1;};P a,p=new P{x=x,y=y,d=v};var A=new System.Collections.Generic.List<P>();System.Action q=()=>{if(((E=M[p.x,p.y])==e|E==84)&!A.Contains(p)&!S(p.x,p.y,p.d))A.Add(p);};q();for(o=0;(O=A.Count)!=o;o=O)for(i=O;i-->o;){p=A[i];if((E=M[p.x,p.y])==84)for(R="";;p=a){i=0;n:a=A[i++];O=T.Abs(p.y-a.y)+T.Abs(a.x-p.x);if(O==1&p.d==a.d)R=(a.y-p.y==1?"N":p.y-a.y==1?"S":a.x-p.x==1?"W":"E")+R;else if(O<1)R="F"+(char)p.d+R;else goto n;if(i<2)goto Z;}if(E==e){if(p.x-->0)q();p.x+=2;if(p.x<w)q();p.x--;if(p.y-->0)q();p.y+=2;if(p.y<h)q();p.y--;for(F=0;F<4;q())p.d="NESW"[F++];}}R="0";Z:C.WriteLine(R);}}

Este é um programa completo que espera que a entrada termine com um EOF e seja passada para STDIN. (Espero) imprime o caminho mais curto para o TARDIS, ou "0" se não houver caminho. Ele usa uma pesquisa de largura de primeira qualidade para seguir todas as rotas possíveis, depois recua do TARDIS ao The Doctor para montar a saída.

Código formatado:

using C=System.Console;
using T=System.Math;

struct P
{
    int x,y,d;

    static void Main()
    {
        int v=C.ReadLine()[0],w,h,i,o=0,x=0,y=0,O,E,F,e=46;
        var R=C.In.ReadToEnd().Replace("\r","");
        var M=new int[w=R.IndexOf("\n"),h=(R.Length+1)/(w+1)];

        for(;o<h;o++)
            for(i=0;i<w;i++)
                if((M[i,o]=R[o+o*w+i])==68)
                    M[x=i,y=o]=e;

        System.Func<int,int,int,bool>S=null;
        S=(X,Y,D)=>
        {
            var Z="SSSE_WNNNE_W___E_W";

            int I=0,H=0,L=0,J=Y,K=M[X,Y],B;
            M[X,Y]=D>0?D:K;

            for(H=0;H<9;H++)
                for(I=X,J=Y;H!=4&(I+=H%3-1)<w&I>=0&(J+=H/3-1)<h&&J>=0;)
                {
                    if(((B=M[I,J])==Z[H]|B==Z[H+9])&(D<1||!S(I,J,0)))
                        goto W;
                    if(B!=e)
                        break;
                }

            for(B=I=-1;++I<w;B=1)
                for(J=0;J<h;J++)
                    if(I!=X&J!=Y&(((B=M[I,J])==87&I>X&(H=T.Abs(J-Y))<I-X)|(B==69&I<X&H<X-I)|(B==78&J>Y&(L=T.Abs(I-X))<J-Y)|(B==83&J<Y&L<Y-J))&(D<1||!S(I,J,0)))
                        goto W;
        W:
            M[X,Y]=K;
            return B>1;
        };

        P a,p=new P{x=x,y=y,d=v};
        var A=new System.Collections.Generic.List<P>();
        System.Action q=()=>{if(((E=M[p.x,p.y])==e|E==84)&!A.Contains(p)&!S(p.x,p.y,p.d))A.Add(p);};
        q();

        for(o=0;(O=A.Count)!=o;o=O)
            for(i=O;i-->o;)
            {
                p=A[i];
                if((E=M[p.x,p.y])==84)
                    for(R="";;p=a)
                    {
                        i=0;
                    n:
                        a=A[i++];

                        O=T.Abs(p.y-a.y)+T.Abs(a.x-p.x);
                        if(O==1&p.d==a.d)
                            R=(a.y-p.y==1?"N":p.y-a.y==1?"S":a.x-p.x==1?"W":"E")+R;
                        else if(O<1)
                            R="F"+(char)p.d+R;
                        else goto n;

                        if(i<2)
                            goto Z;
                    }
                if(E==e)
                {
                    if(p.x-->0)q();
                    p.x+=2;if(p.x<w)q();p.x--;
                    if(p.y-->0)q();
                    p.y+=2;if(p.y<h)q();p.y--;

                    for(F=0;F<4;q())
                        p.d="NESW"[F++];
                }
            }
        R="0";
    Z:
        C.WriteLine(R);
    }
}

Saída, por exemplo, entrada

SFESWSSSSSSS

Saída para o caso de teste 1)

WSWSWSSSESESE

Saída para o caso de teste 2)

0

Apresento, conforme solicitado, um novo caso de teste:

S
..E..DS....
...........
...........
...........
...........
...........
...........
...........
....SSSSS.W
.......T...

Meu programa gera

SESESESESFNSSSSWW

Caso de teste 1 do WozzeC:

EEEEFWSSSFNWWN

Caso de teste 2 do WozzeC:

FSEEEESFWSSSSWFNWWWNFENNEES

Perdi totalmente a possibilidade de usar X = System.Console. Obrigado por isso :)
WozzeC

@WozzeC que você pode querer verificar para fora Dicas para code-golfe em C #
VisualMelon

Eu acredito que o médico é atacado na inicialização com o seu caso de teste: S
WozzeC

@WozzeC O anjo do oeste no sudeste pode ver o anjo do leste no noroeste, para que o Doctor possa escapar, mas nesse ponto, parece que minha solução não percebe se o médico é atacado na inicialização. Por que esse código é tão difícil de testar!
VisualMelon

1
Desculpe, não importa. Perdi os pequenos detalhes de que eles não podem se mover se outro anjo estiver assistindo.
WozzeC

2

C # 1454, 1396, 1373, 1303 1279

class P{static int x,d,y=x=d=55,o=170,X=0,Y=0,u,k=3;static string[,]t=new string[o,o];static int[,]m=new int[o,o];static string e=" NS ETD W      .",q="0";static void Main(string[]s){m[0,1]=m[1,8]=-1;m[0,2]=m[1,4]=1;u=e.IndexOf(s[0][0]);for(;k<s[0].Length;k++){var c=s[0][k];if(c=='D'){X=x;Y=y;}if(c=='\\'){y++;x=d;k++;}else m[y,x++]=e.IndexOf(c);}k=A(X,Y,1);if((k&u)!=0){W(X,Y,k,"");}System.Console.Write(q);}static void W(int x,int y,int h,string s){t[y,x]=s;for(int i=1;i<9;i*=2){int l=y+m[0,i],g=x+m[1,i];if(m[l,g]==5)q=t[l,g]=s+e[i];else if(m[l,g]==15){m[l,g]=6;m[y,x]=15;int n=A(g,l,1),U;for(int j=1;j<9;j*=2){var z=t[l,g]??s;if((n&h&j)!=0&z.Length>=s.Length){U=u;u=j;W(g,l,n,s+((u!=j)?"F"+e[j]:"")+e[i]);u=U;}}m[y,x]=6;m[l,g]=0;}}}static int A(int x,int y,int L){int r=15,a,b,c,f=0,g,h,R,B;for(a=1;a<d-5;a++){g=1;for(b=y-a;b<=y+a;b++)for(c=x-a;c<=x+a;c++){B=m[b,c];R=0;bool W=(c+a-x)%a==0,V=(b+a-y)%a==0,z=W&V;if(B>0&B<9&B!=6&B!=5&g!=16&!((W|V)&(f&g)!=0)){h=R;if(b==y-a){R=1;if(c==x-a){h=4;R=9;}else if(c==x+a){h=8;R=5;}B&=h&2;}else if(b==y+a){R=2;if(c==x-a){h=4;R=10;}else if(c==x+a){h=8;R=6;}B&=h&1;}else if(c==x-a){B&=4;R=8;}else if(c==x+a){B&=8;R=4;}else B=0;if(B!=0){if(L==1&&A(c,b,0)==15)r&=R;if(L==0)return R;}}if(z){if(B<9&B>0&!(c==x&y==b))f|=g;g*=2;}}}return r;}}

Direito. Então eu decidi tentar e rapaz demorou um pouco. Ele é construído principalmente usando operadores lógicos.

  • Norte = 1 = N
  • Sul = 2 = S
  • Leste = 4 = E
  • Oeste = 8 = W
  • Médico = 6 = D
  • TARDIS = 5 = T
  • 15 =. <-Todos os espaços livres

Para evitar ter que procurar Nulo etc., decidi usar um campo de [MAX_SIZE * 3] * [MAX_SIZE] * 3 e colocar o tabuleiro de jogo próximo ao centro.

As verificações de loop são feitas por dentro e por fora até 50 (MAX_SIZE). Então, algo como isto:

22222
21112
21D12
21112
22222

Quando um EWS ou N é encontrado, faço a mesma verificação por parte deles. Se alguma coisa é encontrada olhando para os anjos (não o médico), eles retornam 15 como passagem livre. Se não forem observados, retornam de que maneira o médico deve enfrentar para estar seguro. isto é, N retornaria 2 para o sul. A menos que seja NW ou NE, nesse caso, retornaria 6 (2 + 4) e 10 (2 + 8), respectivamente.

Se dois anjos estiverem observando o médico, os valores retornados serão "ANDed", portanto, no exemplo de teste 2, as posições 4 e 8 se transformarão em 0. Isso significa que a posição é ruim e deve ser evitada.

Código expandido:

class P
{
    static int x,d,y=x=d=55,o=170,X=0,Y=0,u,k=3;
    static string[,] t = new string[o, o];
    static int[,] m = new int[o, o];
    static string e = " NS ETD W      .", q="0";
    static void Main(string[]s)
    {   
        m[0, 1]=m[1, 8]=-1;
        m[0, 2]=m[1, 4]=1;
        u=e.IndexOf(s[0][0]);
        for (;k<s[0].Length;k++)
        {
            var c = s[0][k];
            if (c == 'D') { X = x; Y = y; }
            if (c == '\\') { y++; x = d; k++; }
            else m[y, x++] = e.IndexOf(c);
        }
        k=A(X,Y,1);
        if ((k&u)!=0)
        {
            W(X, Y, k,"");
        }
        System.Console.Write(q);
    }
    static void W(int x,int y,int h,string s){
        t[y, x] = s;
        for (int i = 1; i < 9; i*=2)
        {
            int l = y+m[0, i], g = x+m[1, i];
            if (m[l, g] == 5)
                q = t[l, g] = s + e[i];
            else if (m[l, g] == 15)
            {
                m[l, g] = 6;
                m[y, x] = 15;
                int n = A(g, l,1),U;
                for (int j = 1; j < 9; j *= 2)
                {
                    var z = t[l, g]??s;
                    if ((n & h & j) != 0 & z.Length>=s.Length)
                    {
                        U = u;
                        u = j;
                        W(g, l, n,s+((u != j) ? "F" + e[j] : "") + e[i]);
                        u = U;
                    }
                }
                m[y, x] = 6;
                m[l, g] = 0;
            }
        }
    }
    static int A(int x, int y,int L)
    {
        int r = 15,a,b,c,f=0,g,h,R,B;
        for (a = 1; a < d - 5; a++)
        {
            g = 1;
            for (b = y - a; b <= y + a; b++)
                for (c = x - a; c <= x + a; c++)
                {
                    B=m[b, c];
                    R=0;
                    bool W=(c+a-x)%a==0,V=(b+a-y)%a==0,z=W&V; 
                    if (B>0&B<9&B!=6&B!=5&g!=16&!((W|V)&(f&g)!=0))
                    {
                        h=R;
                        if (b==y-a)
                        {
                            R=1;
                            if(c==x-a){h=4;R=9;}
                            else if(c==x+a){h=8;R=5;}
                            B&=h&2;
                        }
                        else if (b==y+a)
                        {
                            R=2;
                            if(c==x-a){h=4;R=10;}
                            else if (c==x+a){h=8;R=6;}
                            B&=h&1;
                        }
                        else if(c==x-a){B&=4;R=8;}
                        else if(c==x+a){B&=8;R=4;}
                        else B=0;
                        if (B!=0)
                        {
                            if(L==1&&A(c,b,0)==15)r&=R;
                            if (L==0)return R;
                        }
                    }
                    if (z)
                    {
                        if (B < 9 & B > 0 & !(c==x&y==b))
                           f |= g;
                        g *= 2;
                    }
                }
        }
        return r;
    }
}

Resultado dos testes

1 Exemplo: FNSSSWNNNWSSSWSSSSENNESES

2 Exemplo: Sem saída

Exemplo de VisualMelon: FNSSSSSSSWNNNNNNNWSSSSSSSSSEEEE

Meu caso de teste1: FSSENEEEFWSSFNSWWN

Meu caso de teste2: FSEEEESFWSSSSFNWWWWNFENNFSEES

Como pode ser visto, meu médico adora andar como um idiota para mostrar aos anjos como é divertido se movimentar. Posso fazer com que o software encontre o caminho mais curto, mas leva mais tempo e precisa de mais código.

Casos de teste para vocês

S
D....
..NE.
.WTS.
.S...

Outro:

E
D....
WNNN.
...E.
.WTE.
.SSE.
.....

1
O código golfado está faltando um espaço em um local que o impede de compilar, mas com essa correção, faço você contar apenas 1395! Bom trabalho, tornando-o tão baixo, e é um jogo perfeitamente justo para você usar using S=System.Console;, ou você pode simplesmente remover completamente o S no seu código e economizar 6 bytes por using System. Agora eu vou ter que tentar e cortar minha abordagem ingênua para baixo um pouco mais ...;)
VisualMelon

1
Oh um espaço perdido, eu deveria cuidar disso. E é claro que o S = ... Me empolguei quando soube disso. :)
WozzeC

Bom trabalho recebendo o byte contagem regressiva;)
VisualMelon

Encontrei algum código que nunca foi usado. Além de algumas coisas desnecessárias adicionais.
WozzeC
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.