Itu sia-sia

12

Saya pernah mengalami permainan (mini) ini di mana Anda memiliki 4 atau lebih pipa vertikal yang dihubungkan oleh sejumlah pipa horisontal dan Anda harus menjatuhkan bola atau air ke dalam pipa vertikal.
Ada 2 jenis yang saya ketahui:

  • Masukkan benda ke dalam ember / keranjang di bawah salah satu pintu keluar (tebak pipa yang akan dilemparkan)
  • Tebak pipa dari mana objek itu berasal.

Pipa sampel:

|       |       |-------|  
|-------|       |-------|  
|       |-------|       |  
|-------|-------|-------|  
|       |-------|       |  
|-------|       |-------|  
|-------|       |-------|  
|       |-------|       |  

Aturan dasar:

  • Saat bergerak melalui pipa horizontal objek akan turun jika memungkinkan
  • Saat bergerak melalui pipa vertikal, objek akan berubah menjadi pipa horizontal jika memungkinkan.

Pekerjaan Anda

  • Tulis program yang akan membuat kisi-kisi pipa acak (lihat contoh pipa).
  • Harus ada setidaknya 4 pipa vertikal dan cukup banyak pipa horizontal setidaknya 10.
  • Panjang pipa vertikal terserah Anda.
  • Perlihatkan jalur yang diperlukan objek untuk mencapai bagian bawah dan tunjukkan berapa banyak belokan yang diperlukan untuk sampai ke sana.
  • (Opsional) input untuk menentukan titik awal, pipa bernomor 1..N dari kiri ke kanan.

Tampilan:

 | vertical pipe
 - horizontal pipe
 : vertical pipe used by the object
 = horizontal pipe used by the object
 V Object starting point
 ^ Object ending point

Contoh:

V
:       |       |-------|
:=======:       |-------|
|       :=======:       |
|-----!-:=======:       |
|       :=======:-------|
|-------|       :=======:
|-------|       :=======:
|       :=======:       |
        ^
14 turns were taken to get to the end.

Detail
Objek memasuki pipa 1 dan mulai bergerak ke bawah, ke kiri ke pipa horizontal pertama.
Kembali ke bawah dan ke pipa kedua diikuti oleh putar-U ke pipa ketiga.
Pada akhir pipa ketiga Anda melihat tanda seru,
seharusnya tidak ada dalam hasil Anda, tetapi saya menggunakan ini untuk menunjukkan kepada Anda objek itu bisa lurus ke depan.
Namun aturan nomor 1 mencegah itu.

Pemenang akan ditentukan oleh suara dalam 3 minggu dari sekarang 24-02-2014 (dd-mm).

Selamat coding ^. ^

Teun Pronk
sumber
7
Apa yang terjadi jika ada benda yang jatuh dan ada pipa di kiri dan setinggi pipa di kanan?
Howard
2
Juga karena input dan output sudah diperbaiki saya tidak berpikir itu ide yang baik untuk membuatnya menjadi kontes popularitas .
Howard
@ Howard - apa yang akan Anda tandai sebagai, lalu? "Pemenang akan ditentukan oleh suara" sepertinya konteks popularitas bagi saya - tentu saja tidak ada golf atau kriteria keberhasilan lainnya di sini, dan itu bukan output string yang tetap
jimbobmcgee
1
@ Davidvidarraher - bagaimana dengan pinball, bukan air? Dengan setiap pipa horizontal menjadi sedikit magnet? Dan magnetisme itu dinyalakan ketika bola mencapai ujung bagian downpipe dan mati ketika memasuki pipa horizontal! Dengan laser-tripwire. :-) (Magnet, bagaimana mereka bekerja ?!) (Laser-tripwires, bagaimana mereka bekerja !!?)
jimbobmcgee
1
@Fabinout - ini lebih baik bukan pekerjaan rumah yang berdarah! Saya telah menghabiskan terlalu banyak pekerjaan yang sangat baik di hari kerja untuk menghilangkan jawaban saya untuk ini!
jimbobmcgee

Jawaban:

24

Mathematica

Kode 2D menghasilkan grafik yang menunjukkan jalur air. Saya menampilkan nomor vertex untuk pemeriksaan silang yang nyaman dengan tampilan 3D. Biasanya angka titik akan disembunyikan.

Memasukkan:

r=10;c=7;
result=flow2D[{r,c},3]

Sebenarnya, hasilnya berisi banyak objek. Objek pertama result[[1]],, adalah grafik 2D yang ditunjukkan di sini.

2D


Pipa 3 dimensi Tube(garis 3D) diplot dalam 3 ruang. Koordinat dihitung berdasarkan simpul dari grafik 2D sepanjang koordinat ke-3 yang dihasilkan secara acak (Hal ini memungkinkan pipa untuk mengambil posisi yang berbeda sepanjang y setiap kali kode dijalankan.)

Sumbu ditampilkan untuk membantu pembaca meyakinkan dirinya sendiri bahwa rendering 3D memang didasarkan pada rendering 2D.

Input 3D yang menarik di sini adalah:

Graphics3D[{CapForm[None],verticalPipes,allRungs,Darker@Red,connections},
ImageSize->600,Axes-> True,Ticks->{Range[1,2 r,2],Range[c],Range[10]},ViewPoint->{0,-2,1.5}]

Angka atau baris, kolom dan kolom entri diambil dari kode 2D. Mereka tidak harus dimasukkan kembali.

3D

Kode 2D

Dalam beberapa hari mendatang saya akan mendokumentasikan dan merapikan kode untuk 2D dan 3D.

flow2D[{rows_,columns_},startColumn_]:=
Module[{r=rows,c=columns,g,j,h,ends,middle,midcuts,direction="down",turns=0,path,rungs},

   (*complete gridgraph*)
g=GridGraph[{r,c},VertexSize-> Medium,GraphStyle->"Prototype",EdgeStyle->"Thick",
  VertexLabels->"Name",ImagePadding-> 30,ImageSize->470];

(*horizontal pipes that must be removed*)
ends=Table[r(c1-1)+r1\[UndirectedEdge] r(c1)+r1,{c1,1,c-1},{r1,{1,r}}];

(*horizontal pipes to consider removing *)
middle=Table[r(c1-1)+r1\[UndirectedEdge] r(c1)+r1,{c1,1,c-1},{r1,2,r-1}];
midcuts=RandomSample[#,RandomInteger[Round[{r/15,2r/5}]]]&/@middle;

rungs=Flatten[midcuts(*Join[ends,midcuts]*)];

j=EdgeDelete[g,Flatten[Join[ends,midcuts]]];

h[path_]:= Module[{start=path[[-1]],right,left,up,down,newnodes}, 
     {v=NeighborhoodGraph[j,start,1,(*VertexLabels\[Rule]"Name",*)ImagePadding->25],
     VertexList[v]};newnodes=Complement[VertexList[v],path];
     If[newnodes=={},path,  
     h[Append[path,
  Switch[direction,
   "down",Which[
     MemberQ[newnodes,start+r],(turns++;direction="right";start+r),
     MemberQ[newnodes,start-r],(turns++;direction="left";start-r),
     MemberQ[newnodes,start-1],start-1],
   "right",Which[
     MemberQ[newnodes,start-1],(turns++;direction="down";start-1),
     MemberQ[newnodes,start+r],start+r],  
   "left",Which[
     MemberQ[newnodes,start-1],(turns++;direction="down";start-1),
     MemberQ[newnodes,start-r],start-r]
    ]]]]];
{HighlightGraph[j,path=h[{r*startColumn}],ImageSize->300],path,rungs,ends,midcuts}]

convert[node_,r_,c_]:=Append[footing[[Quotient[node-1,r]+1]],Mod[node-1,r]+1(*Mod[node,r]*)]
connect[a_\[UndirectedEdge]b_,r_,c_]:=Tube[Line[{convert[a,r,c],convert[b,r,c]}],0.2]

Kode 3D dan hasilnya

r=10;c=7;
result=flow2D[{r,c},3];
g2D=result[[1]];
path2D=result[[2]];
\[AliasDelimiter]
xScale=2;
footing = {#, RandomInteger[{1, 6}]} & /@ Range[1,xScale c, xScale];
verticalPipes=Tube[Line[{Append[#,1],Append[#,r]}],.19]&/@footing;
Graphics3D[{CapForm[None],verticalPipes},ImageSize->600,Axes->True,AxesEdge->Automatic,ViewPoint->{0,-2,1.5},
Ticks->{Range[1,2 r,2],Range[c],Range[10]}];

path3D=UndirectedEdge@@@Partition[Riffle[stops=path2D,Rest@stops],2];
allRungs=connect[#,r,c]&/@rungs;
connections=connect[#,r,c]&/@path3D;

path2D;
g2D
Graphics3D[{CapForm[None],verticalPipes,allRungs,Darker@Red,connections},
ImageSize->600,Axes-> True,Ticks->{Range[1,2 r,2],Range[c],Range[10]},ViewPoint->{0,-2,1.5}]
DavidC
sumber
2
Jika Anda dapat membuat jalur, ini pasti akan menang dengan mudah! Bisakah Anda mengubah warna pipa, berdasarkan apakah simpul "disentuh"?
jimbobmcgee
1
Saya pikir saya bisa mengubah warna pipa untuk menunjukkan jalan yang diambil. Saya tidak yakin bagaimana memutuskan pipa penghubung (horisontal) mana yang harus "diambil" dan mana yang harus dihindari. Saat ini semua pipa penghubung "terbuka".
DavidC
Pilih satu secara acak, atau buat itu bisa didefinisikan seperti yang saya lakukan di tambang? Masih akan menang - hasilnya terlalu cantik untuk tidak !!
jimbobmcgee
1
Saat ini, Anda tampaknya mengambil beberapa pipa horizontal pada tingkat yang sama. Saya percaya ini melanggar Aturan Dasar # 1.
Timwi
Timwi, terima kasih. Pengawasan itu telah diperbaiki.
DavidC
12

C #

(via LINQPad, dalam mode "C # Program";)

Akan harus menerapkan Equitable Stroke Control, sejauh mungkin bermain golf, tapi ini adalah pendekatan saya di C # (well, LINQPad, tapi siapa yang mau semua boilerplate yang digunakan untuk membuat aplikasi C # berfungsi?) .

Definisi grid adalah variabel, dengan sejumlah pipa vertikal dan tinggi struktur keseluruhan, dan diulang-acak dengan melewatkan benih (lihat PipeGridkonstruktor).

Dengan tidak adanya jawaban pasti tentang ke arah mana objek akan mengalir jika salah satu arah itu mungkin, saya telah memungkinkan Anda untuk menentukan perilaku dari sejumlah opsi (lihat SolveBehaviorenumerasi / PipeSolverkonstruktor).

Mulai vertikal dapat ditentukan (lihat PipeSolver.Solve).

Saya berasumsi bahwa pipa horizontal selalu berada di antara dua pipa vertikal yang berdekatan , yaitu tidak ada pipa horisontal yang dapat memotong pipa horizontal.

///<summary>Entry point</summary>
void Main()
{
    var grid = new PipeGrid(vertical:10, height:10, seed:5);
    var solver = new PipeSolver(grid, SolveBehavior.FlipFlop);
    solver.Solve(start:2);
}

///<summary>Represents the direction the object is travelling</summary>
enum Direction
{
    Down = 0,
    Left = 1,
    Right = 2
}

///<summary>Determines the route to take if a junction yields both horizontal directions</summary>
enum SolveBehavior
{
    ///<summary>Throws an <see cref="InvalidOperationException" /></summary>
    Fail = 0,

    ///<summary>Prefers the left-most direction (screen-relative)</summary>
    FavorLeft = 1,

    ///<summary>Prefers the right-most direction (screen-relative)</summary>
    FavorRight = 2,

    ///<summary>Alternates preferred direction, based on the number of turns</summary>
    FlipFlop = 3,

    ///<summary>Prefers the same direction the object travelled, on its last horizontal movement</summary>
    SameDirection = 4,

    ///<summary>Prefers the opposite direction the object travelled, on its last horizontal movement</summary>
    Uturn = 5
}

///<summary>Provides the logic for solving a <see cref="PipeGrid" /></summmary>
class PipeSolver
{
    ///<summary>Creates a new <see cref="PipeSolver" /> for the supplied <paramref name="grid" />,
    ///with the given <paramref name="behavior" /> used to resolve junctions with both horizontal 
    ///paths</summary>
    public PipeSolver(PipeGrid grid, SolveBehavior behavior = SolveBehavior.FlipFlop)
    {       
        if (grid == null) throw new ArgumentNullException("grid");
        _grid = grid;
        _behavior = behavior;
    }

    private readonly PipeGrid _grid;
    private readonly SolveBehavior _behavior;

    ///<summary>Simulate the dropping of an object to run through the grid, at the top of a
    ///given <paramref name="start" /> vertical pipe</summary>
    public void Solve(int start = 1, bool dumpFrames = false, string tag = "Result")
    {
        if (start < 1) start = 1;
        if (start > _grid.Verticals) start = _grid.Verticals;

        int x, y;

        Direction?[,] path = new Direction?[_grid.Width, _grid.Height];

        x = (start - 1) * 2;
        y = 0;
        Direction dir = Direction.Down, lastDir = Direction.Down;

        int turns = 0;      
        do
        {
            path[x, y] = dir;       // we moved through this pipe

            // rule 1: when moving through horizontal pipe, object will go down when possible
            if ((dir == Direction.Left || dir == Direction.Right) && (x % 2 == 0))
            {
                lastDir = dir;
                dir = Direction.Down;
                ++turns;
            }
            // rule 2: when moving through start pipe, object will turn into horizontal pipe when possible
            else if (dir == Direction.Down)
            {
                bool hasLeft  = (x > 0 && _grid[x - 1, y]);
                bool hasRight = (x < _grid.Width - 1 && _grid[x + 1, y]);

                if (hasLeft && hasRight)
                {
                    switch (_behavior)
                    {
                        case SolveBehavior.FavorLeft: 
                            hasRight = false;       // "forget" about right pipe
                            break;
                        case SolveBehavior.FavorRight:
                            hasLeft = false;        // "forget" about left pipe
                            break;
                        case SolveBehavior.FlipFlop:
                            if (turns % 2 == 0) hasLeft = false;
                            else hasRight = false;  // "forget" about left on the even moves, or right on the odd moves
                            break;
                        case SolveBehavior.SameDirection:   // force staying in the same direction
                            if (lastDir == Direction.Left)       hasRight = false;
                            else if (lastDir == Direction.Right) hasLeft = false;
                            else goto case SolveBehavior.FlipFlop;  // use the flip-flop behaviour to determine first turn
                            break;
                        case SolveBehavior.Uturn:   // force turning back on itself
                            if (lastDir == Direction.Left)       hasLeft = false;
                            else if (lastDir == Direction.Right) hasRight = false;
                            else goto case SolveBehavior.FlipFlop;  // use the flip-flop behaviour to determine first turn
                            break;
                        default: throw new InvalidOperationException(
                            "Failed to find distinct path, with no resolving behavior defined"
                        );
                    }
                }

                if (hasLeft)        dir = Direction.Left;
                else if (hasRight)  dir = Direction.Right;

                if (hasLeft || hasRight) ++turns;
            }

            switch (dir)    // update position, based on current direction
            {
                case Direction.Left:  if (x > 0) --x; break;
                case Direction.Right: if (x < _grid.Width - 1) ++x; break;
                default: ++y; break;
            }
            if (dumpFrames) 
            {
                DumpFrame(path, start, tag:string.Concat("Frame #", turns, " (", _grid.Seed, ")"));
                DrawFrame(path, start, tag:string.Concat("Frame #", turns));
            }
        } 
        while (y < _grid.Height);

        int end = (x / 2) + 1;
        DumpFrame(path, start, end, turns, tag);
        DrawFrame(path, start, end, turns, tag);
    }

    ///<summary>Internal method for drawing a given frame</summary>
    private void DumpFrame(Direction?[,] path, int start, int? end = null, int? turns = null, string tag = null)
    {
        var builder = new StringBuilder();

        builder.Append(' ', --start * 5).AppendLine("v");
        for (int y = 0; y < _grid.Height; y++)
        {
            for (int x = 0; x < _grid.Width; x++)
            {
                builder.Append(
                    (x % 2 == 0) 
                        ? path[x, y].HasValue ? ":"    : _grid[x, y] ? "|"    : " "
                        : path[x, y].HasValue ? "====" : _grid[x, y] ? "----" : "    "
                );
            }
            builder.AppendLine();
        }
        if (end.HasValue)   builder.Append(' ', (end.Value - 1) * 5).AppendLine("^");

        if (turns.HasValue) builder.Append(turns.Value)
                                   .Append(" turns were taken to get to ")
                                   .AppendLine(end.HasValue ? "the end." : "this point.");

        builder.ToString().Dump(string.IsNullOrWhiteSpace(tag) ? "Frame" : tag);
    }

    ///<summary>Internal method for rendering a frame as a bitmap</summary>
    private void DrawFrame(Direction?[,] path, int start, int? end = null, int? turns = null, string tag = null)
    {
        using (var sprites = new Sprites())
        using (var canvas = new Bitmap(16 * _grid.Width, 16 * (_grid.Height + 3)))
        using (var graphics = Graphics.FromImage(canvas))
        {
            graphics.FillRectangle(Brushes.Green, 0, 16, 16 * _grid.Width, 16 * _grid.Height);
            _grid.Draw(graphics, sprites, offsetX:0, offsetY:16);

            // draw the start position
            start = (start - 1) * 32;
            graphics.DrawImageUnscaled(sprites.RoadVertical, start, 0);
            graphics.DrawImageUnscaled(sprites.CarVertical,  start, 0);
            graphics.DrawImageUnscaled(sprites.StartFlag,    start, 0);

            // draw the path
            for (int y = 0; y < _grid.Height; y++)
            for (int x = 0; x < _grid.Width;  x++)
            {
                if (path[x, y].HasValue)
                {
                    Image car;

                    switch (path[x, y])
                    {
                        case Direction.Left:
                            // if even, then on a vertical, so turning left; otherwise travelling left
                            car = (x % 2 == 0) ? sprites.CarTurnLeft : sprites.CarLeft;
                            break;
                        case Direction.Right:
                            // if even, then on a vertical, so turning right; otherwise travelling right
                            car = (x % 2 == 0) ? sprites.CarTurnRight: sprites.CarRight;
                            break;
                        default:
                            car = sprites.CarVertical;
                            if (x == 0 && path[x + 1, y].HasValue)                            // far-left and will move right = turn-right
                                car = sprites.CarTurnRight;
                            else if (x == _grid.Width - 1 && path[x - 1, y].HasValue)         // far-right and will move left = turn-left
                                car = sprites.CarTurnLeft;
                            else if (x > 0 && x < _grid.Width - 1)
                            {
                                car = sprites.CarVertical;                                    // if not right or left, then down
                                if (path[x + 1, y].HasValue && !path[x - 1, y].HasValue)      // if came from the left, then turn right
                                    car = sprites.CarTurnRight;
                                else if (path[x - 1, y].HasValue && !path[x + 1, y].HasValue) // if came from the right, then turn left
                                    car = sprites.CarTurnLeft;
                            }
                            break;
                    }

                    graphics.DrawImageUnscaled(car, 16 * x, 16 * (y + 1));
                }
            }

            // draw the end position, if we are at the end
            if (end.HasValue)
            {
                end = (end - 1) * 32;
                graphics.DrawImageUnscaled(sprites.RoadVertical, end.Value, 16 * (_grid.Height + 1));
                graphics.DrawImageUnscaled(sprites.CarVertical,  end.Value, 16 * (_grid.Height + 1));
                graphics.DrawImageUnscaled(sprites.EndFlag,      end.Value, 16 * (_grid.Height + 1));
            }

            if (turns.HasValue) 
            {
                string s = string.Concat(turns.Value, " turns were taken to get to ", 
                                         end.HasValue ? "the end." : "this point.");

                graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
                graphics.DrawString(s, SystemFonts.DefaultFont, Brushes.Black, 0, 16 * (_grid.Height + 2));
            }

            canvas.Dump(tag ?? "Bonus");
        }       
    }
}

///<summary>Represents a configuration of pipes</summary>
class PipeGrid
{
    ///<summary>Creates a new <see cref="PipeGrid" />, of a given <paramref name="height" />
    ///with the given number of <paramref name="vertical" /> pipes, and randomly distributes 
    ///horizontal pipes between them, based on a repeatable <paramref name="seed" />.</summary>
    public PipeGrid(int vertical = 4, int height = 8, int? seed = null)
    {
        if (vertical < 2) vertical = 2;
        if (height < 2) height = 2;

        Width = (2 * vertical) - 1;
        Height = height;
        Verticals = vertical;

        Seed = seed ?? Environment.TickCount;
        var rnd = new Random(Seed);

        _nodes = new bool[Width,Height];
        for (int x = 0, xw = Width; x < xw; x++) 
        for (int y = 0; y < height; y++)
        {
            // place verticals in every even column, and randomly place horizontals in odd columns
            if (x % 2 == 0 || rnd.Next(0, 2) == 1)
                _nodes[x, y] = true;
        }
    }

    private readonly bool[,] _nodes;

    public int Width { get; private set; }
    public int Height { get; private set; }
    public int Verticals { get; private set; }
    public int Seed { get; private set; }

    public bool this[int x, int y] { get { return _nodes[x, y]; } }

    ///<summary>Renders the grid to the LINQPad results pane, for inspection</summary>
    public PipeGrid Dump(string tag = null)
    {
        var builder = new StringBuilder();

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                builder.Append(
                    (x % 2 == 0)
                        ? _nodes[x, y] ? "|"    : " "
                        : _nodes[x, y] ? "----" : "    "
                );
            }
            builder.AppendLine();
        }

        builder.ToString().Dump(string.IsNullOrWhiteSpace(tag) ? "Grid" : tag);
        return this;
    }

    ///<summary>Render the grid as a bitmap image</summary>
    public void Draw(Graphics g, Sprites s, int offsetX = 0, int offsetY = 0)
    {           
        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                if (_nodes[x, y])
                {   
                    Image sprite = sprite = s.RoadVertical;

                    if (x % 2 != 0) 
                        sprite = s.RoadHorizontal;
                    else if (x == 0 && _nodes[1, y])
                        sprite = s.JunctionTeeRight;
                    else if (x == Width - 1 && _nodes[x - 1, y])
                        sprite = s.JunctionTeeLeft;
                    else if (x > 0 && x < Width - 1)
                    {
                        if (_nodes[x - 1, y] && _nodes[x + 1, y])
                            sprite = s.JunctionCross;
                        else if (_nodes[x + 1, y] && !_nodes[x - 1, y])
                            sprite = s.JunctionTeeRight;
                        else if (_nodes[x - 1, y] && !_nodes[x + 1, y])
                            sprite = s.JunctionTeeLeft;
                    }

                    g.DrawImageUnscaled(sprite, 
                                        x:(16 * x) + offsetX, 
                                        y:(16 * y) + offsetY);
                }
            }
        }
    }

    ///<summary>Creates a <see cref="PipeGrid" /> with horizontal pipes at all possible positions</summary>
    public static PipeGrid CreateAllOpen(int verticals = 4, int height = 8)
    {
        var grid = new PipeGrid(verticals, height, 0);
        for (int y = 0; y < height; y++)
        for (int x = 0, xw = grid.Width; x < xw; x++)
            grid._nodes[x, y] = true;

        return grid;
    }
}

///<summary>Store tile sprites, to be used in the graphical rendering of the result</summary>
class Sprites : IDisposable
{
    public Sprites()
    {
        byte[,] car = new byte[,] {
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 },
            { 0, 0, 0, 1, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0, 0 },
            { 0, 0, 0, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0, 0, 0 },
            { 0, 0, 0, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0, 0, 0 },
            { 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 3, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 3, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 0 },
            { 0, 0, 0, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0, 0, 0 },
            { 0, 0, 0, 1, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0, 0 },
            { 0, 0, 0, 1, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0, 0 },
            { 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0 },
            { 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        };
        byte[,] road = new byte[,] {
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 6, 6, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
        };
        byte[,] roadNESW = new byte[,] {
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
            { 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6 },
            { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
            { 2, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 2, 2, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 2, 2, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 2, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 2, 2, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 2, 2, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 2, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 2, 2, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 2, 2, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 2, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
            { 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
        };
        byte[,] roadNES = new byte[,] {
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
            { 0, 6, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 0, 6, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 0, 6, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 0, 6, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 0, 6, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 0, 6, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 0, 6, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 0, 6, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 0, 6, 2, 2, 5, 5, 2, 5, 5, 2, 5, 5, 2, 2, 2, 2 },
            { 0, 6, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 5, 2, 2, 2 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6 },
            { 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0 },
        };
        byte[,] start = new byte[,] {
            { 0, 0, 1, 1, 1, 0, 4, 4, 4, 0, 0, 0, 4, 0, 0, 0 },
            { 0, 0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0 },
            { 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0 },
            { 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0 },
            { 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0 },
            { 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0 },
            { 0, 0, 1, 4, 4, 4, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        };
        byte[,] end = new byte[,] {
            { 0, 0, 1, 1, 1, 0, 1, 1, 6, 0, 0, 0, 6, 0, 0, 0 },
            { 0, 0, 1, 6, 6, 6, 1, 1, 6, 6, 1, 1, 6, 0, 0, 0 },
            { 0, 0, 1, 1, 6, 6, 6, 6, 1, 6, 1, 1, 1, 0, 0, 0 },
            { 0, 0, 1, 1, 1, 1, 6, 6, 1, 1, 6, 6, 1, 0, 0, 0 },
            { 0, 0, 1, 1, 1, 1, 1, 1, 6, 1, 6, 6, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 6, 6, 1, 1, 6, 6, 1, 1, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 6, 6, 6, 6, 1, 6, 1, 1, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 1, 1, 6, 6, 1, 1, 6, 6, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 6, 6, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        };

        RoadVertical     = Sprite(road);
        RoadHorizontal   = RotateSprite(RoadVertical, 90);
        JunctionCross    = Sprite(roadNESW);
        JunctionTeeRight = Sprite(roadNES);
        JunctionTeeLeft  = FlipSprite(JunctionTeeRight, horizontal:true);
        CarVertical      = Sprite(car);
        CarLeft          = RotateSprite(CarVertical,  90);
        CarRight         = FlipSprite(CarLeft, horizontal:true);
        CarTurnLeft      = RotateSprite(CarVertical,  45);
        CarTurnRight     = FlipSprite(CarTurnLeft, horizontal:true);
        StartFlag        = Sprite(start);
        EndFlag          = Sprite(end);
    }

    public Image RoadVertical     { get; private set; }
    public Image RoadHorizontal   { get; private set; }
    public Image JunctionCross    { get; private set; }
    public Image JunctionTeeLeft  { get; private set; }
    public Image JunctionTeeRight { get; private set; }
    public Image CarVertical      { get; private set; }
    public Image CarLeft          { get; private set; }
    public Image CarRight         { get; private set; }
    public Image CarTurnLeft      { get; private set; }
    public Image CarTurnRight     { get; private set; }
    public Image StartFlag        { get; private set; }
    public Image EndFlag          { get; private set; }

    ///<summary>Create a sprite from the byte data</summary>
    private Image Sprite(byte[,] data) 
    {
        int width = data.GetLength(0);
        int height = data.GetLength(1);

        var image = new Bitmap(width, height);

        for (int y = 0; y < height; y++)
        for (int x = 0; x < width; x++)
        {
            Color c;
            switch (data[y,x])
            {
                case 1: c = Color.Black; break;
                case 2: c = Color.DarkGray; break;
                case 3: c = Color.Red; break;
                case 4: c = Color.LimeGreen; break;
                case 5: c = Color.Yellow; break;
                case 6: c = Color.White; break;
                default: continue;
            }

            image.SetPixel(x, y, c);
        }

        return image;
    }

    ///<summary>Rotate an image by a number of <paramref name="degrees" /> around the centre</summary>
    private Image RotateSprite(Image source, float deg)
    {
        var b = new Bitmap(source.Width, source.Height);

        using (var g = Graphics.FromImage(b))
        {
            float tx = (float)source.Width / 2.0f;
            float ty = (float)source.Height / 2.0f;

            g.TranslateTransform(tx, ty);
            g.RotateTransform(deg);
            g.TranslateTransform(-tx, -ty);
            g.DrawImageUnscaled(source, 0, 0);
        }

        return b;
    }

    ///<summary>Flip an image about its centre</summary>
    private Image FlipSprite(Image source, bool horizontal = false, bool vertical = false)
    {
        var b = new Bitmap(source);

        RotateFlipType rft = ( horizontal &&  vertical) ? RotateFlipType.RotateNoneFlipXY
                           : ( horizontal && !vertical) ? RotateFlipType.RotateNoneFlipX
                           : (!horizontal &&  vertical) ? RotateFlipType.RotateNoneFlipY
                           : RotateFlipType.RotateNoneFlipNone;

        b.RotateFlip(rft);
        return b;
    }

    #region IDisposable implementation
    public void Dispose() { Dispose(true); }
    ~Sprites() { Dispose(false); }
    protected void Dispose(bool disposing)
    {
        if (disposing)
        {
            GC.SuppressFinalize(this);
            using (RoadVertical) { }    
            using (RoadHorizontal) { }
            using (JunctionCross) { }
            using (JunctionTeeLeft) { }
            using (JunctionTeeRight) { }
            using (CarVertical) { }
            using (CarLeft) { }
            using (CarRight) { }
            using (CarTurnLeft) { }
            using (CarTurnRight) { }
            using (StartFlag) { }
            using (EndFlag) { };
        }
        RoadVertical = null;
        RoadHorizontal = null;
        JunctionCross = null;
        JunctionTeeLeft = null;
        JunctionTeeRight = null;
        CarVertical = null;
        CarLeft = null;
        CarRight = null;
        CarTurnLeft = null;
        CarTurnRight = null;
        StartFlag = null;
        EndFlag = null;
    }
    #endregion
}

Memperbarui:

Khawatir output teks lama saya mungkin sedikit membosankan untuk konteks popularitas ini, saya menawarkan versi yang diperpanjang yang juga menggambarkan jalur yang diambil sebagai gambar. Saya telah memodelkannya sebagai mobil, mengemudi melalui jaringan jalan yang mengerikan, mencoba untuk sampai ke bawah, tetapi dengan GPS terburuk di dunia yang memaksa Anda berbelok di setiap persimpangan.

Sebagai bonus, ini juga membuatnya lebih jelas untuk melihat 'belokan'.

Nikmati - vroom vroom !!

Contoh hasil:

(vertikal: 10, tinggi: 10, benih acak: 5, mulai pipa: 2, selesaikan perilaku: FlipFlop}) Contoh hasil, seperti yang terlihat di halaman hasil LINQPad, untuk {vertikal: 10, tinggi: 10, seed: 5, mulai: 2, perilaku: FlipFlop}

jimbobmcgee
sumber
8

C #

Waktu yang menyenangkan! :-)

Kode ini memastikan setidaknya ada beberapa pipa lurus di kedua ujung setiap pipa. Ini juga memastikan tidak ada belokan ambigu.

using System;

namespace Experiment.DownTheDrain
{
    class Program
    {
        static void Main(string[] args)
        {
            var program = new Program();
            program.Width = 19;
            program.Height = 17;
            program.SpanCount = program.Width * program.Height / 4;
            program.Spacing = 3;
            program.Run();
        }

        public int Width { get; set; }
        public int Height { get; set; }
        public int SpanCount { get; set; }
        public int Spacing { get; set; }
        public bool[,] Spans { get; private set; }

        public void Run()
        {
            GenerateSpans();
            DrawPipes();
            var pipe = ReadStartPipe();
            var turns = DrawPath(pipe);
            WriteTurns(turns);
            Console.ReadLine();
        }

        private void GenerateSpans()
        {
            Random random = new Random();
            Spans = new bool[Width, Height];

            int x, y;
            for (int i = 0; i < SpanCount; i++)
            {
                do
                {
                    x = random.Next(Width);
                    y = random.Next(Height);
                }
                while (SpanAt(x - 1, y) || SpanAt(x, y) || SpanAt(x + 1, y));
                Spans[x, y] = true;
            }
        }

        private void DrawPipes()
        {
            const string Junction = "│┤├┼";

            Console.CursorLeft = 0;
            Console.CursorTop = 0;
            DrawLabels();
            for (int y = -1; y <= Height; y++)
            {
                for (int x = 0; x <= Width; x++)
                {
                    Console.Write(Junction[(SpanAt(x-1,y) ? 1 : 0) + (SpanAt(x,y) ? 2 : 0)]);
                    Console.Write(x == Width ? Environment.NewLine : new string(SpanAt(x, y) ? '─' : ' ', Spacing));
                }
            }
            DrawLabels();
        }

        private void DrawLabels()
        {
            for (int x = 0; x <= Width; x++)
                Console.Write("{0}{1}",
                    (char)(x + 65),
                    x == Width ? Environment.NewLine : new string(' ', Spacing)
                );
        }

        private int ReadStartPipe()
        {
            Console.WriteLine();
            Console.Write("Please select a start pipe: ");
            int pipe;
            do
            {
                var key = Console.ReadKey(true);
                pipe = (int)char.ToUpper(key.KeyChar) - 65;
            }
            while (pipe < 0 || pipe > Width);
            Console.WriteLine((char)(pipe + 65));
            return pipe;
        }

        private int DrawPath(int x)
        {
            int turns = 0;
            Console.CursorTop = 1;
            for (int y = -1; y <= Height; y++)
            {
                if (SpanAt(x - 1, y))
                {
                    x--;
                    Console.CursorLeft = x * (Spacing + 1);
                    Console.WriteLine("╔{0}╝", new string('═', Spacing));
                    turns += 2;
                }
                else if (SpanAt(x, y))
                {
                    Console.CursorLeft = x * (Spacing + 1);
                    Console.WriteLine("╚{0}╗", new string('═', Spacing));
                    x++;
                    turns += 2;
                }
                else
                {
                    Console.CursorLeft = x * (Spacing + 1);
                    Console.WriteLine("║");
                }
            }

            return turns;
        }

        private void WriteTurns(int turns)
        {
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("{0} turns taken to reach the bottom.", turns);
        }

        private bool SpanAt(int x, int y)
        {
            return x >= 0
                && x < Width
                && y >= 0
                && y < Height
                && Spans[x, y];
        }
    }
}

Keluaran:

Kedalam selokan

Makanan Tangan
sumber
1
Sial, saya juga punya ide untuk menggunakan karakter menggambar kotak, Anda mengalahkan saya untuk itu :)
Timwi
Juga, saya suka ide memastikan tidak menghasilkan pipa dengan belokan yang ambigu. Saya tidak memikirkan itu!
Timwi
8

Funciton

Seolah-olah Funciton belum menjadi salah satu bahasa yang paling tidak berguna di dunia, ini jelas merupakan program yang paling tidak berguna yang saya tulis sejauh ini.

Karena ini terlihat jelek di StackExchange karena spasi baris tambahan, pertimbangkan untuk menjalankan yang berikut di konsol JavaScript browser Anda untuk memperbaikinya:

$('pre').each(function(){$(this).css('line-height',1)})

Karena Funciton tidak memiliki generator angka acak, saya memutuskan untuk membiarkan Anda memasuki pola pipa. Karena pengkodean pola tidak jelas, membenturkan tombol angka pada keyboard Anda secara acak sama baiknya dengan generator angka acak.

Input diharapkan menjadi tiga angka desimal yang dipisahkan oleh spasi. Angka pertama adalah lebarnya (satu lebih sedikit dari jumlah pipa vertikal); yang kedua adalah indeks pipa awal, dan yang terakhir adalah angka yang mengkodekan pola pipa horizontal; Anda dapat membuatnya sebesar yang Anda inginkan. Jika lebarnya negatif atau indeks pipa di luar jangkauan, hasilnya adalahImpossiburu.

Program ini secara otomatis memastikan bahwa tidak ada dua pipa horisontal yang bersebelahan, yang dapat menyebabkan belokan yang ambigu.

                            ┌───╖
               ┌────────────┤ ♯ ╟───────────┬───────────────┐
     ╔════╗  ┌─┴─╖  ┌────╖  ╘═══╝  ╔═══╗  ┌─┴─╖  ╔════╗     │
     ║ 21 ║  │ × ╟──┤ >> ╟─────────╢   ╟──┤ ʘ ╟──╢ 32 ║     │
     ╚═╤══╝  ╘═╤═╝  ╘═╤══╝         ╚═══╝  ╘═══╝  ╚════╝     │
       └───────┘  ┌───┴───┐                                 │
   ╔════╗  ┌───╖  │   ┌───┴──────────────────┐              │
   ║ 32 ╟──┤ ʘ ╟──┘   │          ╔═══╗       │              │
   ╚════╝  ╘═╤═╝    ┌─┴─╖        ║ 0 ╟───┐   │              │
     ┌───────┴──────┤ · ╟────┐   ╚═══╝ ┌─┴─╖ │              │
     │              ╘═╤═╝    └─────────┤ ʃ ╟─┘              │
     │     ┌──────────┘                ╘═╤═╝                │
   ┌─┴─╖ ┌─┴──╖  ┌─────────╖        ┌────┴────╖             │
   │ ♯ ║ │ >> ╟──┤ str→int ╟────┐   │ str→int ║             │
   ╘═╤═╝ ╘═╤══╝  ╘═════════╝  ┌─┴─╖ ╘════╤════╝           ┌─┴─╖
     │   ┌─┴─╖ ╔════╗         │ ░ ║   ┌──┴────────────────┤ · ╟────────────┐
     └───┤ × ╟─╢ 21 ║         ╘═╤═╝ ┌─┴─╖                 ╘═╤═╝            │
         ╘═══╝ ╚════╝┌─────┐    └───┤ ▒ ╟───┐ ┌─────────╖ ┌─┴─╖            │
      ┌─────────╖  ┌─┴─╖   │        ╘═╤═╝   ├─┤ str→int ╟─┤ ʃ ╟─┐          │
   ┌──┤ int→str ╟──┤ · ╟─┐ └──────────┘     │ ╘═════════╝ ╘═╤═╝ │          │
   │  ╘═════════╝  ╘═╤═╝ │ ╔══════════════╗ │ ╔═══╗  ┌──────┘   │          │
   │ ╔══════════╗  ┌─┴─╖ │ ║ 158740358500 ║ │ ║   ╟──┘ ┌───╖  ╔═╧═╗  ┌───╖ │
   │ ║ 20971533 ╟──┤   ╟─┘ ║ 305622435610 ║ │ ╚═══╝  ┌─┤ ≤ ╟──╢ 0 ╟──┤ ≥ ╟─┴─┐
   │ ╚════╤═════╝  └─┬─╜   ║ 491689778976 ║ └────────┤ ╘═╤═╝  ╚═══╝  ╘═╤═╝   │
   │    ┌─┴─╖  ┌───╖ │     ║ 886507240727 ║          │   └──────┬──────┘     │
   │    │ ‼ ╟──┤ ‼ ╟─┘     ║ 896192890374 ║          │         ┌┴┐           │
   │    ╘═╤═╝  ╘═╤═╝       ║ 899130957897 ╟───┐      │         └┬┘           │
   └──────┘    ┌─┴─╖       ╚══════════════╝ ┌─┴─╖  ┌─┴─╖        │            │
               │ ‼ ╟────────────────────────┤ ? ╟──┤ · ╟────────┤            │
               ╘═╤═╝                        ╘═╤═╝  ╘═╤═╝      ┌─┴─╖          │
 ╔═══════════════╧════════════════════════╗   │      └────────┤ ≥ ╟──────────┘
 ║ 83139057126481738391428729850811584337 ║       ┌────╖      ╘═══╝
 ║ 75842912478026089564602018574355013746 ║  ┌────┤ >> ╟──┐
 ║ 85373033606532129933858395805642598753 ║  │    ╘══╤═╝  │
 ║ 19381927245726769973108298347355345088 ║  │     ┌─┴─╖  │       ╓───╖
 ║ 84932603219463911206052446527634696060 ║  │     │ ░ ║  │       ║ ░ ║
 ║ 230797436494578049782495796264992      ║  │     ╘═╤═╝  │       ╙─┬─╜
 ╚════════════════════════════════════════╝  │    ┌──┴──┐ └─────────┴────────┐
                                             │    │   ┌─┴──╖ ┌┐   ┌┐         │
                                             │    │   │ << ╟─┤├─┬─┤├─────┐   │
   ┌────╖  ╔═══╗                             │    │   ╘═╤══╝ └┘ │ └┘   ╔═╧═╗ │
 ┌─┤ << ╟──╢ 1 ║                             │    │   ╔═╧═╗     │      ║ 1 ║ │
 │ ╘═╤══╝  ╚═══╝      ┌───────────────────┐  │    │   ║ 2 ║     │      ╚═╤═╝ │
 │   └─────┬──────────┴─────────┐         │  │ ┌──┴─╖ ╚═══╝   ┌─┴─╖ ┌┐   │   │
 │         │           ┌───┐  ┌─┴─╖       │  │ │ << ╟─────────┤ ? ╟─┤├───┤   │
 │         │           │   ├──┤ · ╟─┐     │  │ ╘══╤═╝         ╘═╤═╝ └┘   ├───┘
 │ ┌───┐ ┌─┴─╖ ┌───╖   └─┬─┘  ╘═╤═╝ ├───┐ │  │  ╔═╧═╗  ╔═══╗  ┌─┴─╖      │
 ├─┤   ├─┤ · ╟─┤ ♯ ╟─────┘    ┌─┴─╖ │   │ │  └──╢ 1 ║  ║ 0 ╟──┤ ? ╟──────┘
 │ └───┘ ╘═╤═╝ ╘═══╝  ┌───────┤ · ╟─┴─┐ │ │     ╚═══╝  ╚═══╝  ╘═╤═╝
 │       ┌─┴─╖      ┌─┴─╖     ╘═╤═╝   │ │ └─────────────────┐   │
 │  ┌────┤ · ╟──────┤ · ╟──┐    │     │ └────────┐          │
 │  │    ╘═╤═╝      ╘═╤═╝  │    │     └────┐     │          │
 │  └───┬──┴──┐       │    │    │        ┌─┴──╖  │          │
 │      │    ┌┴┐      │    │    └─────┬──┤ << ║  │          │
 │      │    └┬┘      │    │         ┌┴┐ ╘═╤══╝  │          │
 │    ┌─┴─╖ ┌─┴─╖   ┌─┴─╖  │         └┬┘ ╔═╧═╗   │          │
 └────┤ · ╟─┤ ? ╟─┐ │ ♯ ║  ├──────────┤  ║ 1 ║   │          │
      ╘═╤═╝ ╘═╤═╝ │ ╘═╤═╝ ┌┴┐         │  ╚═══╝   │          │
        │     │   │ ┌─┴─╖ └┬┘         │          │          │
        │     │   └─┤ ? ╟──┘        ┌─┴─╖        │          │
        │     │     ╘═╤═╝     ┌─────┤ > ╟─────┬──┘          │
        │     │     ┌─┴─╖   ┌─┴─╖   ╘═══╝     ├─────────┐   │
      ┌─┴─╖   └─────┤ · ╟───┤ · ╟─────────────┘         │   │
    ┌─┤ · ╟─────┐   ╘═╤═╝   ╘═╤═╝                       │   │
    │ ╘═╤═╝  ┌──┴─╖ ┌─┴─╖     │                         │   │
    │   │    │ >> ╟─┤ ▒ ╟──┐  ├─────────────┐         ┌─┴─╖ │
    │   │    ╘══╤═╝ ╘═╤═╝  ├──┘             │ ╓───╖ ┌─┤ · ╟─┤
    │   │       │   ┌─┴─╖  │                ├─╢ ▒ ╟─┤ ╘═╤═╝ │
    │   │       └───┤ · ╟──┘                │ ╙─┬─╜ │   │   │
    │   │           ╘═╤═╝                   │   │ ┌─┴─╖ │   │
    │   │           ┌─┴─╖                   │   └─┤ · ╟─┤   │
    │   │        ┌──┤   ╟────────────┐      │     ╘═╤═╝ │   │
    │   │        │  └─┬─╜  ┌───╖   ┌─┴─╖  ┌─┴─╖   ┌─┴─╖ │   │
    │   └──────┐ │    └────┤ ‼ ╟───┤ · ╟──┤ · ╟───┤ ▓ ╟─┘   │
    │          │ │         ╘═╤═╝   ╘═╤═╝  ╘═╤═╝   ╘═╤═╝     │
    │          │ │  ╔═══╗  ┌─┴─╖     │      └───────┘       │
    │          │ └──╢ 0 ╟──┤ ? ╟─┐   │                      │
    │          │    ╚═══╝  ╘═╤═╝ │ ┌─┴─╖                    │
    │ ╔═══╗    │           ┌─┴─╖ ├─┤ · ╟─┐                  │
    │ ║ 2 ║    │      ┌────┤ · ╟─┘ ╘═╤═╝ ├──────────────────┘
    │ ╚═╤═╝    │      │    ╘═╤═╝     │   │
    │ ┌─┴─╖  ┌─┴─╖  ┌─┴─╖  ╔═╧═╕ ┌─┐ │   │
    │ │ + ╟──┤ ? ╟──┤ ? ╟──╢   ├─┴─┘ │   │
    │ ╘═╤═╝  ╘═╤═╝  ╘═╤═╝  ╚═╤═╛     │   │
    │   └──┬───┘    ╔═╧═╗    │       │   │
    │      │        ║ 0 ║            │   │
    │      │        ╚═══╝            │   │
    │      └─────────────────────────┘   │
    └────────────────────────────────────┘        ╓┬──╖
 ┌────────────────────────────────────────────────╫┘▓ ╟────────────┐
 │ ╔═══════════╗        ╔════════════════════╗    ╙─┬─╜            │
 │ ║ 387759291 ║        ║ 385690484238253342 ║      │              │
 │ ║ 565251600 ║    ┌───╢ 839653020379129116 ║      │    ┌────┐    │
 │ ║ 199735775 ║  ┌─┴─╖ ╚════════════════════╝      │    │   ┌┴┐   │
 │ ║ 904933210 ╟──┤ ? ╟────────────────┐            │    │   └┬┘   │
 │ ╚═══════════╝  ╘═╤═╝    ┌──────┐    ├────────────┴────┘  ┌─┴─╖  │
 │ ╔═══════════╗  ┌─┴─╖  ┌─┴─╖  ╔═╧═╗  │  ╔════╗    ╔═══╗   │ ♯ ║  │
 │ ║ 388002680 ╟──┤ ? ╟──┤ ≠ ║  ║ 1 ║  │  ║ 21 ║  ┌─╢ 1 ║   ╘═╤═╝  │
 │ ║ 480495420 ║  ╘═╤═╝  ╘═╤═╝  ╚═══╝  │  ╚═╤══╝  │ ╚═══╝    ┌┴┐   │
 │ ║ 244823142 ║    │      ├───────────┘    │     │          └┬┘   │
 │ ║ 920365396 ║    │    ┌─┴─╖  ┌───╖     ┌─┴──╖  │ ┌────╖  ┌─┴─╖  │
 │ ╚═══════════╝    └────┤ · ╟──┤ ‡ ╟─────┤ >> ║  └─┤ >> ╟──┤ · ╟──┴─┐
 │ ╔═══════════╗ ┌───┐   ╘═╤═╝  ╘═╤═╝     ╘═╤══╝    ╘═╤══╝  ╘═╤═╝    │
 │ ║ 618970314 ╟─┘ ┌─┴─╖ ┌─┘      │         │       ┌─┴─╖     │      │
 │ ║ 790736054 ║ ┌─┤ ? ╟─┴─┐      │         ├───────┤ ▓ ╟─────┘      │
 │ ║ 357861634 ║ │ ╘═╤═╝   │      │     ┌───┘       ╘═╤═╝            │
 │ ╚═══════════╝ │ ┌─┴─╖ ┌─┴─╖  ┌─┴─╖ ┌─┴─╖         ┌─┴─╖     ╔═══╗  │
 │ ╔═══════════╗ │ │ ‼ ╟─┤ · ╟──┤ ? ╟─┤ · ╟─────────┤ · ╟──┐  ║ 1 ║  │
 │ ║ 618970314 ╟─┘ ╘═╤═╝ ╘═╤═╝  ╘═╤═╝ ╘═╤═╝         ╘═╤═╝  │  ╚═╤═╝  │
 │ ║ 790736054 ║     │   ┌─┴─╖  ┌─┴─╖   │   ╓┬──╖    ┌┴┐  ┌┴┐   │    │
 │ ║ 357861713 ║     └───┤ · ╟──┤ · ╟───┘ ┌─╫┘‡ ╟─┐  └┬┘  └┬┘   │    │
 │ ╚═══════════╝         ╘═╤═╝  ╘═╤═╝     │ ╙───╜ │ ┌─┴─╖  └────┤    │
 │ ╔════════════════╗    ┌─┴─╖  ┌─┴─╖     │ ┌───╖ │ │ ♯ ║       └────┘
 │ ║ 43980492383490 ╟────┤ ? ╟──┤ ? ╟───┐ └─┤ ‼ ╟─┘ ╘═╤═╝
 │ ╚════════════════╝    ╘═╤═╝  ╘═╤═╝   │   ╘═╤═╝    ┌┴┐
 │ ╔════════════════╗      │      │     │     │      └┬┘
 │ ║ 43980492383569 ╟──────┘            └──────┬──────┘
 │ ╚════════════════╝                          │
 └─────────────────────────────────────────────┘

Penjelasan

  • Program utama menemukan dua spasi pertama dan membagi angka. Ini menjalankan ketiga (pola pipa) melalui dan kemudian memanggil dengan hasilnya, yang mengembalikan output serta jumlah putaran yang diambil. Itu kemudian menambahkan teks n turns were taken to get to the end., di mana njumlah putaran dihitung oleh .

  • mengambil nomor dan memasukkan 0-bit setelah setiap 1-bit, sehingga memastikan tidak ada dua pipa horizontal berturut-turut.

  • menghasilkan output dengan memanggil secara berurutan dan kemudian menggeser jumlah bit yang tepat dari pola pipa sampai nol. Ini juga menambah atau mengurangi “pipa saat ini” dengan tepat.

  • menghasilkan satu baris output. Dalam setiap iterasi, ia menggeser keluar satu bit dari pola pipa dan kemudian memutuskan apakah akan menghasilkan (+ 4 spasi), (+ 4 spasi) ├────┤,, ╔════╝atau ╚════╗; dalam tiga kasus terakhir, ia menghilangkan karakter pertama dari iterasi berikutnya. Iterasi terakhir menghasilkan │\r\natau ║\r\nsesuai kebutuhan.

Contoh output

Memasukkan:

6 3 73497529294753

Keluaran:

├────┤    │    ║    │    │    │
├────┤    │    ╚════╗    ├────┤
│    ├────┤    ╔════╝    ├────┤
│    ├────┤    ║    │    │    │
│    │    │    ║    │    ├────┤
│    │    │    ║    ├────┤    │
│    ├────┤    ╚════╗    ├────┤
│    ├────┤    │    ║    │    │
│    ├────┤    ╔════╝    │    │
├────┤    ╔════╝    │    ├────┤
│    │    ║    │    │    ├────┤

10 turns were taken to get to the end.

Memasukkan:

3 0 65536

Keluaran:

║    │    │    │
║    │    │    │
║    │    ├────┤

0 turns were taken to get to the end.

Memasukkan:

3 7 75203587360867 (indeks pipa di luar jangkauan)

Keluaran:

Impossiburu.
Timwi
sumber
3

Groovy, 311

t=System.in.text.collect{it.collect{it}};s=t.size();d=0;c=0;y=0;x=t[0].indexOf('|');println' '*x+'V'
while(y<s){t[y][x]=t[y][x]=='|'?':':'='
if(d){x+=d}else y++
if(y<s)if(d){if(t[y][x]=='|'){d=0;c++}}else if(t[y][x+1]=='-'){d=1;c++} else if(t[y][x-1]=='-'){d=-1;c++}}
t.each{println it.join()}println' '*x+'^'+c
  • baris 1: setup dan temukan dulu |
  • baris 2: ganti swap keluar: atau =
  • baris 3: pindahkan x / y ke pos berikutnya (d = 0 = turun, d = -1 = kiri, d = 1 = kanan)
  • baris 4: cari arah selanjutnya
  • baris 5: cetak hasilnya

Ini diformat:

t=System.in.text.split('\n').collect{it.collect{it}}; s=t.size()
d=0; c=0; y=0; x=t[0].indexOf('|')
println ' '*x + 'V'
while (y<s) { 
    t[y][x] = t[y][x] == '|' ? ':' : '='
    if (d) {x += d} else y++
    if (y<s) 
        if (d) {if (t[y][x]=='|') {d = 0; c++}} 
        else if(t[y][x+1]=='-') {d = 1; c++}
        else if(t[y][x-1]=='-') {d = -1; c++}
}
t.each {println it.join()}
println ' '*x + '^'+c

Output dari sampel:

V
:       |       |-------|  
:=======:       |-------|  
|       :=======:       |  
|-------|-------:=======:  
|       |-------|       :  
|-------|       :=======:  
|-------|       :=======:  
|       |-------|       :
                        ^10

Output lainnya:

V
:       |       |-------|       |
:=======:       |-------|       |
|       :=======:       |-------|  
|-------|-------:=======:       |
|       |-------|       :=======:
|-------|       |-------|       :
|-------|       |-------|       :
|       |-------|       :=======:
|       |-------|       :       |
|       |       :=======:       |
|-------|       :       |       |
|       :=======:       |       |
|       :       |-------|       |
|       :=======:       |       |
                ^16

(Saya tahu saya melakukan kode-golf bukan popularitas, tapi itu hanya gaya saya)

krs
sumber
2

JavaScript

Kanvas HTML mendengarkan acara klik dan menemukan deretan pipa terdekat dan menggunakannya untuk titik awal. Keluaran diambil pada kanvas dan ada juga textarea yang berisi keluaran ASCII yang didefinisikan oleh OP.

Algoritma akan memastikan bahwa tidak ada dua yang menghubungkan pipa horisontal. Selain pembatasan itu, probabilitas didefinisikan dalam variabel awal dan yang digunakan untuk menentukan secara acak apakah pipa horizontal harus terjadi atau tidak.

JSFIDDLE

<html>
<head>
<script type="text/javascript">
var     WIDTH       = 20,
        HEIGHT      = 15,
        JUNCTIONS   = [],
        PROBABILITY = 0.2,
        COLOR1      = '#00DD00',
        COLOR2      = '#DD0000',
        RADIUS      = 4,
        SPACING     = 20,
        turns       = 0,
        pipe        = 10,
        canvas,
        context;

function Junction( x, y ){
    this.x = x;
    this.y = y;
    this.l = null;
    this.r = null;

    if ( y == 0 )
        JUNCTIONS[x] = [];

    JUNCTIONS[x][y] = this;

    var l = this.left();
    if ( x > 0 && l.l == null && Math.random() <= PROBABILITY )
    {
        this.l = l;
        l.r = this;
    }
}

Junction.prototype.left = function(){
    return this.x == 0?null:JUNCTIONS[this.x-1][this.y];
}
Junction.prototype.right= function(){
    return this.x == WIDTH-1?null:JUNCTIONS[this.x+1][this.y];
}
Junction.prototype.down = function(){
    return this.y == HEIGHT-1?null:JUNCTIONS[this.x][this.y+1];
}
Junction.prototype.reset = function(){
    this.entry = null;
    this.exit = null;
}

Junction.prototype.followPipe = function( prev ){
    this.entry = prev;
    if ( prev === this.l || prev === this.r ) {
        this.exit = this.down() || true;
        turns++;
    } else if ( this.l !== null ) {
        this.exit = this.l;
        turns++;
    } else if ( this.r !== null ) {
        this.exit = this.r;
        turns++;
    } else
        this.exit = this.down() || true;
    console.log( this.exit );
    if ( this.exit !== true )
        this.exit.followPipe( this );
}

Junction.prototype.toString = function(){
    if ( this.entry === null ){
        if ( this.r === null )  return '|  ';
                                        return '|--';
    } else {
        if ( this.r === null )  return ':  ';
                                        return ':==';
    }
}

function init(){
    for ( var x = 0; x < WIDTH; ++x )
        for ( var y = 0; y < HEIGHT; ++y )
            new Junction( x, y );

    canvas  = document.getElementById('canvas');
    context = canvas.getContext('2d');

    canvas.addEventListener('click', draw );

    draw();
}

function draw( evt ){
    for ( var x = 0; x < WIDTH; ++x )
        for ( var y = 0; y < HEIGHT; ++y )
            JUNCTIONS[x][y].reset();

    if ( evt ){ 
        pipe = Math.round((evt.clientX - canvas.getBoundingClientRect().left)/SPACING)-1;
        if ( pipe < 0 )     pipe = 0;
        if ( pipe >= WIDTH )    pipe = WIDTH - 1;
    }

    turns = 0;
    JUNCTIONS[pipe][0].followPipe( true );

    context.clearRect(0, 0, canvas.width, canvas.height);
    context.lineWidth = 2;

    for ( var y = 0; y < HEIGHT; ++y ) {
        for ( var x = 0; x < WIDTH; ++x ) {
            var j = JUNCTIONS[x][y];
                    e = j.entry;

            if ( j.r !== null ){
                context.beginPath();
                context.strokeStyle = e===null?COLOR1:COLOR2;
                context.moveTo(SPACING*(x+1), SPACING*(y+1));
                context.lineTo(SPACING*(x+2), SPACING*(y+1));
                context.stroke();
            }

            if ( y > 0 ){
                context.beginPath();
                context.strokeStyle = (e===JUNCTIONS[x][y-1])?COLOR2:COLOR1;
                context.moveTo(SPACING*(x+1), SPACING*(y));
                context.lineTo(SPACING*(x+1), SPACING*(y+1));
                context.stroke();
            }
        }
    }

    for ( var y = 0; y < HEIGHT; ++y ) {
        for ( var x = 0; x < WIDTH; ++x ) {
            context.beginPath();
            context.arc(SPACING*(x+1), SPACING*(y+1), RADIUS, 0, 2*Math.PI, false);
            context.fillStyle = JUNCTIONS[x][y].entry===null?COLOR1:COLOR2;
            context.fill();
        }
    }

    var h = [];
    for ( var x = 0; x < WIDTH; ++x )
        h.push( x!=pipe?'   ':'v  ' );
    h.push( '\n' );
    for ( var y = 0; y < HEIGHT; ++y ) {
        for ( var x = 0; x < WIDTH; ++x )
            h.push( JUNCTIONS[x][y].toString() )
        h.push( '\n' );
    }
    for ( var x = 0; x < WIDTH; ++x )
        h.push( JUNCTIONS[x][HEIGHT-1].exit!==true?'   ':'^  ' );
    h.push( '\n' );
    h.push( turns + ' turns were taken to get to the end.' );
    document.getElementById( 'output' ).value = h.join( '' );
}

window.onload   = init;
</script>
</head>
<body>
<p>Click on a row to show the path</p>
<canvas id="canvas" width="450" height="350"></canvas>
<textarea id="output" style="width:100%; height:24em;"></textarea>
</body>
</html>

Keluaran

http://imageshack.com/a/img600/9241/94wh.png

MT0
sumber