I have to create a method to multiply a given Matrix by its transpose.
Consider my matrix is 2d array double [][] matrix;
public double[][] MultiplyByTranspose(double[][] matrix)
{
return newMatrix;
}
If you need my Matrix class check it in the answer of this question
Well, the simplest way is just to implement Transpose and Multiplication.
Of course, when combined, it could be done more efficient, but I think that you'll need Transpose and Multiplication as separated routine further in your code (you've asked about matrix rotation)
public static Boolean IsRectangle(Double[][] value) {
if (Object.ReferenceEquals(null, value))
return false;
else if (value.Length <= 0)
return false;
Double[] line = value[value.Length - 1];
if (Object.ReferenceEquals(null, line))
return false;
int size = line.Length;
for (int i = value.Length - 2; i >= 0; --i)
if (Object.ReferenceEquals(null, value[i]))
return false;
else if (value[i].Length != size)
return false;
return true;
}
public static Double[][] Transpose(Double[][] value) {
if (Object.ReferenceEquals(null, value))
throw new ArgumentNullException("value");
if (!IsRectangle(value))
throw new ArgumentException("value should be a rectangular matrix.", "value");
int colCount = value.Length;
int rowCount = value[value.Length - 1].Length;
Double[][] result = new Double[rowCount][];
for (int i = rowCount - 1; i >= 0; --i) {
Double[] line = new Double[colCount];
result[i] = line;
for (int j = colCount - 1; j >= 0; --j)
line[j] = value[j][i];
}
return result;
}
// Simple quibic algorithm
public static Double[][] Multiply(Double[][] left, Double[][] right) {
if (Object.ReferenceEquals(null, left))
throw new ArgumentNullException("left");
else if (Object.ReferenceEquals(null, right))
throw new ArgumentNullException("right");
if (!IsRectangle(left))
throw new ArgumentException("left should be a rectangular matrix", "left");
else if (!IsRectangle(right))
throw new ArgumentException("right should be a rectangular matrix", "right");
int leftRows = left.Length;
int leftCols = left[0].Length;
int rightRows = right.Length;
int rightCols = right[0].Length;
if (leftCols != rightRows)
throw new ArgumentOutOfRangeException("right");
Double[][] result = new Double[leftRows][];
for (int r = leftRows - 1; r >= 0; --r) {
Double[] leftLine = left[r];
Double[] line = new Double[rightCols];
result[r] = line;
for (int c = rightCols - 1; c >= 0; --c) {
Double s = 0.0;
for (int i = leftCols - 1; i >= 0; --i)
s += leftLine[i] * right[i][c];
line[c] = s;
}
}
return result;
}
...
public double[][] MultiplyByTranspose(double[][] matrix) {
//TODO: Check the order! Which matrix should be the first and which the second,
// In Linear Algebra A * B != B * A
return Multiply(matrix, Transpose(matrix));
// Or
// return Multiply(Transpose(matrix), matrix);
}
Related
I use Unity. but this engine cannot use Span ..
so, I made string parsing function
My function purpose is converting string to Single struct value(int, float, bool, UnityEngine.Vector4 etc..)
and i thought about how to not generate GC as much as possible
string data is read xml file
Examples of string data specifications are: "-1234.23,234,-.232.344", "554", "-.55"
During the test, I found something interesting
public unsafe Vector4 GetVectorToStackAlloc()
{
Vector4 vec = Vector4.Zero;
char* data = stackalloc char[8];
int dot = -1;
int index = 0;
int colume = 0;
for (int i = 0; i < Str.Length; ++i)
{
if (Str[i] == Token)
{
Parse();
dot = -1;
index = 0;
colume++;
}
else
{
if (Str[i] == '.') dot = index;
data[index++] = Str[i];
}
}
Parse();
void Parse()
{
if (index == 0) return;
bool isMinus = data[0] == '-';
int length = isMinus ? 1 : 0;
int mul = dot != -1 ? (dot - index) + 1 : 0;
for (int x = index - 1; x >= length; --x)
{
if (data[x] == '.') continue;
int k = data[x] - '0';
float m = MathF.Pow(10, mul++);
vec[colume] += k * m;
}
if (isMinus) vec[colume] *= -1;
}
return vec;
}
public Vector4 GetDefaultVector()
{
Vector4 vec = Vector4.Zero;
string[] split = Str.Split(Token);
for (int i = 0; i < split.Length; ++i)
{
if (string.IsNullOrWhiteSpace(split[i])) continue;
vec[i] = float.Parse(split[i]);
}
return vec;
}
public Vector4 GetSpanVector()
{
Vector4 vec = Vector4.Zero;
Span<char> span = stackalloc char[8];
int index = 0;
int colume = 0;
for (int i = 0; i < Str.Length; ++i)
{
if (Str[i] == ',')
{
if (index == 0) { vec[colume++] = 0; }
else vec[colume++] = float.Parse(span);
index = 0;
span.Clear();
}
else span[index++] = Str[i];
}
vec[colume] = float.Parse(span);
return vec;
}
Testing Vector4
During the testing process, I discovered that there was overhead in float.Parse() function and tested with a single float
public unsafe float GetStackAllocFloat()
{
float value = 0;
char* data = stackalloc char[8];
int dot = -1;
int index = 0;
for (int i = 0; i < Str.Length; ++i)
{
if (Str[i] == '.') dot = index;
data[index++] = Str[i];
}
if (index == 0) return value;
bool isMinus = data[0] == '-';
int length = isMinus ? 1 : 0;
int mul = dot != -1 ? (dot - index) + 1 : 0;
for (int x = index - 1; x >= length; --x)
{
if (data[x] == '.') continue;
int k = data[x] - '0';
float m = MathF.Pow(10, mul++);
value += k * m;
}
if (isMinus) value *= -1;
return value;
}
public unsafe float GetDefaultFloat()
{
return float.Parse(Str);
}
Testing Float
I think it is better to use stackalloc if the test method is normal.
Had I made mistake?
OK, I tested it again to fit the Unity engine as much as possible
I think it's not bad!
public readonly string[] Strs = new string[200] { // data is fill .. }
public const char Token = ',';
[Benchmark]
public unsafe Vector4 GetVectorToStackAlloc()
{
Vector4 result = Vector4.Zero;
int r = Strs.Length - 1;
while (r != -1)
{
Vector4 vec = Vector4.Zero;
char* data = stackalloc char[12];
int dot = -1;
int index = 0;
int colume = 0;
string Str = Strs[r--];
for (int i = 0; i < Str.Length; ++i)
{
if (Str[i] == Token)
{
vec[colume++] = Parse(index, data, dot);
dot = -1;
index = 0;
}
else
{
if (Str[i] == '.') dot = index;
data[index++] = Str[i];
}
}
vec[colume] = Parse(index, data, dot);
result.x += vec.x;
}
return result;
float Parse(int _index, char* _data, int _dot)
{
if (_index == 0) return 0;
float val = 0;
bool isMinus = _data[0] == '-';
int length = isMinus ? 1 : 0;
int mul = _dot != -1 ? (_dot - _index) + 1 : 0;
for (int x = _index - 1; x >= length; --x)
{
if (_data[x] == '.') continue;
int k = _data[x] - '0';
float m = MathF.Pow(10, mul++);
val = k * m;
}
return isMinus ? val * -1 : val;
}
}
[Benchmark]
public Vector4 GetDefaultVector()
{
Vector4 result = Vector4.Zero;
int r = Strs.Length - 1;
while (r != -1)
{
Vector4 vec = Vector4.Zero;
string Str = Strs[r--];
string[] split = Str.Split(Token);
for (int i = 0; i < split.Length; ++i)
{
if (string.IsNullOrWhiteSpace(split[i])) continue;
vec[i] = float.Parse(split[i]);
}
result.x += vec.x;
}
return result;
}
I'm trying some code from jamesmccaffrey web about inverse matrix (link). I used for invert n x n hessian matrix and I got the exception: "Cannot use Doolittle's method" in "static double[][] MatrixDecompose()" method. Here is the code that I used:
static double[][] MatrixCreate(int rows, int cols){
double[][] result = new double[rows][];
for (int i = 0; i < rows; ++i)
{
result[i] = new double[cols];
}
return result;
}
static double[][] MatrixRandom(int rows, int cols, double[,] hesian){
double[][] result = MatrixCreate(rows, cols);
double temp;
for (int i = 0; i < rows; i++)
{
temp = 0;
for (int j = 0; j < cols; j++)
{
temp = hesian[i, j];
result[i][j] = temp;
}
}
return result;
}
static double[][] MatrixDecompose(double[][] matrix, out int[] perm, out int toggle){
// Doolittle LUP decomposition with partial pivoting.
// rerturns: result is L (with 1s on diagonal) and U;
// perm holds row permutations; toggle is +1 or -1 (even or odd)
int rows = matrix.Length;
int cols = matrix[0].Length; // assume square
if (rows != cols)
{
throw new Exception("Attempt to decompose a non-square m");
}
int n = rows; // convenience
double[][] result = MatrixDuplicate(matrix);
perm = new int[n]; // set up row permutation result
for (int i = 0; i < n; ++i)
{
perm[i] = i;
}
toggle = 1; // toggle tracks row swaps.
// +1 -greater-than even, -1 -greater-than odd. used by MatrixDeterminant
for (int j = 0; j < n - 1; ++j) // each column
{
double colMax = Math.Abs(result[j][j]); // find largest val in col
int pRow = j;
//for (int i = j + 1; i less-than n; ++i)
//{
// if (result[i][j] greater-than colMax)
// {
// colMax = result[i][j];
// pRow = i;
// }
//}
// reader Matt V needed this:
for (int i = j + 1; i < n; ++i)
{
if (Math.Abs(result[i][j]) > colMax)
{
colMax = Math.Abs(result[i][j]);
pRow = i;
}
}
// Not sure if this approach is needed always, or not.
if (pRow != j) // if largest value not on pivot, swap rows
{
double[] rowPtr = result[pRow];
result[pRow] = result[j];
result[j] = rowPtr;
int tmp = perm[pRow]; // and swap perm info
perm[pRow] = perm[j];
perm[j] = tmp;
toggle = -toggle; // adjust the row-swap toggle
}
// --------------------------------------------------
// This part added later (not in original)
// and replaces the 'return null' below.
// if there is a 0 on the diagonal, find a good row
// from i = j+1 down that doesn't have
// a 0 in column j, and swap that good row with row j
// --------------------------------------------------
if (result[j][j] == 0.0)
{
// find a good row to swap
int goodRow = -1;
for (int row = j + 1; row < n; ++row)
{
if (result[row][j] != 0.0)
goodRow = row;
}
if (goodRow == -1)
throw new Exception("Cannot use Doolittle's method");
// swap rows so 0.0 no longer on diagonal
double[] rowPtr = result[goodRow];
result[goodRow] = result[j];
result[j] = rowPtr;
int tmp = perm[goodRow]; // and swap perm info
perm[goodRow] = perm[j];
perm[j] = tmp;
toggle = -toggle; // adjust the row-swap toggle
}
// --------------------------------------------------
// if diagonal after swap is zero . .
//if (Math.Abs(result[j][j]) less-than 1.0E-20)
// return null; // consider a throw
for (int i = j + 1; i < n; ++i)
{
result[i][j] /= result[j][j];
for (int k = j + 1; k < n; ++k)
{
result[i][k] -= result[i][j] * result[j][k];
}
}
} // main j column loop
return result;
} // MatrixDecompose
static double[][] MatrixInverse(double[][] matrix){
int n = matrix.Length;
double[][] result = MatrixDuplicate(matrix);
int[] perm;
int toggle;
double[][] lum = MatrixDecompose(matrix, out perm,
out toggle);
if (lum == null)
throw new Exception("Unable to compute inverse");
double[] b = new double[n];
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (i == perm[j])
b[j] = 1.0;
else
b[j] = 0.0;
}
double[] x = HelperSolve(lum, b); //
for (int j = 0; j < n; ++j)
result[j][i] = x[j];
}
return result;
}
static double MatrixDeterminant(double[][] matrix)
{
int[] perm;
int toggle;
double[][] lum = MatrixDecompose(matrix, out perm, out toggle);
if (lum == null)
{
throw new Exception("Unable to compute MatrixDeterminant");
}
double result = toggle;
for (int i = 0; i < lum.Length; ++i)
{
result *= lum[i][i];
}
return result;
}
static double[][] MatrixDuplicate(double[][] matrix)
{
// allocates/creates a duplicate of a matrix.
double[][] result = MatrixCreate(matrix.Length, matrix[0].Length);
for (int i = 0; i < matrix.Length; ++i)
{ // copy the values
for (int j = 0; j < matrix[i].Length; ++j)
{
result[i][j] = matrix[i][j];
}
{
return result;
}
I expect that the MatrixInverse() method returns inverse hessian matrix.
I'm trying to implement the MinMax algorithm for four in a row (or connect4 or connect four) game.
I think I got the idea of it, it should build a tree of possible boards up to a certain depth, evaluate them and return their score, then we just take the max of those scores.
So, aiChooseCol() checks the score of every possible column by calling MinMax() and returns the column with the max score.
Now I wasn't sure, is this the right way to call MinMax()?
Is it right to check temp = Math.Max(temp, 1000);?
I still haven't made the heuristic function but this should at least recognize a winning column and choose it, but currently it just choose the first free column from the left... I can't figure out what am I doing wrong.
private int AiChooseCol()
{
int best = -1000;
int col=0;
for (int i = 0; i < m_Board.Cols; i++)
{
if (m_Board.CheckIfColHasRoom(i))
{
m_Board.FillSignInBoardAccordingToCol(i, m_Sign);
int t = MinMax(5, m_Board, board.GetOtherPlayerSign(m_Sign));
if (t > best)
{
best = t;
col = i;
}
m_Board.RemoveTopCoinFromCol(i);
}
}
return col;
}
private int MinMax(int Depth, board Board, char PlayerSign)
{
int temp=0;
if (Depth <= 0)
{
// return from heurisitic function
return temp;
}
char otherPlayerSign = board.GetOtherPlayerSign(PlayerSign);
char checkBoard = Board.CheckBoardForWin();
if (checkBoard == PlayerSign)
{
return 1000;
}
else if (checkBoard == otherPlayerSign)
{
return -1000;
}
else if (!Board.CheckIfBoardIsNotFull())
{
return 0; // tie
}
if (PlayerSign == m_Sign) // maximizing Player is myself
{
temp = -1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Max(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
else
{
temp = 1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Min(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
return temp;
}
Some notes:
FillSignInBoardAccordingToCol() returns a boolean if it was successful.
The board type has a char[,] array with the actual board and signs of the players.
This code is in the AI Player class.
So I decided to write my own MinMax Connect 4. I used the depth to determine the value of a win or loss so that a move that gets you closer to winning or blocking a loss will take precedence. I also decide that I will randomly pick the move if more than one has the same heuristic. Finally I stretched out the depth to 6 as that's how many moves are required to find possible win paths from the start.
private static void Main(string[] args)
{
var board = new Board(8,7);
var random = new Random();
while (true)
{
Console.WriteLine("Pick a column 1 -8");
int move;
if (!int.TryParse(Console.ReadLine(), out move) || move < 1 || move > 8)
{
Console.WriteLine("Must enter a number 1-8.");
continue;
}
if (!board.DropCoin(1, move-1))
{
Console.WriteLine("That column is full, pick another one");
continue;
}
if (board.Winner == 1)
{
Console.WriteLine(board);
Console.WriteLine("You win!");
break;
}
if (board.IsFull)
{
Console.WriteLine(board);
Console.WriteLine("Tie!");
break;
}
var moves = new List<Tuple<int, int>>();
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(2, i))
continue;
moves.Add(Tuple.Create(i, MinMax(6, board, false)));
board.RemoveTopCoin(i);
}
int maxMoveScore = moves.Max(t => t.Item2);
var bestMoves = moves.Where(t => t.Item2 == maxMoveScore).ToList();
board.DropCoin(2, bestMoves[random.Next(0,bestMoves.Count)].Item1);
Console.WriteLine(board);
if (board.Winner == 2)
{
Console.WriteLine("You lost!");
break;
}
if (board.IsFull)
{
Console.WriteLine("Tie!");
break;
}
}
Console.WriteLine("DONE");
Console.ReadKey();
}
private static int MinMax(int depth, Board board, bool maximizingPlayer)
{
if (depth <= 0)
return 0;
var winner = board.Winner;
if (winner == 2)
return depth;
if (winner == 1)
return -depth;
if (board.IsFull)
return 0;
int bestValue = maximizingPlayer ? -1 : 1;
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(maximizingPlayer ? 2 : 1, i))
continue;
int v = MinMax(depth - 1, board, !maximizingPlayer);
bestValue = maximizingPlayer ? Math.Max(bestValue, v) : Math.Min(bestValue, v);
board.RemoveTopCoin(i);
}
return bestValue;
}
public class Board
{
private readonly int?[,] _board;
private int? _winner;
private bool _changed;
public Board(int cols, int rows)
{
Columns = cols;
Rows = rows;
_board = new int?[cols, rows];
}
public int Columns { get; }
public int Rows { get; }
public bool ColumnFree(int column)
{
return !_board[column, 0].HasValue;
}
public bool DropCoin(int playerId, int column)
{
int row = 0;
while (row < Rows && !_board[column,row].HasValue)
{
row++;
}
if (row == 0)
return false;
_board[column, row - 1] = playerId;
_changed = true;
return true;
}
public bool RemoveTopCoin(int column)
{
int row = 0;
while (row < Rows && !_board[column, row].HasValue)
{
row++;
}
if (row == Rows)
return false;
_board[column, row] = null;
_changed = true;
return true;
}
public int? Winner
{
get
{
if (!_changed)
return _winner;
_changed = false;
for (int i = 0; i < Columns; i++)
{
for (int j = 0; j < Rows; j++)
{
if (!_board[i, j].HasValue)
continue;
bool horizontal = i + 3 < Columns;
bool vertical = j + 3 < Rows;
if (!horizontal && !vertical)
continue;
bool forwardDiagonal = horizontal && vertical;
bool backwardDiagonal = vertical && i - 3 >= 0;
for (int k = 1; k < 4; k++)
{
horizontal = horizontal && _board[i, j] == _board[i + k, j];
vertical = vertical && _board[i, j] == _board[i, j + k];
forwardDiagonal = forwardDiagonal && _board[i, j] == _board[i + k, j + k];
backwardDiagonal = backwardDiagonal && _board[i, j] == _board[i - k, j + k];
if (!horizontal && !vertical && !forwardDiagonal && !backwardDiagonal)
break;
}
if (horizontal || vertical || forwardDiagonal || backwardDiagonal)
{
_winner = _board[i, j];
return _winner;
}
}
}
_winner = null;
return _winner;
}
}
public bool IsFull
{
get
{
for (int i = 0; i < Columns; i++)
{
if (!_board[i, 0].HasValue)
return false;
}
return true;
}
}
public override string ToString()
{
var builder = new StringBuilder();
for (int j = 0; j < Rows; j++)
{
builder.Append('|');
for (int i = 0; i < Columns; i++)
{
builder.Append(_board[i, j].HasValue ? _board[i,j].Value.ToString() : " ").Append('|');
}
builder.AppendLine();
}
return builder.ToString();
}
}
I've tried to reimplement the Fast Graphics Gems Ray/AABB Intersection Method in C#:
// Based on "Fast Ray-Box Intersection" algorithm by Andrew Woo, "Graphics Gems", Academic Press, 1990
public unsafe Vector? IntersectionWith(Cuboid other) {
const int NUM_DIMENSIONS = 3;
Assure.Equal(NUM_DIMENSIONS, 3); // If that value is ever changed, this algorithm will need some maintenance
const byte QUADRANT_MIN = 0;
const byte QUADRANT_MAX = 1;
const byte QUADRANT_BETWEEN = 2;
// Step 1: Work out which direction from the start point to test for intersection for all 3 dimensions, and the distance
byte* quadrants = stackalloc byte[NUM_DIMENSIONS];
float* candidatePlanes = stackalloc float[NUM_DIMENSIONS];
float* cuboidMinPoints = stackalloc float[NUM_DIMENSIONS];
float* cuboidMaxPoints = stackalloc float[NUM_DIMENSIONS];
float maxDistance = Single.NegativeInfinity;
byte maxDistanceDimension = 0;
bool startPointIsInsideCuboid = true;
cuboidMinPoints[0] = other.X;
cuboidMinPoints[1] = other.Y;
cuboidMinPoints[2] = other.Z;
cuboidMaxPoints[0] = other.X + other.Width;
cuboidMaxPoints[1] = other.Y + other.Height;
cuboidMaxPoints[2] = other.Z + other.Depth;
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
if (StartPoint[i] < cuboidMinPoints[i]) {
quadrants[i] = QUADRANT_MIN;
candidatePlanes[i] = cuboidMinPoints[i];
startPointIsInsideCuboid = false;
}
else if (StartPoint[i] > cuboidMaxPoints[i]) {
quadrants[i] = QUADRANT_MAX;
candidatePlanes[i] = cuboidMaxPoints[i];
startPointIsInsideCuboid = false;
}
else {
quadrants[i] = QUADRANT_BETWEEN;
}
}
if (startPointIsInsideCuboid) return StartPoint;
// Step 2: Find farthest dimension from cuboid
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
// ReSharper disable once CompareOfFloatsByEqualityOperator Exact check is desired here: Anything other than 0f is usable
if (quadrants[i] != QUADRANT_BETWEEN && Orientation[i] != 0f) {
float thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i];
if (thisDimensionDist > maxDistance) {
maxDistance = thisDimensionDist;
maxDistanceDimension = i;
}
}
}
if (maxDistance < 0f) return null;
if (maxDistance - Length > MathUtils.FlopsErrorMargin) return null;
float* intersectionPoint = stackalloc float[NUM_DIMENSIONS];
for (byte i = 0; i < NUM_DIMENSIONS; ++i) {
if (maxDistanceDimension == i) {
intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i];
if (cuboidMinPoints[i] - intersectionPoint[i] > MathUtils.FlopsErrorMargin || intersectionPoint[i] - cuboidMaxPoints[i] > MathUtils.FlopsErrorMargin) return null;
}
else intersectionPoint[i] = candidatePlanes[i];
}
Vector result = new Vector(intersectionPoint[0], intersectionPoint[1], intersectionPoint[2]);
if (!IsInfiniteLength && Vector.DistanceSquared(StartPoint, result) > Length * Length) return null;
else return result;
}
However, although it sort of works, I'm getting incorrect results on the following part of a unit test:
Cuboid cuboid = new Cuboid(frontBottomLeft: new Vector(0f, 7.1f, 0f), width: 0f, height: 5f, depth: 0f);
Ray testRayC = new Ray(startPoint: new Vector(30f, 30f, 30f), orientation: new Vector(-1f, -1f, -1f));
Assert.AreEqual(
null,
testRayC.IntersectionWith(cuboid)
);
I am expecting null from the call to testRayC.IntersectionWith(cuboid), but instead it returns a Vector(0, 12.1, 0), which is not a point on the ray at all.
So is it just a case of adding a final check that the calculated point is on the ray? Or (and this is what I suspect), have I made an error in transcribing the code? I have double and triple checked but didn't see anything obvious...
The problem in your code is when you do if (maxDistanceDimension == i) {. The original code checks if (whichPlane != i) {. I don't have your data structures, but a fix should look like:
for (byte i = 0; i < NUM_DIMENSIONS; ++i)
{
if (maxDistanceDimension != i)
{
intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i];
if (intersectionPoint[i] < cuboidMinPoints[i] - MathUtils.FlopsErrorMargin || intersectionPoint[i] > cuboidMaxPoints[i] + MathUtils.FlopsErrorMargin)
return null;
}
else
{
intersectionPoint[i] = candidatePlanes[i];
}
}
Next, the following isn't in the original code. What is this for?
if (maxDistance - Length > MathUtils.FlopsErrorMargin)
return null;
If you are trying to check if the hit is within the extent of the ray, this may be a bug. Given that your Orientation does not appear to be normalized, maxDistance is not necessarily in units of length. This may not matter in the original algorithm, but if you are going to check maxDistance against some other length you need to normalize Orientation (make it dimensionless) so that
thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i];
will have units of length.
Incidentally, in the original I think the following is wrong:
if(inside) {
coord = origin;
return (TRUE);
}
Assuming this code is c and not c++, this simply sets the the coord pointer to have the same reference as the origin pointer, which will have no effect on the caller. This issue doesn't apply to your version, however.
Also, in the course of looking at this, I made a more literal c# transcription of the algorithm here:
public static class RayXCuboid
{
enum HitQuadrant
{
Right = 0,
Left = 1,
Middle = 2,
}
const int Dimension = 3;
[Conditional("DEBUG")]
static void AssertValidArguments<TDoubleList>(params TDoubleList[] args) where TDoubleList : IList<double>
{
Debug.Assert(Dimension == 3);
foreach (var list in args)
Debug.Assert(list != null && list.Count == Dimension);
}
public static bool HitBoundingBox<TDoubleList>(TDoubleList minB, TDoubleList maxB, TDoubleList origin, TDoubleList dir, TDoubleList coord) where TDoubleList : IList<double>
{
AssertValidArguments(minB, maxB, origin, dir, coord);
HitQuadrant[] quadrant = new HitQuadrant[Dimension];
double[] maxT = new double[Dimension];
double[] candidatePlane = new double[Dimension];
/* Find candidate planes; this loop can be avoided if
rays cast all from the eye(assume perpsective view) */
bool inside = true;
for (int i = 0; i < Dimension; i++)
if (origin[i] < minB[i])
{
quadrant[i] = HitQuadrant.Left;
candidatePlane[i] = minB[i];
inside = false;
}
else if (origin[i] > maxB[i])
{
quadrant[i] = HitQuadrant.Right;
candidatePlane[i] = maxB[i];
inside = false;
}
else
{
quadrant[i] = HitQuadrant.Middle;
}
/* Ray origin inside bounding box */
if (inside)
{
CopyTo(origin, coord);
return true;
}
/* Calculate T distances to candidate planes */
for (int i = 0; i < Dimension; i++)
if (quadrant[i] != HitQuadrant.Middle && dir[i] != 0.0)
maxT[i] = (candidatePlane[i] - origin[i]) / dir[i];
else
maxT[i] = -1.0;
/* Get largest of the maxT's for final choice of intersection */
int whichPlane = 0;
for (int i = 1; i < Dimension; i++)
if (maxT[whichPlane] < maxT[i])
whichPlane = i;
/* Check final candidate actually inside box */
if (maxT[whichPlane] < 0.0)
{
FillWithDefault(coord);
return false;
}
for (int i = 0; i < Dimension; i++)
if (whichPlane != i)
{
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
if (coord[i] < minB[i] || coord[i] > maxB[i])
{
FillWithDefault(coord);
return false;
}
}
else
{
coord[i] = candidatePlane[i];
}
return true; /* ray hits box */
}
static void FillWithDefault<T>(IList<T> list)
{
for (int i = 0; i < list.Count; i++)
list[i] = default(T);
}
static void CopyTo<T>(IList<T> from, IList<T> to)
{
int arrayIndex = 0;
foreach (var item in from)
to[arrayIndex++] = item;
}
}
here will be my code for famous Knights Tour for 8x8 deck. So, the main idea of my code is: we will choose from Turns our destination, check it with isPossible and then go recursevly to it, marked this cell to '1'. So, check every cell, and if we will be in 64's cell - return true.
But my code goes to infinite recurssion, and I can't debug it, any recommendation will be greatly appreciated.
class Class1
{
static void Main(string[] args)
{
int x = 0;
int y = 0;
Console.WriteLine("Enter X and press enter");
x = Int32.Parse(Console.ReadLine());
Console.WriteLine("Enter Y and press enter");
y = Int32.Parse(Console.ReadLine());
TurnVariation Turns = new TurnVariation();
EmptyBoard Board = new EmptyBoard();
if (TryPut.Put(Board, x, y, Turns, 1, false))
{
Console.WriteLine("МОЖНА!!!!");
}
else
{
Console.WriteLine("NET!!");
}
}
}
public class TryPut : EmptyBoard
{
public static bool Put(EmptyBoard Board, int x, int y, TurnVariation Turns, int count, bool flag)
{
int tempX = 0;
int tempY = 0;
if (count >= 64)
{
Console.WriteLine("yeab");
return true;
}
for (int i = 0; i <= 7; i++)
{
tempX = x + Turns.Turns[i,0];
tempY = y + Turns.Turns[i,1];
//Console.WriteLine(count);
if (IsPossible(Board, tempX, tempY))
{
Board.Array[tempX, tempY] = 1;
flag = Put(Board, tempX, tempY, Turns, count+1, flag);
if (flag)
{
break;
}
Board.Array[tempX, tempY] = 0;
}
}
if (flag)
return true;
else
return false;
}
public static bool IsPossible(EmptyBoard Board, int x, int y)
{
if ((x < 0) || (x > 7) || (y < 0) || (y > 7))
return false;
if (Board.Array[x, y] == 1)
return false;
return true;
}
}
public class TurnVariation
{
public int[,] Turns = new int[8, 2];
public TurnVariation()
{
Turns[0, 0] = -2; Turns[0, 1] = 1;
Turns[1,0] = -2; Turns[1,1] = -1;
Turns[2,0] = -1; Turns[2,1] = 2;
Turns[3,0] = 1; Turns[3,1] = 2;
Turns[4,0] = 2; Turns[4,1] = 1;
Turns[5,0] = 2; Turns[5,1] = -1;
Turns[6,0] = 1; Turns[6,1] = -2;
Turns[7,0] = -1; Turns[7,1] = -2;
}
}
public class EmptyBoard
{
public const int N = 8;
public int[,] Array = new int[N, N];
public EmptyBoard()
{
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
Array[i, j] = 0;
}
}
I think your problem is that your testing for count<64, but you never assign to count. You just pass (by value!) 'Count + 1' to the put method. You are probably thinking that this will bewritten back to the count variable. But that is not the case...
Do note that debugging is the first skill you need to learn!