アイスパズルジェネレーターとソルバーを構築する


13

単収縮プレイズポケモン、最も厄介な障害の一つ1缶の顔はあなたがいずれかの壁や岩にヒットするまで一方向にすべての方法をスライドさせて、ある場所から別の場所へ移動しなければならない氷のパズルは、あります。

あなたの仕事は、ランダムで難しい氷のパズルを生成するプログラムを構築することです。

あなたのプログラムは、3つの数字を受け入れるMNP、入力として(と10 <= M <= 3015 <= N <= 40そして、0 <= P < 65536):

12 18

出力されます:

  • 成るグリッドとMN.O、それぞれ氷と玉石を表します。
  • パズルの入力元を表す位置マーカー。この位置マーカーは、文字で構成されLRT、またはB、左、右、上、下を表すから入力されるその側(左または上から)の位置を示す数字が続きます。
  • パズルが終了する場所を表す同様の位置マーカー。
  • 最短の配列からなるパズルの解決策、LRU、およびDそれぞれ。

出力例:

..O...O...........
............O.....
..O...............
.......O..........
..................
...........O......
O..O...........O..
..........O.......
..O..........O....
........O.........
O....O.........O..
............O.....
R 4
B 5
LDLDRULD
(Note that this output is actually invalid because it is not actually long enough.)

入力MおよびのN場合、パズルの解決策には少なくともmin(M, N)ステップが必要で、少なくとも2 (M + N)合計スペースを移動する必要があります。(参考までに、上記のパズルは合計で12ステップ、69スペース移動します。)パズルジェネレーターは、シードごとに異なるソリューションパス(つまり、各ソリューションの異なるステップシーケンス)で異なるMby Nパズルを生成する必要がありますP

  • 別のソリューションパスの要件は、ここでのClaudiuのソリューションのように、ロックパスを体系的に生成しようとするソリューションを避けることです。プログラムが意図的に同じ動きのシーケンスでパズルを生成しようとしていない限り、ランダム性の癖により同一のソリューションのペアが2つまたは3つある場合でも問題ありません。

上記を実行する最短のコードが優先されます。


2
「壁や岩にぶつかるまで一方向にスライドさせて、ある場所から別の場所に移動しなければならない」という目的を理解できません。壁や岩にぶつかってもいいですか?最初からどこを目指していますか?岩にぶつかるとゲームは終了しますか?壁にぶつかるとどうなりますか?それは私だけですか、それとも方向性が不明確ですか?
DavidC 14年

3
ああ、ポケモンの金と銀の昔の思い出がここにあります。出口を見つけてHM07を取得し、Blackthorn Cityに行きます。
ビクタースタフサ14年

3
これは、Chip's Challengeの氷のレベルを思い出させます。
luserはドローグ

1
エンターとエグジットに>and <(または任意の文字)を使用しないのはなぜですか?パズルは読みやすくなります。
AL

1
実際にあなたのサンプル出力は無効です-最短経路があるLDLDRULDだけで8段階の長である
クラウディウ

回答:


5

Python、672 548文字、より興味深いパズル

厳密には規則に従っていますが、他のPythonプログラムはこれに勝っていますが、とにかくもっと面白いパズルを生成するものを書くことにしました。ここにあります:

R=range;import random as J;X=J.randint
x=(0,1,-1,0);y=x[2:]+x
g=lambda r,c:(0<=r<H)+(0<=c<W)>1and f[r][c]or x[(r,c)in(A,E)]
l=lambda r,c:g(r+y[d],c+x[d])<1and(r,c)or l(r+y[d],c+x[d])
H,W,P=input();J.seed(P)
while 1:
 A=(-1,X(0,W));E=(H,X(0,W));f=[[X(0,7)for _ in R(W)]for _ in R(H)]
 q=[(A,'')];n=z={}
 while q and n!=E:
    n,O=q.pop()
    for d in R(4):
     N=l(*n)
     if g(n[0]+y[d],n[1]+x[d])and N not in z:q[:0]=[(N,O+"URLD"[d])];z[N]=1
 if(n==E)*len(O)>min(H,W):print"\n".join(''.join('O.'[c>0]for c in T)for T in f),"\nT",A[1],"\nB",E[1],"\n",O;break

インデントレベルは、スペース、タブ、タブ+スペースです。

サンプル

$ echo [10,15,0] | python ice2.py
.....OO........
...............
...O....O.OO..O
...........O...
..O....O.......
.......O....O..
....O..........
.............O.
..............O
...............
T 1
B 10
DLURDRURULDRD

Pシードとして使用するため、それぞれPが同じパズルを生成し、それぞれが異なるP可能性が非常に高くなります。

$ echo [10,15,1] | python ice2.py
.OOO.O.........
...O......O.O.O
.......O.......
..O..........OO
.....O.........
.............O.
.O.............
.O............O
O....O.........
......O........
T 14
B 8
DLDRDLURULD

のサイズまではかなり速く動作M=25,N=40しますが、それまでは本当に遅くなります。理論上はM=30, N=40、十分な長さで実行させると動作するはずです。追跡するのは難しいので、ここでトレイルに手動で書きました-プログラムはパズルを出力するだけです。

$ echo [25,40,0] | python ice2.py
                   *
...................dO....urrrO..O..O....
....O.....O........dO....u..dO..........
..........O.....O..d....Ou.Odrrrrrrrrrrr
...........O.......d.O..Ou..O.....OOllld
.O....O.OO.........drrrrrrO....Olllud..O
O......O...O.O.....O............dO.ud...
O........OO..........O.........Od..ud..O
.........O......................d..ud...
....O.....O.O....O.....O........d..ud.O.
.....O..O...................O...d..udO..
.........O.........O..O.........d..ud...
.......O.O...O..O.OO....O...OOlldOOld...
........Olllllllllu....OO.OO..dOO...O...
.O.O....Od........u......O....d..O...O..
..O....O.d........u..O........d..O..O...
....O....d..O.....uO.....O....d.........
.........d........u...........d.........
.........d....O...u.O..O.....Od.O.......
........Od...O....u...........d.........
.O.....OuxrrrrO...u...OOOO..O.d.........
........udO..dO.O.u...........d.........
O..O.O..ud...d..urrO..........d.O...O...
........ud...d..u.O.O........Od..O...O..
..OO....ud..Od..u......OllllludO.....O..
..O....OldO..dOOlllllllld...Old...O..O..
             *
T 19
B 13
DRURDRDLDLULDLDLULDLURULDLURD

説明

プログラムはループし、ランダムな開始位置を上部に、ランダムな終了位置を下部に、ランダムグリッドを生成し、12.5%任意のスポットにボルダーを配置します。次に、幅優先探索でパズルを解決し、ソリューションが存在しmin(H,W)、それより大きい場合は、印刷して終了します。


4

Java-2632

私はClaudiuの答えの技術的な純粋さを賞賛しながら、少し難しいパズルを作ること手をかけることにしました;)

基本的な手順(非常に簡単):

Randomize entry location
Step forward
For min(m,n)-1 steps:
    Rotate left or right
    Slide until I hit something or go a random distance
    Place a rock in front of stopping location
If I can slide straight to any wall:
    Slide to exit
Else
    Create another step and try again

If at any step I get trapped, start over
If BFS finds shorter path, start over

また、スライドしているときに各スポットを「nogo」としてマークします。もし私が最後のスポット(または岩がそこに行くことを意味するものの直前)に行くなら、それは無効なステップです。

したがって、基本的には、多くのマップをランダムに生成し、有効な最初のマップを保持するという考え方です。私はこれをよりスマートに(バックトラッキングなど)する予定ですが、今はうまく機能しています。また、冗長なコードを削減する可能性もあります。

そのままでは、小さなマップ(15x10)がほぼ瞬時に生成され、中(30x20)のマップは数秒で、大きな(40x30)はシードに応じて20秒から20分の間のランダムな時間で生成されます。私のマシンでは、サイズに応じて毎秒30万から50万のマップをテストします。

サイドノート:単にステップと同じ数の岩しかないために、マップがそれほど難しくない場合があります。ステップで壁に連れて行かない限り、ほとんどの場合、実際の岩を打ちたい場合は1つのオプションしかありません。すべてのステップが描画された後、安全な場所に「ランダムな」岩を配置することで、後で修正します。nogoスポットは既にマークされているので、それは非常に簡単なはずです。今のところ、これらの例をお楽しみください。

さまざまなサイズ/シードを示す出力:

$ java I 30 20 6851              $ java I 15 10 1     $ java I 15 10 65513  

............................O.      .......O.......     ....O..........     
..............................      ...............     ...............     
..............................      .........O.....     .........O.....     
..........O......O............      .............O.     ..............O     
...............O...........O..      ...............     ...............     
..............................      .......O.......     .....O.O.......     
..............................      O..............     ...............     
........................O.....      ...............     ..........O....     
..............................      ...............     O..............     
...O.......................O..      ......O........     ...............     
O...............O.OO..........          
..............O..........O....          
...........O..................      T 14                R 6         
....O.........................      T 7                 T 14            
..............................      DLDLULURU           LULDLDRURU
..............................
..............................
.................O............
.O............................
..............................


B 28
R 9
ULURDLDLDRURDLDRURUR

最大サイズ40x30:

$ java I 40 30 2

........................................
........................................
........................................
........................................
................O.......................
..........O.............................
........................................
.......O................................
.....................O..........O.......
......................O.................
.................................O......
......................................O.
........................................
........................................
..............................O.........
...........O............................
........................................
.......................................O
.........O...................O..........
....................O...................
...............................O........
............O..O......................O.
......O...........O.....................
..................O....O................
..................................O.....
........................................
..............................O.........
.....................................O..
...........O............................
...................O....................

B 19
B 11
URURDLULULDRDRDLULDLDLULURDLD

ゴルフ済み:

import java.util.*;import java.awt.*;class I{int m,n,p,g,a[][],b[][];Random r;Point s,e,c;ArrayList<Integer>z;void Q(String q,int l){if(l>0)System.out.println(q);else System.out.print(q);}void G(String[]y){m=Integer.valueOf(y[0]);n=Integer.valueOf(y[1]);p=Integer.valueOf(y[2]);r=new Random(p);Q("",1);int o=0,i,j,u=0;char t,f[]={85,76,68,82};while(o<3){if(++u%20000==0)Q("\r#"+u,0);a=new int[m+2][n+2];b=new int[m+2][n+2];for(i=0;i<m+2;i++)for(j=0;j<n+2;j++)if(i==0||i==m+1||j==0||j==n+1)a[i][j]=2;s=new Point();int e=r.nextInt(m*2+n*2);if(e<m*2){s.x=e%m+1;s.y=e<m?0:n+1;}else{s.y=(e-m*2)%n+1;s.x=(e-m*2)<n?0:m+1;}if(s.x<1)g=3;else if(s.x>m)g=1;else if(s.y<1)g=2;else if(s.y>n)g=0;a[s.x][s.y]=0;c=new Point(s);z=new ArrayList<Integer>();z.add(g);for(i=0;i++<Math.min(m,n)-1;)if(N()<1&&N()<1)break;o=((z.size()>=Math.min(m,n)-1)?1:0)+F()+((V()==z.size())?1:0);}Q("\r",0);for(j=1;j<n+1;j++){for(i=1;i<m+1;i++)Q(String.valueOf(a[i][j]>0?'O':'.'),0);Q("",1);}Q("\n\n",0);if(s.x<1||s.x>m){t=s.x<1?'L':'R';u=s.y;}else{t=s.y<1?'T':'B';u=s.x;}Q(t+" "+u,1);if(e.x<1||e.x>m){t=e.x<1?'L':'R';u=e.y;}else{t=e.y<1?'T':'B';u=e.x;}Q(t+" "+u,1);for(i=0;i<z.size();)Q(String.valueOf(f[z.get(i++)]),0);Q("",1);}public static void main(String[]a){new I().G(a);}int F(){int c=0;while(C()<1&&c++<10)if(N()<1)return 0;return e==null?0:1;}int C(){int d=g<2?-1:1;if(g%2<1){int y=c.y;while(y>0&&y<n+1){y+=d;if(a[c.x][y]==1)return 0;}e=new Point(c.x,y);}else{int x=c.x;while(x>0&&x<m+1){x+=d;if(a[x][c.y]==1)return 0;}e=new Point(x,c.y);}a[e.x][e.y]=0;return 1;}int V(){if((s.x-e.x)+(s.y-e.y)<2)return 0;Queue<Point>q=new ArrayDeque<Point>();Queue<Integer>d=new ArrayDeque<Integer>();a[s.x][s.y]=-2;q.add(s);d.add(0);while(q.size()>0){Point t=q.poll();int h=d.poll(),i=0;if(t.equals(e))return h;for(;i<4;i++){Point n=S(a,t,i<2?0:1,i%2<1?-1:1,99,1);if(a[n.x][n.y]==-2)continue;a[n.x][n.y]=-2;q.add(n);d.add(h+1);}}return 0;}int N(){Point q;int d=g<2?-1:1,x,y;System.arraycopy(a,0,b,0,a.length);q=S(b,c,g,d,r.nextInt((g%2<1?n:m)/2)+2,0);if(q.x<1||q.y<1||q.x>m||q.y>n||q.equals(c)||b[q.x][q.y]!=0)return 0;x=q.x;y=q.y;if(g%2<1)y+=d;else x+=d;if(b[x][y]<0)return 0;b[q.x][q.y]=-1;b[x][y]=1;int f=r.nextInt(2)<1?-1:1;g=g%2<1?(f<0?1:3):(g=f<0?0:2);c=q;System.arraycopy(b,0,a,0,a.length);z.add(g);return 1;}Point S(int[][]u,Point f,int w,int d,int q,int s){int i=1,x=f.x,y=f.y;for(;i<=q;i++){if(w%2<1)y=f.y+i*d;else x=f.x+i*d;if(e!=null&&e.x==x&&e.y==y)return e;if(y<0||y>n+1||x<0||x>m+1)return f;if(s<1&&u[x][y]<1)u[x][y]=-1;if(u[x][y]>0){if(w%2<1)y-=d;else x-=d;return new Point(x,y);}}if(w%2<1)return new Point(f.x,f.y+i*d);else return new Point(f.x+i*d,f.y);}}

改行あり:

import java.util.*;
import java.awt.*;

class I{
    int m,n,p,g,a[][],b[][];
    Random r;
    Point s,e,c;
    ArrayList<Integer>z;

    void Q(String q,int l){if(l>0)System.out.println(q);else System.out.print(q);}

    void G(String[]y){
        m=Integer.valueOf(y[0]);
        n=Integer.valueOf(y[1]);
        p=Integer.valueOf(y[2]);
        r=new Random(p);
        Q("",1);

        int o=0,i,j,u=0;
        char t,f[]={85,76,68,82};
        while(o<3){
            if(++u%20000==0)
                Q("\r#"+u,0);

            a=new int[m+2][n+2];
            b=new int[m+2][n+2];
            for(i=0;i<m+2;i++)
                for(j=0;j<n+2;j++)
                    if(i==0||i==m+1||j==0||j==n+1)
                        a[i][j]=2;

            s=new Point(); 
            int e=r.nextInt(m*2+n*2);
            if(e<m*2){
                s.x=e%m+1;
                s.y=e<m?0:n+1;
            }else{
                s.y=(e-m*2)%n+1;
                s.x=(e-m*2)<n?0:m+1;
            }
            if(s.x<1)g=3;
            else if(s.x>m)g=1;
            else if(s.y<1)g=2;
            else if(s.y>n)g=0;

            a[s.x][s.y]=0;
            c=new Point(s);
            z=new ArrayList<Integer>();
            z.add(g);

            for(i=0;i++<Math.min(m,n)-1;)
                if(N()<1&&N()<1)
                        break;
            o=((z.size()>=Math.min(m,n)-1)?1:0)+F()+((V()==z.size())?1:0);
        }

        Q("\r",0);
        for(j=1;j<n+1;j++){
            for(i=1;i<m+1;i++)
                Q(String.valueOf(a[i][j]>0?'O':'.'),0);
            Q("",1);
        }
        Q("\n\n",0);
        if(s.x<1||s.x>m){
            t=s.x<1?'L':'R';
            u=s.y;
        }else{
            t=s.y<1?'T':'B';
            u=s.x;
        }
        Q(t+" "+u,1);
        if(e.x<1||e.x>m){
            t=e.x<1?'L':'R';
            u=e.y;
        } else {
            t=e.y<1?'T':'B';
            u=e.x;
        }
        Q(t+" "+u,1);
        for(i=0;i<z.size();)
            Q(String.valueOf(f[z.get(i++)]),0);
        Q("",1);
    }

    public static void main(String[]a){
        new I().G(a);
    }

    int F(){
        int c=0;
        while(C()<1&&c++<10)
            if(N()<1)
                return 0;
        return e==null?0:1;
    }

    int C(){
        int d=g<2?-1:1;
        if(g%2<1){
            int y=c.y;
            while(y>0&&y<n+1){
                y+=d;
                if(a[c.x][y]==1)
                    return 0;
            }
            e=new Point(c.x,y);
        }else{
            int x=c.x;
            while(x>0&&x<m+1){
                x+=d;
                if(a[x][c.y]==1)
                    return 0;
            }
            e=new Point(x,c.y);
        }
        a[e.x][e.y]=0;
        return 1;
    }


    int V(){
        if((s.x-e.x)+(s.y-e.y)<2)
            return 0;
        Queue<Point>q=new ArrayDeque<Point>();
        Queue<Integer>d=new ArrayDeque<Integer>();
        a[s.x][s.y]=-2;

        q.add(s);
        d.add(0);
        while(q.size()>0){
            Point t=q.poll();
            int h=d.poll(),i=0;
            if(t.equals(e))
                return h;
            for(;i<4;i++){
                Point n=S(a,t,i<2?0:1,i%2<1?-1:1,99,1);
                if(a[n.x][n.y]==-2)
                    continue;
                a[n.x][n.y]=-2;
                q.add(n);d.add(h+1);
            }
        }
        return 0;
    }


    int N(){
        Point q;
        int d=g<2?-1:1,x,y;
        System.arraycopy(a,0,b,0,a.length);
        q=S(b,c,g,d,r.nextInt((g%2<1?n:m)/2)+2,0);      
        if(q.x<1||q.y<1||q.x>m||q.y>n||q.equals(c)||b[q.x][q.y]!=0)
            return 0;
        x=q.x;
        y=q.y;
        if(g%2<1)
            y+=d;
        else
            x+=d;
        if(b[x][y]<0)
            return 0;
        b[q.x][q.y]=-1;
        b[x][y]=1;
        int f=r.nextInt(2)<1?-1:1;          
        g=g%2<1?(f<0?1:3):(g=f<0?0:2);
        c=q;
        System.arraycopy(b,0,a,0,a.length);
        z.add(g);
        return 1;
    }

    Point S(int[][]u,Point f,int w,int d,int q,int s){
        int i=1,x=f.x,y=f.y;
        for(;i<=q;i++){
            if(w%2<1)
                y=f.y+i*d;
            else
                x=f.x+i*d;
            if(e!=null&&e.x==x&&e.y==y)
                return e;
            if(y<0||y>n+1||x<0||x>m+1)
                return f;
            if(s<1&&u[x][y]<1)
                u[x][y]=-1;
            if(u[x][y]>0){
                if(w%2<1)
                    y-=d;
                else
                    x-=d;
                return new Point(x,y);
            }
        }
        if(w%2<1)
            return new Point(f.x,f.y+i*d);
        else
            return new Point(f.x+i*d,f.y);              
    }
}

できませんでしたwhile(o<3){...;o=...;}ことがfor(;o<3;o=...){...;}1バイトを保存し、?
ジョナサンフレッチ

if(w%2<1)return new Point(f.x,f.y+i*d);else return new Point(f.x+i*d,f.y);-> return new Point(f.x+(w%2<1?0:i*d),f.y+(w%2<1?f.y:0));
ジョナサンフレッチ

3

Pythonの、235の 206 185 176文字

H,W,P=input()
t=''
for x in range(16):t+=".O"[(P>>x)%2]
for n in[t[1:],t[0],"O","...O"]+["."]*(H-5)+[".O.."]:print(n*W)[:W]
print"B 1\nR",(H,3)[-W%4/2],"\n",("URDR"*W)[:W+W%2]

使用法

入力は、形式の標準入力を介して行われ[M, N, P]ます。

$ echo [14, 17, 2] | python ice.py
O..............O.
.................
OOOOOOOOOOOOOOOOO
...O...O...O...O.
.................
.................
.................
.................
.................
.................
.................
.................
.................
.O...O...O...O...
B 1
R 3
URDRURDRURDRURDRUR

あなたは、マップは種ごとに異なっていなければならないと言いましたP...そしてそれらは:

$ echo [14, 17, 233] | python ice.py
..O.OOO..........
OOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOO
...O...O...O...O.
.................
.................
.................
.................
.................
.................
.................
.................
.................
.O...O...O...O...
B 1
R 3
URDRURDRURDRURDRUR
$ echo [14, 17, 65133] | python ice.py
.OO.OO..OOOOOOO.O
OOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOO
...O...O...O...O.
.................
.................
.................
.................
.................
.................
.................
.................
.................
.O...O...O...O...
B 1
R 3
URDRURDRURDRURDRUR

そして、異なるサイズの例:

$ echo [10, 15, 65133] | python ice.py
.OO.OO..OOOOOOO
OOOOOOOOOOOOOOO
OOOOOOOOOOOOOOO
...O...O...O...
...............
...............
...............
...............
...............
.O...O...O...O.
B 1
R 10
URDRURDRURDRURDR

提供されたすべての客観的基準を満たします:

  • それぞれPが異なるパズルにつながります
  • 解決策は1つしかないため、最短です
  • 解決策N + N%2は、少なくとも次の手順を実行します。N
  • ソリューションは常に2 (M + N)合計スペースよりも多くを必要とします

説明

各行は、特定の文字列要素を繰り返しWて長さを制限することで構成されますWHとのW代わりにMand を使用しますN)。

最初の2行は、P各パズルを一意にするために依存しています。基本的Pに、16ビットの符号なし整数に適合することに注意してください。0と1 Pを使用.して、バイナリに変換しOます。

t=''
for x in range(16):t+=".O"[(P>>x)%2]

最初の行要素は最後の15ビット、t[1:]2番目の行要素は1番目のビット、t[0]です。最小幅が15であるため、すべてを1つの行に配置できませんでしたP。32767を超える場合、16ビットすべてに適合しません。したがって、最初の2行は、の可能な値のそれぞれを一意に表しますP

3番目の行は完全な壁であるため、の値はPソリューションに影響しません。

その後、実際の迷路要素に従ってください。この行はすべてを印刷し、上限まで繰り返します。結果は上記のとおりです。

for n in[t[1:],t[0],"O","O..."]+["."]*(H-5)+["..O."]:print(n*W)[:W]

残りは、動的に生成された迷路を解決する方法を考え出すことでした。これは、迷路の幅のみに依存します。与えられた幅に対する解決策は次のとおりであることに注意しました。

  W  | solution 
-----+---------
  1  | UR
  2  | UR
  3  | UR DR
  4  | UR DR 
  5  | UR DR UR
  6  | UR DR UR
  7  | UR DR UR DR
  8  | UR DR UR DR

など。したがってURDR、適切な場所で繰り返され、切り取られW+W%2ます。

print"B 1\nR",(H,3,3,H)[W%4],"\n",("URDR"*W)[:W+W%2]

1
整数の33番目のビットまでどのように機能しますか?
masterX244 14年

@ masterX244:ゴルフのとてもたくさん...基本的には、出力の反復性を悪用し、必ずそれを適切すべての行を補うために、いくつかの数学をやって
クラウディウ

ほとんど(PSはdownvoteは私からではなかった)「ランダム」が行われているかについて疑問に思う
masterX244

@ masterX244:あー 説明を追加します
Claudiu 14年

1
否定的な意味ではありませんでした。それは確かに賢いです、私は野心的なゲーム
開発者が
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.