3-Axis Coordinate System for a Chinese Checkers Board - Iteration 2

This is a followup to 3-Axis Coordinate System for a Chinese Checkers Board.

I have made the following changes:

  • The properties of Vector have been made private set
  • A chunk of code that I forgot to remove after it lost relevance has been removed
  • Bracing style has been switched to allman
  • Use of separating statements on to multiple lines has been done where requested
  • ToString has been implemented for struct Vector

Now that we, hopefully, got all the stylistic stuff out of the way I'm interested in any feedback on the following from the OP:

However, it quickly became apparent that it is valuable to have a type-enforced way of separating unit vectors from vectors of non-unit magnitude.

...

I could include conditional code, and either return null or throw exceptions, but that kind of overhead seems excessive for this simple task (not to mention forcing calling code to add potential run-time error checking for something that should be able to be validated at compile-time).

I like the idea of keeping the Vector struct/class as simple as possible because it's not a terribly complex structure (and wouldn't warrant a polymorphic class in my typical C++ projects; but instead a simple typedef).

So I'm looking for suggestions on the cleanest, lightest (is that an oxymoron? :P ), or in other words most preferred C# way of enforcing the use of "unit vectors".

Here is the updated code (with running fiddle) with the use-case code drawn from my unit tests:

using System; using System.Collections.Generic;  namespace Cs_Console_Test {     public class Program     {         const string TableHeader = " X  \t YL \t YR ";         static string TableRow(Grid.Vector vec)         {             return String.Format("{0,4}\t{1,4}\t{2,4}", vec.X, vec.YL, vec.YR);         }          // Tests the Neighbor member function         static void PrintNeighbors(Grid.ICell Center)         {             Console.WriteLine("    Neighbors of {0}", Center.Location);             Console.WriteLine(TableHeader + "\t->\tValue");             foreach (Grid.Vector unit in Grid.Vector.Units)             {                 Grid.Vector? Translated = Center.Location + unit;                 Grid.ICell Neighbor = Center.Neighbor(unit);                  string Location =                     Translated == null                     ? "X: null,\tYL: null,\tYZ: null"                     : TableRow(Translated.Value);                  string Value =                     Neighbor == null                     ? "null"                     : "Grid.ICell";                  Console.WriteLine(Location + "\t->\t" + Value);             }             Console.WriteLine();         }          static void PrintNeighborsOf(Grid Board, Grid.Vector Direction)         {             Grid.Vector Center = new Grid.Vector(0, 0, 0);              // Test the addition operator             Grid.Vector? Translated = Center + Direction;             if (Translated != null)             {                 Grid.ICell Cell = Board[Translated.Value];                 if (Cell != null)                 {                     PrintNeighbors(Cell);                 }                 else                 {                     Console.WriteLine("No Grid.ICell found at {0}\n", Translated.Value);                 }             }             else             {                 Console.WriteLine("Unable to translate by {0}: Intregal Overflow\n", Direction);             }          }          static void PrintLocation(Grid.Vector lhs, Grid.Vector rhs)         {             Grid.Vector? Translated = lhs + rhs;             if (Translated == null)             {                 Console.WriteLine("Unable to translate by {0}: Intregal Overflow\n", rhs);             }             else             {                 Console.WriteLine("This should not get printed\n");             }         }          public static void Main(string[] args)         {             Grid Board = new Grid();              PrintNeighborsOf(Board, new Grid.Vector(0, 0, 0));             PrintNeighborsOf(Board, new Grid.Vector(4, 4, 4));             PrintNeighborsOf(Board, new Grid.Vector(5, 0, 0));             PrintLocation(new Grid.Vector(1, 0, 0), new Grid.Vector(127, 0, 0));              Console.Write("Press any key to continue . . . ");             Console.ReadKey();         }     }      public partial class Grid     {         public struct Vector         {             // Enumerate all six of the cardinal unit vectors             public static readonly Vector[] Units = new Vector[6]{                 new Vector( 1,  0,  0),                 new Vector(-1,  0,  0),                 new Vector( 0,  1,  0),                 new Vector( 0, -1,  0),                 new Vector( 0,  0,  1),                 new Vector( 0,  0, -1),             };              // sbyte => range of [-128, 127]; plenty big for this app, and small enough to GetHashCode()             public sbyte X  { get; private set; } // Horizontal Axis             public sbyte YL { get; private set; } // Left-slanted Vertical Axis             public sbyte YR { get; private set; } // Right-slanted Vertical Axis             public Vector(sbyte x, sbyte yl, sbyte yr) : this() {                 X  = x;                 YL = yl;                 YR = yr;             }              // Overloaded Arithmetic Operators; Prototypes found at: http://stackoverflow.com/a/20596352/310560             // Since we don't have a clear cut way to give a comparable "numerical" value to a set of 3 signed integers             // The logic for `Compare` will be based on `==` and `<` (the typical C++ approach)             // Where the typical C# approach would base `==` and `<` off `Compare`             public static bool operator==(Vector lhs, Vector rhs)             {                 return                     lhs.X  == rhs.X  &&                     lhs.YL == rhs.YL &&                     lhs.YR == rhs.YR;             }              // The < operator is important for any data algorithms which require sorting             public static bool operator< (Vector lhs, Vector rhs)             {                 return                     lhs.X  < rhs.X  || (lhs.X  == rhs.X  &&                     lhs.YL < rhs.YL || (lhs.YL == rhs.YL &&                     lhs.YR < rhs.YR));             }              // We'll just implement the rest of the comparison operators simply because we can,  and complementary             // operators should always be implemented together (though why C# doesn't do this already I'm not sure)             public static bool operator> (Vector lhs, Vector rhs) { return   rhs < lhs; }             public static bool operator<=(Vector lhs, Vector rhs) { return !(lhs > rhs); }             public static bool operator>=(Vector lhs, Vector rhs) { return !(lhs < rhs); }             public static bool operator!=(Vector lhs, Vector rhs) { return !(lhs == rhs); }              // Attached Object Comparison Overloads             public override bool Equals(object obj) { return (obj is Vector) && (this == (Vector)obj); }             public bool Equals(Vector rhs) { return Equals(this, rhs); }             public int CompareTo(Vector rhs) { return CompareTo(this, rhs); }              // Detached Object Comparison Overloads             public static bool Equals(Vector lhs, Vector rhs) { return lhs == rhs; }             private static int CompareTo(Vector lhs, Vector rhs)             {                 return lhs == rhs ?  0                     : (lhs <  rhs ? -1                     :                1);             }              // Used for indexing in hash tables (i.e. Dictionary<Vector, Cell>)             public override int GetHashCode()             {                 return (X << 16) | (YL << 8) | (YR << 0);             }              // Addition operator used for translation             public static Vector? operator+(Vector lhs, Vector rhs)             {                 try                 {                     Vector shifted = new Vector(                         checked((sbyte)(lhs.X  + rhs.X)),                         checked((sbyte)(lhs.YL + rhs.YL)),                         checked((sbyte)(lhs.YR + rhs.YR)));                     return shifted;                 }                 catch                 {                     return null;                 }             }              public override string ToString()             {                 return String.Format("Grid.Vector({0}, {1}, {2})", X, YL, YR);             }         }     }      public partial class Grid     {         private readonly Dictionary<Vector, ICell> Board;         public ICell this[Vector i]         {             get { if (Board.ContainsKey(i)) return Board[i]; return null; }             private set { Board[i] = value; }         }         public ICell GetCell(sbyte x, sbyte yl, sbyte yr)         {             return this[new Vector(x, yl, yr)];         }          public Grid()         {             Board = new Dictionary<Vector, ICell>();              // Add the inner hexagonal part of the Chinese Checkers board             // Will add logic for the outer triangles after finished testing             for (sbyte i = -4; i < 5; ++i)             {                 for (sbyte j = -4; j < 5; ++j)                 {                     for (sbyte k = -4; k < 5; ++k)                     {                         new Cell(this, new Vector(i, j, k));                     }                 }             }         }     }      public partial class Grid     {         public interface ICell         {             Grid Parent { get; }             Vector Location { get; }             ICell Neighbor(Vector direction);         }          // It's important this class is private to insure Grid exclusively can instantiate cells         // Thus it is important to maintain the interface ICell for public interaction         private class Cell : ICell         {             private readonly Grid _parent;             public Grid Parent { get { return _parent; } }              private readonly Vector _location;             public Vector Location { get { return _location; } }              public ICell Neighbor(Vector direction)             {                 Vector? loc = Location + direction;                 if (loc == null) { return null; }                 return Parent[loc.Value];             }              public Cell(Grid par, Vector loc)             {                 _parent = par; _location = loc;                 Parent[Location] = this;             }         }     } } 

Replay

Category: c# Time: 2016-07-28 Views: 0

Related post

iOS development

Android development

Python development

JAVA development

Development language

PHP development

Ruby development

search

Front-end development

Database

development tools

Open Platform

Javascript development

.NET development

cloud computing

server

Copyright (C) avrocks.com, All Rights Reserved.

processed in 0.103 (s). 12 q(s)