सी#
(लिनक्यूपैड के माध्यम से, "सी # प्रोग्राम" मोड में;)
जहाँ तक कोई भी गोल्फिंग जा सकती है, समतुल्य स्ट्रोक नियंत्रण को लागू करने के लिए जा रहा है, लेकिन यह C # में मेरा दृष्टिकोण है (ठीक है, LINQPad, लेकिन कौन चाहता है कि सभी बॉयलरप्लेट जो एक पूर्ण सी # ऐप काम करने में जाता है?) ।
ग्रिड परिभाषाएं चर हैं, जिनमें कई ऊर्ध्वाधर पाइप हैं और समग्र संरचना की ऊंचाई है, और एक बीज को पारित करके ( PipeGrid
कंस्ट्रक्टर देखें ) दोहराए-यादृच्छिक हैं ।
किसी निश्चित उत्तर के अभाव में जिस तरह से वस्तु प्रवाहित होगी यदि दिशा या तो संभव थी, तो मैंने आपको कई विकल्पों में से एक व्यवहार निर्दिष्ट करने की अनुमति दी है ( SolveBehavior
गणना / PipeSolver
निर्माण देखें )।
ऊर्ध्वाधर शुरू करना निश्चित है (देखें PipeSolver.Solve
)।
मैंने मान लिया है कि क्षैतिज पाइप हमेशा दो आसन्न ऊर्ध्वाधर पाइपों के बीच होते हैं , अर्थात कोई क्षैतिज पाइप एक क्षैतिज पाइप को बायपास नहीं कर सकता है।
///<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
}
अपडेट करें:
मेरे सादे पुराने पाठ आउटपुट के डर से इस लोकप्रियता के संदर्भ में थोड़ा कमज़ोर हो सकता है, मैं एक विस्तारित संस्करण की पेशकश करता हूं जो एक छवि के रूप में लिया गया पथ भी खींचता है। मैंने इसे कार के रूप में मॉडल किया है, एक भयानक सड़क नेटवर्क के माध्यम से ड्राइविंग, नीचे तक पहुंचने की कोशिश कर रहा है, लेकिन दुनिया के सबसे खराब जीपीएस के साथ जो आपको हर जंक्शन पर एक मोड़ बनाने के लिए मजबूर करता है।
एक बोनस के रूप में, यह 'घुमाव' देखने के लिए भी स्पष्ट करता है।
आनंद - वर वधू !!
उदाहरण के परिणाम:
(ऊर्ध्वाधर: 10, ऊंचाई: 10, यादृच्छिक बीज: 5, पाइप शुरू: 2, व्यवहार को हल करें: FlipFlop})