text:
Down the drain it goes
I once encountered this (mini) game where you had 4 or more vertical pipes that were connected by a number of horizontal pipes and you have to drop a ball or water into the vertical pipes.
There are 2 kinds I know of:

Get the object into a bucket/basket under one of the exits (guess
what pipe to throw it in)
Guess what pipe the object will come from.

Sample pipes:
|       |       |-------|
|-------|       |-------|
|       |-------|       |
|-------|-------|-------|
|       |-------|       |
|-------|       |-------|
|-------|       |-------|
|       |-------|       |

Basic rules:

When moving through a horizontal pipe the object will go down when
possible
When moving through a vertical pipe the object will turn into a horizontal pipe when possible.

Your job

Write a program that will create a random grid of pipes(see sample
pipes).
There should be at least 4 vertical pipes and a fair amount of horizontal pipes at least 10.
The length of the vertical pipes is up to you.
Show the path that the object took to reach the bottom and show how many turns it took to get there.
(Optional) input to deterimine starting point, pipes numbered 1..N from left to right.

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

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

Detail
The object enters pipe 1 and starts moving down, goes left into the first horizontal pipe.
Back down and into the second pipe followed by a U-turn into the third pipe.
At the end of the third pipe you see an exclamation mark,
shouldnt be in your result but I used this to show you the object could have gone straight ahead.
However rule number 1 prevents that.
Winner will be determined by votes in 3 weeks from now 24-02-2014 (dd-mm).
Happy coding ^.^

What happens if there the object is falling down and there is a pipe to the left and on the same height a pipe to the right?

Also since input and output is fixed I don't think it is a good idea to make it [tag:popularity-contest].

@Howard - what would you tag it as, then?  "Winner will be determined by votes" seems like a popularity context to me -- there's certainly no golfing or other success criteria here, and it's not a fixed string output

@Howard For what it's worth, my homeworks from a long time ago specified that the water goes in the same direction as before the fall. If I'm right, the first sample pipe would be {down, right, down, right, down, right, down down,...}

I'm having trouble making sense out of the behavior of the water.  It descends (due to gravity?) until it arrives at a junction. If the junction has a favorable (unclogged) horizontal pipe (Namely, ===) the water stops descending and flows into the inviting pipe.  [Shouldn't the downward trajectory then be blocked or otherwise displayed as unfavorable?]  If the horizontal pipe is not favorable (---), the water continues descending. It's as if vertical pipes were clogged or unclogged depending on the availability of alternative routes.  My intuitions about the underlying physics are puzzled.

@DavidCarraher - what about a pinball, rather than water?  With each horizontal pipe being a little bit magnetic? And that magnetism being turned on when the ball reaches the end of the section of downpipe and off when it enters the horizontal pipe!  By laser-tripwire.  :-) (Magnets, how do they work?!)  (Laser-tripwires, how to they work?!!)

@Fabinout - this better not be bloody homework!  I've wasted far too much of a perfectly good working weekday knocking out my answer to this!

jimbobmcgee I like the pinball model.  I'll give it some thought and see where it leads.

There is no rule about which direction it should go (left or right) for the first sample when it reaches line 4 ( |-------|-------|-------| ).

@krs correct, that is up to you.

Mathematica
The 2D code generates a graph showing the path of the water. I displayed the vertex numbers for convenient cross-checking with the 3D display.  Normally the vertex numbers would be hidden.
Input:
r=10;c=7;
result=flow2D[{r,c},3]

Actually, the result contains multiple objects. The first object, result[[1]], is the 2D graph shown here.

The 3 dimensional pipes are Tube's  (3D lines) plotted in 3 space.  The coordinates computed based on the vertices of the 2D graph along a 3rd coordinate that was randomly generated (This allows the pipes to assume different positions along y each time the code is run.)
The axes are displayed to help the reader convince herself that the 3D rendering is indeed based on the 2D rendering.
The 3D input of interest here is:
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}]

The number or rows, columns and entry column are taken from the 2D code.  They do not have to be re-entered.

2D Code
In the coming days I will document and tidy up the code for 2D and 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]

3D Code and results
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}]

If you can render the pathway, this will surely win hands-down!  Can you alter the colour of the pipes, based on whether the vertices are "touched"?

I think I can alter the pipe color to show the path taken. I'm not sure how to decide which connecting (horizontal) pipes should be "taken" and which should be avoided. At present all connecting pipes are "open".

Pick one randomly, or make it definable like I did in mine?  Still going to win -- the output is too pretty not to!!

Right now, you seem to take several horizontal pipes on the same level. I believe this violates the Basic Rule #1.

Timwi, Thanks. That oversight has been corrected.

C#
(via LINQPad, in "C# Program" mode; )
Going to have to apply Equitable Stroke Control, as far as any golfing might go, but this is my approach in C# (well, LINQPad, but who wants all the boilerplate that goes into making a full C# app work?).
Grid definitions are variable, with a number of vertical pipes and height of overall structure, and are repeatably-random by passing a seed (see the PipeGrid constructor).
In the absence of a definitive answer as to which way the object would flow if either direction was possible, I have allowed you to specify a behaviour from a number of options (see SolveBehavior enumeration / PipeSolver constructor).
Starting vertical is definable (see PipeSolver.Solve).
I have assumed that the horizontal pipes are always between two adjacent vertical pipes, i.e. no horizontal can bypass a horizontal pipe.
///Entry point
void Main()
{
    var grid = new PipeGrid(vertical:10, height:10, seed:5);
    var solver = new PipeSolver(grid, SolveBehavior.FlipFlop);
    solver.Solve(start:2);
}

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

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

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

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

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

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

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

///Provides the logic for solving a <see cref="PipeGrid" /></summmary>
class PipeSolver
{
    ///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
    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;

    ///Simulate the dropping of an object to run through the grid, at the top of a
    ///given <paramref name="start" /> vertical pipe
    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);
    }

    ///Internal method for drawing a given frame
    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);
    }

    ///Internal method for rendering a frame as a bitmap
    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");
        }
    }
}

///Represents a configuration of pipes
class PipeGrid
{
    ///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" />.
    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]; } }

    ///Renders the grid to the LINQPad results pane, for inspection
    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;
    }

    ///Render the grid as a bitmap image
    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);
                }
            }
        }
    }

    ///Creates a <see cref="PipeGrid" /> with horizontal pipes at all possible positions
    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;
    }
}

///Store tile sprites, to be used in the graphical rendering of the result
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; }

    ///Create a sprite from the byte data
    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;
    }

    ///Rotate an image by a number of <paramref name="degrees" /> around the centre
    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;
    }

    ///Flip an image about its centre
    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
}

Update:
Fearing my plain old text output might be a little drab for this popularity context, I offer up an extended version that also draws the path taken as an image.  I've modelled it as car, driving through a horrible road network, trying to get to the bottom, but with the world's-worst GPS that forces you to make a turn at every junction.
As a bonus, this also makes it clearer to see the 'turns'.
Enjoy -- vroom vroom!!
Example results:
(verticals: 10, height: 10, random seed:5, start pipe: 2, solve behaviour: FlipFlop})

C#
Fun times!  :-)
This code ensures there is at least some straight pipe at either end of each pipe.  It also ensures there are no ambiguous turns.
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];
        }
    }
}

Output:

Damn, I also had the idea of using the box-drawing characters, you beat me to it :)

Also, I like the idea of making sure not to generate pipes with ambiguous turns. I didn’t think of that!

Funciton
As if Funciton wasn’t already among the most pointless languages in the world, this is certainly the most useless program I’ve written in it so far.
Since this looks ugly in StackExchange due to the extra line spacing, consider running the following in your browser’s JavaScript console to fix that:

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

Since Funciton doesn’t have a random number generator, I decided to let you enter the pipe pattern. Since the pattern encoding is unobvious, banging the digit keys on your keyboard randomly is as good as a random number generator.
The input is expected to be three decimal numbers separated by spaces. The first number is the width (one less than the number of vertical pipes); the second is the index of the starting pipe, and the last is any number that encodes the horizontal pipe pattern; you can make it as large as you want. If the width is negative or the pipe index is out of range, the output is Impossiburu.
The program automatically ensures that there are never two horizontal pipes next to each other, which could cause ambiguous turns.
                            ┌───╖
               ┌────────────┤ ♯ ╟───────────┬───────────────┐
     ╔════╗  ┌─┴─╖  ┌────╖  ╘═══╝  ╔═══╗  ┌─┴─╖  ╔════╗     │
     ║ 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 ╟──────┘            └──────┬──────┘
 │ ╚════════════════╝                          │
 └─────────────────────────────────────────────┘

Explanation

The main program finds the first two spaces and splits out the numbers. It runs the third (the pipe pattern) through ░ and then calls ▒ with the result, which returns the output as well as the number of turns taken. It then adds the text n turns were taken to get to the end., where n is the number of turns calculated by ▒.
░ takes a number and inserts a 0-bit after every 1-bit, thus ensuring there are never two horizontal pipes in succession.
▒ generates the output by successively calling ▓ and then shifting out the right number of bits from the pipe pattern until it is zero. It also increments or decrements the “current pipe” appropriately.
▓ generates one line of the output. In each iteration, it shifts out one bit from the pipe pattern and then decides whether to output │ (+ 4 spaces), ║ (+ 4 spaces), ├────┤, ╔════╝ or ╚════╗; in the latter three cases, it removes the first character from the next iteration. The last iteration generates │\r\n or ║\r\n as appropriate.

Example output
Input:

6 3 73497529294753

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

10 turns were taken to get to the end.

Input:

3 0 65536

Output:
║    │    │    │
║    │    │    │
║    │    ├────┤

0 turns were taken to get to the end.

Input:

3 7 75203587360867 (pipe index out of range)

Output:
Impossiburu.

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

line 1: setup and find first |
line 2: swap out replacement : or =
line 3: move x/y to next pos (d=0=down,d=-1=left,d=1=right)
line 4: find next direction
line 5: print out results

Here it is formatted:
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 from the sample:
V
:       |       |-------|
:=======:       |-------|
|       :=======:       |
|-------|-------:=======:
|       |-------|       :
|-------|       :=======:
|-------|       :=======:
|       |-------|       :
                        ^10

Other output:
V
:       |       |-------|       |
:=======:       |-------|       |
|       :=======:       |-------|
|-------|-------:=======:       |
|       |-------|       :=======:
|-------|       |-------|       :
|-------|       |-------|       :
|       |-------|       :=======:
|       |-------|       :       |
|       |       :=======:       |
|-------|       :       |       |
|       :=======:       |       |
|       :       |-------|       |
|       :=======:       |       |
                ^16

(I know I did code-golf instead of popularity, but that's just my style)

JavaScript
The HTML canvas listens for click events and finds the nearest row of pipes and uses that for the starting point. Output is drawn on the canvas and there is also a textarea containing the ASCII output defined by the OP.
The algorithm will ensure that there are never two connecting horizontal pipes. Other than that restriction, a probability is defined in the initial variables and that is used to randomly determine whether a horizontal pipe should occur or not.
JSFIDDLE

Click on a row to show the path

<canvas id="canvas" width="450" height="350"></canvas>
<textarea id="output" style="width:100%; height:24em;"></textarea>

Output


text:
Build a numerical library without using any primitive data type
The task is to build a numerical library for working with arbitrarily large integers that supports the following operations:

addition
subtraction
multiplication
division
modulo operation

However, the library must not use any primitive data types or arrays, neither directly nor indirectly (including booleans). For example, if you use Java, you can neither use AtomicInteger (because it uses bool internally) nor HashMap (because it uses arrays internally). You'll need to create your own data structures, without using any primitive data types, to represent numbers. (Inherited methods such as Java's hashCode don't count, as long as you don't use them in any way.) The only exception is local use of booleans in order to use conditionals (see the clarification points below).
There is only one exception: In order to make your library actually testable, provide two functions to convert from and to native integer representation. For example:
int toNative(MyNum n) { ... }
MyNum fromNative(int n) { ... }

This is the only part of your code that can use built-in data types, and it must not do anything except the conversion.
If in doubt, please ask.
Criteria: The code should be elegant, readable, concise (but no code-golf, readability is more important than code size),  well documented, and if possible, asymptotically efficient (provide and justify your functions asymptotic time and space complexity). The most up-voted answer in 10 days wins.

Update: Since the puzzle seemed impossible to many people, let me give a hint:
public abstract class Nat {
    public static Nat fromInt(int n) {
        Nat r = new Zero();
        for(int i = 0; i < n; i++)
            r = new Succ(r);
        return r;
    }

    public static int toInt(Nat n) {
        int i = 0;
        for(Nat m = n; m instanceof Succ; m = ((Succ)m).n)
            i++;
        return i;
    }
}

final class Zero extends Nat {
}

final class Succ extends Nat {
    public final Nat n;

    public Succ(Nat n) {
        this.n = n;
    }
}

This allows to represent any natural number without primitive types, even though not very efficiently.
To further clarify:

Pointers are allowed to work with data structures as long as you use them only as opaque references. In particular, you may not use any pointer arithmetic.
NULL/nulls are allowed.
If the language of your choice requires it, you can use booleans (or a similar data type) for conditionals, but only locally in functions/methods, not as fields in your data structures, and you can't use anything beyond boolean operations. Bonus if you manage it without booleans (many languages are capable of that, such as those that use pattern matching).
Higher-level languages are better suited for the puzzle.

If we can't use primitive data types and we can't use complex data types because they use primitive types, what can we use?  We obviously have to store data somehow.

Are we allowed to check if an object is null?

I must be missing something obvious. Humour me...  can you please show a (partial) example of how to "create your own data structures, without using any primitive data types"?

Do you count pointers / references as primitive data types? The Wiki link you provide mentions them but I'm struggling to think of a way to produce a solution in most languages without them.

Too bad it's closed, I had come up with something... A Terrible Secret! https://gist.github.com/anonymous/8794989 Unlimited precision even!

Do not trust the Shover robot—he is malfunctioning. We are here to protect you.

@Tobia Do not trust the Pusher robot— he is malfunctioning. We are here to protect you.

@LegoStormtroopr By the way, I could create a node class with a pointer to a nullable element of the same class and then use Church numerals and lambda calculus to solve that. So this indeed is solvable.

@Victor The wikipedia page the OP linked to includes pointers as a primative data type - which nullifies Tobias' answer, and makes yours impossible too.

In my opinion @Tobia's solution is invalid. In his code there is an expression n == 0, and last time I checked 0 is an integer.

I don't think a Turing Machine has anything you would call "primitive types". So this is certainly solvable.

@ace That was in the FromNative method, which the OP explained that it should be there to make the entry testable. The relevant method to the problem is the Add method.

@Victor oh you're right, sorry I misread that.

@gnibbler, a Turing Machine has a tape of cells, each containing a symbol from a finite alphabet.  By a reasonable definition, IMO, that alphabet is the primitive type of a Turing Machine and those symbols are the values for the primitive type.

@PetrPudlák Could you please edit your question to fix all those problems and complains? Maybe relax the rules a bit so let's say "you might use any data type, but only in an opaque way". This implies for example that I can use java Strings as long as I don't access stuff inside the String (like substrings or individual chars). Since this is a popularity contest, the rules can be a bit loose. By the way, are things like Turing-machine-like languages (like brainfuck) allowed?

@Victor Updated, I tried to clarify the most important points and I added an example showing one possible representation.

Eric Lippert did this on his blog in C# in 13 parts http://ericlippert.com/2013/11/12/math-from-scratch-part-thirteen-multiplicative-inverses/

It would seem inappropriate to just copy him, but I'm tempted. I've got a couple of "optimizations" in my own version.

Here's where he starts writing code: http://ericlippert.com/2013/09/19/math-from-scratch-part-two/

Coming from a heavy c background the notion that pointers are excluded from "primitive data types" seems...dumb. And indeed the Wikipedia article you link specifically lists them as such. Likewise it lists both first class function and closures meaning that if we take that article as definitive then most of the suggested solutions are out. I can see what your trying to get at...Church style schemes and such, but this spec is a real mess.

@dmckee My background are higher level languages like Scala or Haskell, where the distinction is very clear.

Haskell
Haskell is pretty good at defining obvious things from scratch.
Almost all definitions are simple translations of math axioms.
Doesn't support negative numbers, behaves badly on errors (e.g. 1-2 or 1/0).
data MyNum = Zero | S MyNum

toNative :: MyNum -> Integer
toNative Zero = 0
toNative (S n) = (toNative n) + 1
fromNative :: Integer -> MyNum
fromNative 0 = Zero
fromNative n = S $ fromNative $ n-1

-- numIfGE a b c = c if a>=b else 0
numIfGE _ Zero n = n
numIfGE Zero _ n = Zero
numIfGE (S a) (S b) n = numIfGE a b n

instance Num MyNum where
    a + Zero = a
    a + (S b) = S (a + b)

    a - Zero = a
    (S a) - (S b) = a - b

    a * Zero = Zero
    a * (S b) = a + (a*b)

a `divi` b = numIfGE a b (S $ (a - b) `divi` b)
a `modu` b = a - ((a `divi` b) * b)

Python 3
The code is a basic lambda calculus implementation I did some time ago when learning about calculus using an online resource which I cannot find anymore (can anybody give me a hint).
It works fine for positive numbers - extension to negatives should be possible.
# booleans and if
TRUE    = lambda x: lambda y: x
FALSE   = lambda x: lambda y: y
IF      = lambda x: x

# numerals
ZERO    = lambda f: lambda x: x
IS_ZERO = lambda n: n(lambda x: FALSE)(TRUE)

INC     = lambda n: lambda f: lambda x: f(n(f)(x))
DEC     = lambda n: lambda f: lambda x: n(lambda g: lambda h: h(g(f)))(lambda y: x)(lambda y: y)

# combinators
Y       = lambda f: (lambda x: f(x(x)))(lambda x: f(x(x)))
Z       = lambda f: (lambda x: f(lambda y: x(x)(y)))(lambda x: f(lambda y: x(x)(y)))

# arithmetic
ADD     = lambda m: lambda n: n(INC)(m)
SUB     = lambda m: lambda n: n(DEC)(m)
MUL     = lambda m: lambda n: n(ADD(n))(ZERO)

IS_LEQ  = lambda m: lambda n: IS_ZERO(SUB(m)(n))
MOD     = Z(lambda f: lambda m: lambda n: IF(IS_LEQ(n)(m))(lambda x: f(SUB(m)(n))(n)(x))(m))
DIV     = Z(lambda f: lambda m: lambda n: IF(IS_LEQ(n)(m))(lambda x: INC(f(SUB(m)(n))(n))(x))(ZERO))

# conversion function
def toNative(n) : return n(lambda x: x+1)(0)
def fromNative(n) : return ZERO if n==0 else INC(fromNative(n-1))

# Test code
n13 = fromNative(13)
n5 = fromNative(5)

print("13/5 = ",toNative(DIV(n13)(n5)))
print("13%5 = ",toNative(MOD(n13)(n5)))

Haskell
unlimited range, negative and positive values, no booleans except in native code
O(n) addition, subtraction (asymptotically optimal)
O(n^2) multiplication,  division/modulo  (no, I'm not going to implement the Karatsuba algorithm)
The representation is: a recursive type representing linked list of bits of the two's complement representation in the little endian order, terminated by either "all zeroes" or "all ones". Haskell has no trouble storing infinite lists in memory, but comparing their last elements is quite... hard.
show (producing a display form) runs backwards because prepending to a string is much faster than appending to it.
Addition, successor and predecessor are very simple. Carry is performed using the successor function. Note I didn't have to define subtraction. Haskell defines it for all Numbers as a - b = a + negate b).
Multiplication is the classical binary lattice multiplication, with the sum step being performed bottom-up.
Division is the classical binary long division (trial subtraction).
Haskell defines two sets of integer division operations. quotient/remainder round the quotient towards zero, while division/modulo round the quotient towards negative infinity. It defines divMod in terms of quotRem by subtracting one from the quotient (and the divisor from the modulus) if the sign of the remainder is opposite the sign of the divisor [source]. This is also the only place where the standard implementation uses native booleans internally (pattern matching probably does as well, but by the word of the author, this doeesn't count).
data LinkedInteger = Zero | MOne | And0 LinkedInteger | And1 LinkedInteger

toNative Zero = 0
toNative MOne = -1
toNative (And0 x) = 2 * toNative x
toNative (And1 x) = 2 * toNative x + 1

instance Show LinkedInteger where
   show = reverse.rshow
     where rshow  Zero    = "0.. "
           rshow  MOne    = "1.. "
           rshow (And0 x) = '0':(rshow x)
           rshow (And1 x) = '1':(rshow x)

fromNative   0  = Zero
fromNative (-1) = MOne
fromNative   x  | odd  x = And1 $ fromNative(x`div`2)
                | even x = And0 $ fromNative(x`div`2)

instance Enum LinkedInteger where
    succ Zero    = And1 Zero
    succ MOne    = Zero
    succ(And0 x) = And1 x
    succ(And1 x) = And0(succ x)

    pred Zero    = MOne
    pred MOne    = And0 MOne
    pred(And0 x) = And1(pred x)
    pred(And1 x) = And0 x

    toEnum = fromNative
    fromEnum = toNative

instance Num LinkedInteger where
    -- ensures sublinear performance in most cases
    Zero + x = x
    x + Zero = x
    MOne + x = pred x
    x + MOne = pred x
    And0 x + And0 y = And0 (x+y)
    And0 x + And1 y = And1 (x+y)
    And1 x + And0 y = And1 (x+y)
    And1 x + And1 y = And0 $ succ (x+y)

    negate  Zero    = Zero
    negate  MOne    = And1 Zero
    negate (And0 x) = And0 (negate x)
    negate (And1 x) = And1 $ pred (negate x)

    Zero   * y = Zero
    MOne   * y = -y
    And0 x * y =     And0 (x*y)
    And1 x * y = y + And0 (x*y)

    fromInteger = fromNative

    signum x = signum' (compare x Zero)
      where signum' LT = MOne
            signum' EQ = Zero
            signum' GT = And1 Zero

    abs x = ifNeg x (-x) x

mappend EQ y = y
mappend x  _ = x

instance Eq LinkedInteger where x == y = (compare x y) == EQ

instance Ord LinkedInteger where
    compare Zero Zero = EQ
    compare MOne MOne = EQ
    compare MOne Zero = LT
    compare Zero MOne = GT
    compare (And0 x) (And0 y) = compare x y
    compare (And1 x) (And1 y) = compare x y
    compare (And0 x) (And1 y) = mappend (compare x y) LT
    compare (And1 x) (And0 y) = mappend (compare x y) GT
    compare Zero x = compare (And0 Zero) x
    compare MOne x = compare (And1 MOne) x
    compare x Zero = compare x (And0 Zero)
    compare x MOne = compare x (And1 MOne)

ifLt w x y z = ifNeg' (compare w x) y z
  where ifNeg' LT y _ = y
        ifNeg'  _ _ z = z

ifNeg x = ifLt x 0

half  Zero    = Zero
half  MOne    = MOne
half (And0 x) = x
half (And1 x) = x

andBitFrom  Zero    = And0
andBitFrom  MOne    = And1
andBitFrom (And0 x) = And0
andBitFrom (And1 x) = And1

instance Real LinkedInteger where toRational = toNative

instance Integral LinkedInteger where
  quotRem _ Zero = undefined
  quotRem x y = (ifNeg x
                  (ifNeg y
                    (let n (q,r) = ( q, -r) in n(quotRem'(-x)(-y)))
                    (let n (q,r) = (-q, -r) in n(quotRem'(-x)  y )))
                  (ifNeg y
                    (let n (q,r) = (-q,  r) in n(quotRem'  x (-y)))
                                                (quotRem'  x   y ) ))

    where quotRem' Zero _ = (Zero, Zero)
          quotRem'    x y =
            let (qHalf, rHalf) = quotRem' (half x) y
                subdiv  = andBitFrom(x) rHalf
                subdiv' = subdiv - y
            in ifNeg subdiv' (And0 qHalf, subdiv) (And1 qHalf, subdiv')

  toInteger = toNative

perl
Here's my take, in perl. I thought this was a code-golfing post at first, so you may see some vestiges of that in the code. Anyway, I went to some effort to make the code as "tight" as possible, probably a little tighter than I otherwise would have. But I didn't go too far over the deep-end. Also note that I left in the prototypes on public functions (despite them being considered bad practice), because it made the test cases much less tedious to code up.
As for time and space, I left notation of the runtimes in the source at the heading of each subroutine, but I didn't take the time to prove them or anything, just to convince myself. Space is the more serious consideration of course - this implementation uses O(n) space to store an integer n, which is pretty bad. I wasn't sure exactly what I could get away with in terms of chars or encoding counts in inheritance patterns and such so I figured I'd do it the "canonical" (if slower) way. This has other effects too, for example, it takes O(n+m) time to ask if n equals m.
All that said, here's nat.pm, a complete (I believe) implementation in perl:
#!/usr/bin/perl

use strict;
use warnings;

package nat;

sub prev() { $_[0]->{prev}; }
sub next() { $_[0]->{next}; }

sub zero() { bless { prev => undef, next => undef } }

sub inc($) {
  bless defined $_[0]->next ?
        { prev => undef, next => $_[0]->next->next } :
        { prev => $_[0], next => undef }
}
sub dec($) {
  bless defined $_[0]->prev ?
        { prev => $_[0]->prev->prev, next => undef } :
        { prev => undef, next => $_[0] }
}

sub is_zero($)     { !defined $_[0]->prev && !defined $_[0]->next };
sub is_negative($) { defined $_[0]->next };
sub is_positive($) { defined $_[0]->prev };

sub from_native($) {
  my ($n) = @_;
  my $x = zero;
  $n--, $x = inc($x) while $n > 0;
  $n++, $x = dec($x) while $n < 0;
  return $x;
}
sub to_native($) {
  my ($x) = @_;
  my $n = 0;
  --$n, $x = $x->next while defined $x->next;
  ++$n, $x = $x->prev while defined $x->prev;
  return $n;
}

# returns 1 if x has greater magnitude than y
# returns -1 if x has lesser magnitude than y
# returns 0 if x and y have the same magnitude
sub _equal_depth { # O(x+y)
  my ($x, $y, $c) = @_;
  while( defined $x->{$c} ) {
    return 1 if !defined $y->{$c};
    $x = $x->{$c};
    $y = $y->{$c};
  }
  return defined $y->{$c} ? -1 : 0;
}

# x<y => -1, x>y => 1, x==y => 0
sub spaceship($$) { # O(x+y)
  my ($x, $y) = @_;
  if( is_positive( $x ) ) {
    return is_positive( $y ) ? _equal_depth($x, $y, 'prev') : 1;
  } elsif( is_negative( $x ) ) {
    return is_negative( $y ) ? _equal_depth($y, $x, 'next') : -1;
  } else {
    return is_zero( $y ) ? 0 : is_positive( $y ) ? -1 : 1;
  }
}

# the below are all O(x+y) as a result of spaceship()
#sub is_lt($$)  { my ($x, $y) = @_; return spaceship($x, $y) == -1 }
#sub is_gt($$)  { my ($x, $y) = @_; return spaceship($x, $y) == 1 }
#sub is_le($$)  { my ($x, $y) = @_; return spaceship($x, $y) != 1 }
#sub is_ge($$)  { my ($x, $y) = @_; return spaceship($x, $y) != -1 }
sub equals($$) { my ($x, $y) = @_; return spaceship($x, $y) == 0 }

sub clone($) { # O(x)
  my ($x) = @_;
  my $r = zero;
  if( is_positive($x) ) {
    $x = $x->prev, $r = inc($r)  while  defined $x->prev;
  } elsif( is_negative($x) ) {
    $x = $x->next, $r = dec($r)  while  defined $x->next;
  }
  return $r;
}

sub _add_sub { # O(x+y)
  my $is_sub = pop;
  my ($x, $y) = map { clone($_) } @_;
  while( 1 ) {
    if( is_positive( $y ) ) {
      $y = dec( $y );
      $x = $is_sub ? dec( $x ) : inc( $x );
    } elsif( is_negative( $y ) ) {
      $y = inc( $y );
      $x = $is_sub ? inc( $x ) : dec( $x );
    } else {
      last;
    }
  }
  return $x;
}

sub add($$) { # O(x+y)
  return _add_sub(@_, 0);
}

sub minus($$) { # O(x+y)
  return _add_sub(@_, 1);
}

sub negate($) {
  my ($x) = @_;
  return minus( zero, $x );
}

sub magnitude($) {
  my ($x) = @_;
  return is_negative($x) ? negate($x) : $x;
}

sub mult($$) { # O(x*y)
  my ($x, $y) = map { clone($_) } @_;
  my $r = zero;
  $x = negate($x), $y = negate($y)  if  is_negative($y);
  while( !is_zero( $y ) ) {
    $r = add($r, $x);
    $y = dec( $y );
  }
  return $r;
}

sub _div { # O(x*y)
  my $is_mod = pop;
  my ($x, $y) = map { clone($_) } @_;
  die "tried to divide by zero" if is_zero( $y );
  if($is_mod && (is_negative($x) || is_negative($y))) {
    if('nat.t' ne (caller(1))[1]) {
      warn "warning: modular arithmetic with negative operands not well defined!\n";
    }
  }
  my $is_neg = ( is_negative($x) xor is_negative($y) );
  $x = magnitude($x);
  $y = magnitude($y);
  # count up from zero by one until we get to $x
  # whenever we get to a multiple, increment the result by one and zero the remainder
  my $q = zero;
  my $r = zero;
  while( !is_zero( $x ) ) {
    $r = inc( $r );
    if( equals( $y, $r ) ) {
      $r = zero;
      $q = inc( $q );
    }
    $x = dec( $x );
  }
  $r = negate($r), $q = negate($q)  if  $is_neg;
  return $is_mod ? $r : $q;
}

sub divi($$) {
  return _div(@_, 0);
}
sub mod($$) {
  return _div(@_, 1);
}

# export
no strict 'refs';
*{scalar(caller)."::$_"} = \&$_ for grep { !/^[A-Z_]/ } keys %nat::;

1;

... and here is the test script I used when building it:
#!/usr/bin/perl

use strict;
use warnings;

use Test::More;

use nat;

my $x;

my $zero = zero;
ok( $zero );
ok( 0 == to_native $zero );
ok( is_zero $zero );
ok( !is_negative $zero );
ok( !is_positive $zero );

my $pos1 = inc $zero;
ok( $pos1 );
ok( 1 == to_native $pos1 );
ok( 0 == to_native dec $pos1 );
ok( !is_zero $pos1 );
ok( !is_negative $pos1 );
ok( is_positive $pos1 );

my $neg1 = dec $zero;
ok( $neg1 );
ok( -1 == to_native $neg1 );
ok(  0 == to_native inc $neg1 );
ok( !is_zero $neg1 );
ok( is_negative $neg1 );
ok( !is_positive $neg1 );

my $pos2 = inc $pos1;
ok( $pos2 );
ok( 2 == to_native $pos2 );
ok( 3 == to_native inc $pos2 );
ok( 1 == to_native dec $pos2 );
ok( !is_zero $pos2 );
ok( !is_negative $pos2 );
ok( is_positive $pos2 );

my $neg3 = dec dec $neg1;
ok( $neg3 );
ok( -3 == to_native $neg3 );
ok( -2 == to_native inc $neg3 );
ok( -4 == to_native dec $neg3 );
ok( !is_zero $neg3 );
ok( is_negative $neg3 );
ok( !is_positive $neg3 );

# make sure inc/dec can go "across" zero
ok(  1 == to_native inc inc inc dec dec zero );
ok( -1 == to_native dec dec dec inc inc zero );

ok( equals $zero, $zero );
ok( !equals $zero, $pos1 );
ok( !equals $zero, $neg1 );
ok( !equals $pos1, $neg1 );

ok( !equals $pos1, $pos2 );
ok( equals $pos1, $pos1 );
ok( equals $pos2, $pos2 );

ok( !equals $neg1, $neg3 );
ok( equals $neg1, $neg1 );
ok( equals $neg3, $neg3 );

ok(  0 == spaceship $neg3, $neg3 );
ok(  0 == spaceship $neg3, $neg3 );
ok( -1 == spaceship $neg3, $neg1 );
ok(  1 == spaceship $neg1, $neg3 );
ok( -1 == spaceship $neg3, $zero );
ok(  1 == spaceship $zero, $neg3 );
ok( -1 == spaceship $neg3, $pos1 );
ok(  1 == spaceship $pos1, $neg3 );
ok( -1 == spaceship $neg3, $pos2 );
ok(  1 == spaceship $pos2, $neg3 );

ok(  0 == spaceship $neg1, $neg1 );
ok(  0 == spaceship $neg1, $neg1 );
ok( -1 == spaceship $neg1, $zero );
ok(  1 == spaceship $zero, $neg1 );
ok( -1 == spaceship $neg1, $pos1 );
ok(  1 == spaceship $pos1, $neg1 );
ok( -1 == spaceship $neg1, $pos2 );
ok(  1 == spaceship $pos2, $neg1 );

ok(  0 == spaceship $zero, $zero );
ok(  0 == spaceship $zero, $zero );
ok( -1 == spaceship $zero, $pos1 );
ok(  1 == spaceship $pos1, $zero );
ok( -1 == spaceship $zero, $pos2 );
ok(  1 == spaceship $pos2, $zero );

ok(  0 == spaceship $pos1, $pos1 );
ok(  0 == spaceship $pos1, $pos1 );
ok( -1 == spaceship $pos1, $pos2 );
ok(  1 == spaceship $pos2, $pos1 );

ok(  0 == spaceship $pos2, $pos2 );
ok(  0 == spaceship $pos2, $pos2 );

#ok( is_lt $neg3, $neg1 );
#ok( !is_lt $neg3, $neg3 );
#ok( is_le $neg3, $neg1 );
#ok( is_le $neg1, $neg1 );
#ok( !is_gt $neg3, $neg1 );
#ok( !is_gt $neg3, $neg3 );
#ok( !is_ge $neg3, $neg1 );
#ok( is_ge $neg1, $neg1 );

ok( equals( inc inc inc inc inc inc zero, from_native 6 ) );
ok( equals( dec dec dec dec dec dec dec zero, from_native -7 ) );

$x = clone $pos2;
ok( equals $pos2, $x );
ok( 2 == to_native $x );
$x = clone $neg3;
ok( equals $neg3, $x );
ok( -3 == to_native $x );

ok( 2 == to_native add $zero, $pos2 );
ok( 1 == to_native add $zero, $pos1 );
ok( 1 == to_native add $pos1, $zero );
ok( 2 == to_native add $pos1, $pos1 );
ok( 3 == to_native add $pos1, $pos2 );
ok( 3 == to_native add $pos2, $pos1 );
ok( 4 == to_native add $pos2, $pos2 );

ok( -3 == to_native add $zero, $neg3 );
ok( -1 == to_native add $zero, $neg1 );
ok( -1 == to_native add $neg1, $zero );
ok( -2 == to_native add $neg1, $neg1 );
ok( -4 == to_native add $neg1, $neg3 );
ok( -4 == to_native add $neg3, $neg1 );
ok( -6 == to_native add $neg3, $neg3 );

ok( -2 == to_native add $neg3, $pos1 );
ok( -1 == to_native add $neg3, $pos2 );
ok(  0 == to_native add $neg1, $pos1 );
ok(  1 == to_native add $neg1, $pos2 );

ok( -2 == to_native minus $neg3, $neg1 );
ok(  2 == to_native minus $neg1, $neg3 );
ok( -3 == to_native minus $neg3, $zero );
ok(  3 == to_native minus $zero, $neg3 );
ok( -4 == to_native minus $neg3, $pos1 );
ok(  4 == to_native minus $pos1, $neg3 );
ok( -5 == to_native minus $neg3, $pos2 );
ok(  5 == to_native minus $pos2, $neg3 );

ok( -1 == to_native minus $neg1, $zero );
ok(  1 == to_native minus $zero, $neg1 );
ok( -2 == to_native minus $neg1, $pos1 );
ok(  2 == to_native minus $pos1, $neg1 );
ok( -3 == to_native minus $neg1, $pos2 );
ok(  3 == to_native minus $pos2, $neg1 );

ok( -1 == to_native minus $zero, $pos1 );
ok(  1 == to_native minus $pos1, $zero );
ok( -2 == to_native minus $zero, $pos2 );
ok(  2 == to_native minus $pos2, $zero );

ok( -1 == to_native minus $pos1, $pos2 );
ok(  1 == to_native minus $pos2, $pos1 );

ok( equals $pos1, negate($neg1) );
ok( equals $neg1, negate($pos1) );
ok(  3 == to_native negate $neg3 );
ok(  1 == to_native negate $neg1 );
ok(  0 == to_native negate $zero );
ok( -1 == to_native negate $pos1 );
ok( -2 == to_native negate $pos2 );

ok( equals magnitude($pos1), magnitude($neg1) );
ok( equals magnitude($neg1), magnitude($pos1) );
ok( equals magnitude($pos1), $pos1 );
ok( equals magnitude($neg1), $pos1 );
ok( 3 == to_native magnitude $neg3 );
ok( 1 == to_native magnitude $neg1 );
ok( 0 == to_native magnitude $zero );
ok( 1 == to_native magnitude $pos1 );
ok( 2 == to_native magnitude $pos2 );

ok(  3 == to_native mult $neg3, $neg1 );
ok(  0 == to_native mult $neg3, $zero );
ok( -3 == to_native mult $neg3, $pos1 );
ok( -6 == to_native mult $neg3, $pos2 );

ok(  1 == to_native mult $neg1, $neg1 );
ok(  0 == to_native mult $neg1, $zero );
ok( -1 == to_native mult $neg1, $pos1 );
ok( -2 == to_native mult $neg1, $pos2 );

ok(  0 == to_native mult $zero, $zero );
ok(  0 == to_native mult $zero, $pos1 );
ok(  0 == to_native mult $zero, $pos2 );

ok(  1 == to_native mult $pos1, $pos1 );
ok(  2 == to_native mult $pos1, $pos2 );

ok(  4 == to_native mult $pos2, $pos2 );

ok(  3 == to_native divi $neg3, $neg1 );
ok(  0 == to_native divi $neg1, $neg3 );
eval { to_native divi $neg3, $zero }; ok($@);
ok(  0 == to_native divi $zero, $neg3 );
ok( -3 == to_native divi $neg3, $pos1 );
ok(  0 == to_native divi $pos1, $neg3 );
ok( -1 == to_native divi $neg3, $pos2 );
ok(  0 == to_native divi $pos2, $neg3 );

eval { to_native divi $neg1, $zero }; ok($@);
ok(  0 == to_native divi $zero, $neg1 );
ok( -1 == to_native divi $neg1, $pos1 );
ok( -1 == to_native divi $pos1, $neg1 );
ok(  0 == to_native divi $neg1, $pos2 );
ok( -2 == to_native divi $pos2, $neg1 );

ok(  0 == to_native divi $zero, $pos1 );
eval { to_native divi $pos1, $zero }; ok($@);
ok(  0 == to_native divi $zero, $pos2 );
eval { to_native divi $pos2, $zero }; ok($@);

ok(  0 == to_native divi $pos1, $pos2 );
ok(  2 == to_native divi $pos2, $pos1 );

ok( 0 == to_native divi from_native(0), from_native(3) );
ok( 0 == to_native mod  from_native(0), from_native(3) );
ok( 0 == to_native divi from_native(1), from_native(3) );
ok( 1 == to_native mod  from_native(1), from_native(3) );
ok( 0 == to_native divi from_native(2), from_native(3) );
ok( 2 == to_native mod  from_native(2), from_native(3) );
ok( 1 == to_native divi from_native(3), from_native(3) );
ok( 0 == to_native mod  from_native(3), from_native(3) );
ok( 1 == to_native divi from_native(4), from_native(3) );
ok( 1 == to_native mod  from_native(4), from_native(3) );
ok( 1 == to_native divi from_native(5), from_native(3) );
ok( 2 == to_native mod  from_native(5), from_native(3) );
ok( 2 == to_native divi from_native(6), from_native(3) );
ok( 0 == to_native mod  from_native(6), from_native(3) );
ok( 2 == to_native divi from_native(7), from_native(3) );
ok( 1 == to_native mod  from_native(7), from_native(3) );

ok(  0 == to_native divi from_native(-1), from_native(3) );
ok( -1 == to_native mod  from_native(-1), from_native(3) );
ok(  0 == to_native divi from_native(-2), from_native(3) );
ok( -2 == to_native mod  from_native(-2), from_native(3) );
ok( -1 == to_native divi from_native(-3), from_native(3) );
ok(  0 == to_native mod  from_native(-3), from_native(3) );
ok( -1 == to_native divi from_native(-4), from_native(3) );
ok( -1 == to_native mod  from_native(-4), from_native(3) );

done_testing();

It depends on the tags of a question. If  it has [tag:code-golf], then it's about the code size. If it has [tag:code-challenge] then there is another criterion, and if it has [tag:popularity-contest], the most up-voted question wins (usually there are some less precise criteria given as well).

Ahh, thanks for the clarifiation, Petr!

Go
Here's my partial submission in Go. Handles conversion to/from uint and sum to arbitrary precision.
The representation is binary, using a struct field (Unf) to store 1 bit of information (whether the pointer is nil or not) and another field (Chooie) to chain the next bit (more significant) which will chain another one if needed, and so on.
The performance is logarithmic with respect to the actual integers, just like in regular arbitrary precision libraries, except that the constant factors are hugely different.
package TerribleSecret

type Unf struct {
    Pak, Chooie *Unf
}

func FromNative(n uint) (u *Unf) {
    u = new(Unf)
    if n == 0 {
        return
    }
    if n&1 != 0 {
        u.Pak = u
    }
    u.Chooie = FromNative(n >> 1)
    return
}

func (u *Unf) ToNative() (n uint) {
    if u == nil {
        return
    }
    n = u.Chooie.ToNative()
    n <<= 1
    if u.Pak != nil {
        n |= 1
    }
    return
}

func (u *Unf) Add(n *Unf) {
    var f *Unf
    for {
        if u == nil {
            u = new(Unf)
        }
        if (n == nil || n.Pak == nil) != (f == nil) {
            if u.Pak != nil {
                u.Pak = nil
            } else {
                u.Pak = u
            }
        }
        if u.Pak != nil && (n == nil || n.Pak == nil) && f != nil {
            f = nil
        } else if u.Pak == nil && n != nil && n.Pak != nil && f == nil {
            f = n.Pak
        }
        if n != nil {
            n = n.Chooie
        }
        if n == nil && f == nil {
            break
        }
        if u.Chooie == nil {
            u.Chooie = new(Unf)
        }
        u = u.Chooie
    }
}

Unit tests
package TerribleSecret

import "testing"

func TestConversion(t *testing.T) {
    for n := uint(0); n < 10000; n++ {
        if r := FromNative(n).ToNative(); r != n {
            t.Fatalf("%d != %d", n, r)
        }
    }
}

func TestAdd(t *testing.T) {
    for x := uint(0); x < 1000; x++ {
        px := FromNative(x)
        for y := uint(0); y < 1000; y++ {
            py := FromNative(y)
            py.Add(px)
            if r := py.ToNative(); r != x+y {
                t.Fatalf("%d + %d = %d != %d", x, y, x+y, r)
            }
        }
    }
}

C#
Supports the 5 operations and negative values.
using System;

namespace NonPrimitive
{
    enum ComparisonResult
    {
        Greater, Equal, Less, Error
    }
    class MainClass
    {
        static void Main ()
        {
            Leaf l1 = Leaf.FromInt (10);
            Leaf l2 = Leaf.FromInt (-20);
            Leaf l3 = Leaf.FromInt (30);
            Leaf l4 = Leaf.FromInt (40);
            Leaf l5 = Leaf.FromInt (50);
            Leaf l6 = Leaf.FromInt (60);
            Leaf l7 = Leaf.FromInt (-20);
            Leaf l8 = Leaf.FromInt (80);
            Leaf l9 = Leaf.FromInt (20);
            Leaf l0 = Leaf.FromInt (50);
            Leaf a = l1.Add (l2);
            Leaf s = l4.Subtract (l3);
            Leaf m = l6.Multiply (l5);
            Leaf d = l8.Divide (l7);
            Leaf mo = l0.Modulo (l9);
            Console.WriteLine ("10 + -20: {0}", a.ToInt ());
            Console.WriteLine ("40 - 30: {0}", s.ToInt ());
            Console.WriteLine ("60 x 50: {0}", m.ToInt ());
            Console.WriteLine ("80 / -20: {0}", d.ToInt ());
            Console.WriteLine ("50 % 20: {0}", mo.ToInt ());
        }
    }
    class Leaf
    {
        public Leaf Parent;
        public Leaf Child;
        public Leaf Negative;
        public Leaf (Leaf parent)
        {
            Parent = parent;
        }
        public Leaf ReverseSign()
        {
            Leaf k = this.GetGrandParent ();
            if(k.Negative != null)
                k.Negative = null;
            else
                k.Negative = new Leaf(null);
            return k;
        }
        public Leaf CreateNewLeaf()
        {
            Child = new Leaf(this);
            return Child;
        }
        public Leaf AttachLeaf(Leaf leaf)
        {
            Child = leaf;
            Child.Parent = this;
            return this;
        }
        public Leaf RemoveChild()
        {
            this.Child = null;
            return this;
        }
        public Leaf GetGrandChild ()
        {
            Leaf k = this;
            while(k.Child != null)
                k = k.Child;
            return k;
        }
        public Leaf Add (Leaf a)
        {
            Leaf t = this.GetGrandChild ().AttachLeaf (a.GetGrandParent ()).GetGrandChild ().Parent.RemoveChild ().GetGrandParent ();
            if ((a.Negative == null && this.Negative == null) ||
                (a.Negative != null && this.Negative != null))
                return t.GetGrandParent ();
            return t.GetGrandParent ().ReverseSign ();
        }
        public Leaf GetGrandParent ()
        {
            Leaf k = this;
            while(k.Parent != null)
                k = k.Parent;
            return k;
        }
        public Leaf Multiply (Leaf t)
        {
            Leaf ret = new Leaf(null);
            bool sign = (t.Negative == null && this.Negative == null) ||
                        (t.Negative != null && this.Negative != null);
            t = t.GetGrandParent ();
            Leaf temp = this;
            while (t.Child != null) {
                while(true)
                {
                    if(temp.Child == null)
                        break;
                    ret = ret.CreateNewLeaf ();
                    temp = temp.Child;
                }
                temp = this.GetGrandParent ();
                t = t.Child;
            }
            if(!sign)
                return ret.GetGrandParent ().ReverseSign ();
            return ret.GetGrandParent ();
        }
        public Leaf Divide (Leaf t)
        {
            Leaf temp = this.GetGrandParent ();
            bool sign = (t.Negative == null && this.Negative == null) ||
                        (t.Negative != null && this.Negative != null);
            Leaf ret = new Leaf (null);
            while (temp.Compare (t) == ComparisonResult.Greater || temp.Compare (t) == ComparisonResult.Equal) {
                temp = temp.Subtract (t);
                ret = ret.CreateNewLeaf ();
            }
            if(!sign)
                return ret.GetGrandParent ().ReverseSign ();
            return ret.GetGrandParent ();
        }
        public ComparisonResult Compare (Leaf a)
        {
            Leaf t = this.GetGrandParent ();
            a = a.GetGrandParent ();
            while (true) {
                if(t.Child == null && a.Child != null)
                    return ComparisonResult.Less;
                if(t.Child == null && a.Child == null)
                    return ComparisonResult.Equal;
                if(t.Child != null && a.Child == null)
                    return ComparisonResult.Greater;
                t = t.Child;
                a = a.Child;
            }
        }
        public Leaf Modulo(Leaf t)
        {
            Leaf temp = this.GetGrandParent ();
            bool sign = (t.Negative == null && this.Negative == null) ||
                        (t.Negative != null && this.Negative != null);
            while (temp.Compare (t) == ComparisonResult.Greater || temp.Compare (t) == ComparisonResult.Equal) {
                temp = temp.Subtract (t);
            }
            if(!sign)
                return temp.GetGrandParent ().ReverseSign ();
            return temp.GetGrandParent ();
        }
        public Leaf Subtract (Leaf a)
        {
            Leaf temp = this.GetGrandParent();
            a = a.GetGrandParent ();
            Leaf counter = new Leaf (null);
            while (true) {
                if(a.Child != null && temp.Child != null) {
                    temp = temp.Child;
                    a = a.Child;
                } else if (a.Child != null && temp.Child == null) {
                    a = a.Child;
                    counter = counter.CreateNewLeaf ();
                } else if (temp.Child != null && a.Child == null) {
                    temp = temp.Child;
                    counter = counter.CreateNewLeaf ();
                }
                else if(temp.Child == null && a.Child == null) {
                    break;
                }
            }
            a = a.GetGrandParent ();
            if(this.Compare (a) == ComparisonResult.Less)
                return counter.ReverseSign ();
            else
                return counter.GetGrandParent ();
        }
        public int ToInt()
        {
            Leaf temp = this.GetGrandParent ();
            int ret = 0;
            while(true)
            {
                if(temp.Child != null) {
                    ret++;
                    temp = temp.Child;
                    continue;
                }
                break;
            }
            if(this.Negative != null)
                return -ret;
            return ret;
        }
        public static Leaf FromInt (int a)
        {
            Leaf ret = new Leaf (null);
            bool neg = a < 0;
            if (neg)
                a = Math.Abs (a);
            for (int i = 0; i < a; i++) {
                ret = ret.CreateNewLeaf ();
            }
            while (true) {
                if(ret.Parent != null)
                    ret = ret.Parent;
                else
                    break;
            }
            if(neg)
                return ret.ReverseSign ();
            return ret;
        }
    }
}

Also, the class is named "Leaf" because it uses a tree-like structure.

Brainfuck (incomplete)
Adding?
,>,[-<+>]

Subtracting?
,>,[-<->]

I admire the attempt to answer what could be a poorly specified or impossible question!  But you seem to be operating on an array of bytes (as you must in Brainfuck), so isn't that violating the terms of the problem?  (i.e. using both arrays and a primitive data type?)  Anyways, kudos for posting something while the rest of us debate in the comments!

@DarrenStone Thanks :) I definitely think the other questions do it better though.

@darren-stone technically all computers have one really large array of bytes, but I disagree that BF does since random access is impossible. I've created a lot of data structures in BF and you need to simulate random access array through bread crumbs and loops just as you can simulate an array with linked lists in other languages. (imagine you read a byte and need to use the input as index in your array)

How do you feel about the primitive data type restriction? BF has an 8-bit byte as a primitive data type.  Operating with - and + on bytes may or may not be in the spirit of the question.  These are just my thoughts -- it's a popularity contest in the end, so the mob will decide an answer's validity. I like BF. I love Forth even more and I was considering a Forth-based submission, but I'm unclear in a stack model how I could push or pop or operate on a number and still be compliant.

@DarrenStone This isn't very compliant, although I don't see you could comply any better with Brainfuck...

Agreed. (Comment was for @Sylwester.) And I'm too scared to submit anything so I'll stop critiquing now!  :-)

@DarrenStone Perhaps a 5 character string can represent 5. I'd like to see a Forth solution :)

@Sylwester String ;}

C++ lambda functions
#include <cstdio>
#include <functional>

using std::function;

typedef function<int(int, function<int(int)>)> church;

church zero = [](int x, function<int(int)> f){ return x; };
function<church(church)> successor = [](church n)
{
  return [=](int x, function<int(int)> f)
  {
    return n(f(x),f);
  };
};

function<church(church, church)> plus = [](church n, church m)
{
  return [=](int x, function<int(int)> f)
  {
    return n(m(x, f), f);
  };
};

function<church(church, church)> times = [](church n, church m)
{
  return [=](int x, function<int(int)> f)
  {
    return m(x, [=](int y){ return n(y, f); });
  };
};

int main()
{
  function<int(int)> convert = [](int x){
    return x + 1;
  };
  auto resf0 = successor(successor(zero));
  int res0 = resf0(0, convert);
  printf("%i\n", res0); // 2

  auto resf1 = successor(resf0);
  int res1 = resf1(0, convert);
  printf("%i\n", res1); // 3

  auto resf2 = plus(resf0, resf1);
  int res2 = resf2(0, convert);
  printf("%i\n", res2); // 5

  auto resf3 = times(resf1, resf2);
  int res3 = resf3(0, convert);
  printf("%i\n", res3); // 15
}

This may not strictly follow the rules, but I wrote this, and somebody else revised it to this in August 2013. Ints are only used as a placeholder datatype, and also so that we can convert the weird function types to actual numbers.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes