别。甚至。眨


50

在此处输入图片说明

您的生活可能取决于此。不要眨眼 甚至不眨眼。眨眼,你就死定了。他们很快。比您想象的要快。不要转过头,不要移开视线,也不要眨眼!祝好运。

哭泣天使是一个外星人种族,在被另一个生物(甚至另一个天使)观察时无法移动。他们通过及时送回受害者来养活自己。您(医生)被困在一个房间里,您需要去TARDIS。


任务

编写一个程序,该程序将给出一个矩形房间的ASCII表示形式,并输出一条可确保您安全的路径。如果有任何天使可以在前进过程中的任何时候发起攻击那么这条道路并不安全。如果一个天使可以看见您而又未被您或另一个天使看见,则可以发起攻击。

输入项

输入分为两个部分。首先,您要面对的方向(NSEW)。然后在随后的几行中,显示房间,显示开始/结束位置,以及所有天使的位置/朝向。

下面的示例显示有一个天使面向西,而您开始面向南。

S
..........
....D.....
..........
..........
..........
..........
..........
..........
.........W
..........
...T......
  • . - 空的空间
  • D -医生(开始位置)
  • T -TARDIS(最终位置)
  • N,S,E,W -面向指定方向的天使(北,南,东,西)

视线

您可以看到与您面对的方向成45度角的任何空间。如果沿直接的水平,垂直或45度对角线存在另一个实体,则视线将被遮挡。任何其他对角线都不会遮挡视图。天使的视线以相同的方式起作用。例如,在下面-,假设您朝南,则表示您的视野。

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

输出量

输出是一个字符串,表示您要退出的路径。如果有多个安全路径,请选择任何一个。如果没有安全的路径,则输出0。如果地图格式不正确,请采取任何措施,包括崩溃。如果房间不是矩形,没有出口等,请考虑它是否畸形。如果没有天使,它就不会畸形,这很容易。

对于每一步,您可以执行以下两项操作之一:沿NSEW方向移动,或转向NSEW方向(不更改位置)。要移动,只需输出该方向的字母即可。要转向一个方向,请在输出F后加上相应的字母。例如,以下输出:

SSFESSSSSSSW

是输入部分中给出的样本的安全路径。您向南移动两次,面向东方以保持天使的视线,然后再向南移动七次,向西移动一次进入TARDIS。

测试用例

1)您可以绕着朝东的天使到达TARDIS。除非您直接在它们之间跨步,否则它们会彼此锁定在适当的位置,因此无论您面对哪种方式都无所谓。

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

2)你输了。无法克服它们。他们可以看到对方,直到您在它们之间移动。到那时,您不能同时面对它们,您已经完成。也可以闭上眼睛,克服它。

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

获奖

适用标准高尔夫球规则和漏洞,最少获胜。我将尝试尽快获得更多测试用例,但在此期间可以随时提出自己的建议。

图片和引自Who Doctor。


我们可以使用库来查找图形的路径吗?
Sparr

@Sparr是的,但是加载/包含库所需的任何内容都应添加到字节数中。
Geobits

2
显然要使用涡旋操纵器!
TheDoctor 2014年

4
@TheDoctor Jack随身带上他,您可以看到他不在任何地图上(J)。
Geobits 2014年

1
@Timmy 可以使用任何标准定义
Geobits 2014年

Answers:


6

蟒蛇- 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"

必须提供这样的输入:

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

从本质上讲,此方法适用于查找Doctor可以安全到达的所有状态(位置和方向),存储他如何到达那里以及在成功的情况下进行打印。位置和方向是用复数实现的。

我可能可以使用Sage的复数算法来保护一些字符,但这会花费很长时间。

我最初以为我可以在到达塔迪斯之后将Doctor转向一个特定的方向来保存六个字符,但是我意识到这可能会导致错误的解决方案。我也首先误读了规则。

这是一个大多数版本的版本:

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"

测试用例

测试用例1:

SSSFSWWWSSSSFWEFSEFWE

测试案例2:

0

VisualMelon的测试用例:

SSFWSSSSSFSWWSSWWWFWEEEEFSEFWEFSE

1
我尚未测试您的代码,但看来您已经将测试用例1的输出粘贴了两次!另外,如果您将程序提供给我建议的测试用例,我也很想看看您的程序会产生什么。
VisualMelon 2014年

@VisualMelon:感谢您的发现,我集成了测试用例。
Wrzlprmft

10

C#1771 2034 1962 1887 1347字节

在1个循环中重新编写阻塞的LOS检查,使其更加整洁,并缩短了约450字节

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

这是一个完整的程序,期望输入以EOF终止并传递给STDIN。(希望)打印到TARDIS的最短路径;如果不存在,则显示“ 0”。它使用伪劣的“广度优先搜索”来跟踪所有可能的路线,然后从TARDIS回溯到“医生”以组装输出。

格式化代码:

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

输出例如输入

SFESWSSSSSSS

测试用例1的输出)

WSWSWSSSESESE

测试案例2的输出)

0

我根据要求提供了一个新的测试用例:

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

我的程序输出

SESESESESFNSSSSWW

WozzeC的测试案例1:

EEEEFWSSSFNWWN

WozzeC的测试案例2:

FSEEEESFWSSSSWFNWWWNFENNEES

我完全错过了使用X = System.Console的可能性。谢谢您:)
WozzeC 2014年

@WozzeC你可能想看看代码,高尔夫技巧在C#
VisualMelon

我相信医生会在您的测试用例启动时受到攻击:S
WozzeC 2014年

@WozzeC东南的西方天使可以看到西北的东方天使,因此医生可以逃脱,但是在这一点上,我的解决方案似乎没有注意到医生在启动时是否受到攻击。为什么这段代码很难测试!
VisualMelon 2014年

1
抱歉,没关系。我错过了微小的细节,如果另一个天使在看着他们,他们将无法动弹。
WozzeC 2014年

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

对。所以我决定试一试,男孩花了一段时间。它主要使用逻辑运算符构建。

  • 北= 1 = N
  • 南= 2 = S
  • 东= 4 = E
  • 西= 8 = W
  • 医生= 6 = D
  • TARDIS = 5 = T
  • 15 =。<-所有可用空间

为了避免检查是否为Null等。我决定使用[MAX_SIZE * 3] * [MAX_SIZE] * 3字段,并将游戏板放置在中央附近。

循环检查从内到外一直进行到50(MAX_SIZE)。所以像这样:

22222
21112
21D12
21112
22222

当找到EWS或N时,我会对它们进行相同的检查。如果发现有人在看天使(不是医生),他们将免费退还15。如果不注意他们,医生将以哪种方式返回以确保安全。即N将向南返回2。除非是NW或NE,否则它将分别返回6(2 + 4)和10(2 + 8)。

如果两个天使在看医生,则返回的值将为“与”,因此在测试示例2中,关键位置4和8将变为0。这意味着该位置不好,应该避免。

扩展代码:

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

检测结果

1范例:FNSSSWNNNWSSSWSSSSSENSES

2示例:无路可走

VisualMelon示例:FNSSSSSSSWNNNNNNNWSSSSSSSSSEEEE

我的测试案例1:FSSENEEEFWSSFNSWWN

我的测试案例2:FSEEEESFWSSSSFNWWWWNFENNFSEES

可以看出,我的医生喜欢像冲洗一样四处张望,向天使们展示四处走动的乐趣。我可以使软件找到最短的路径,但是它需要更长的时间,并且需要更多的代码。

你们的测试用例

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

另一个:

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

1
高尔夫球代码在一个位置缺少一个空间来停止编译,但是通过此修复,我使您的字节数仅为1395!将它降低到很低的水平,这是件很不错的工作,它是供您使用的完全公平的游戏using S=System.Console;,或者您可以完全删除代码中的S并通过节省6个字节using System。现在,我将不得不尝试减少一些幼稚的方法...;)
VisualMelon 2014年

1
哦,错过的空间,我应该照顾好。当然,S = ...当我了解到这一点后,就感到有些困惑。:)
WozzeC 2014年

不错的工作,让字节计数减少;)
VisualMelon 2014年

我发现了一些从未使用过的代码。加上一些其他不必要的东西。
WozzeC 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.