The following code snippet, with width=2,height=2
int maxI = width + height;
for (int i = 1; i <= maxI; i++) {
int startJ = Math.Max(0, i - width);
int maxJ = Math.Min(i, height);
for (int j = startJ; j <= maxJ; j++) {
int x = i - j;
int y = j;
DoSomething(x,y);}}
Will call DoSomething with the following x,y pairs:
1: X=1,Y=0
2: X=0,Y=1 (Diagram: 0,0
3: X=2,Y=0 at bottom left)
4: X=1,Y=1 5 7 8
5: X=0,Y=2 2 4 6
6: X=2,Y=1 # 1 3
7: X=1,Y=2
8: X=2,Y=2
This is the desired result; to iterate a rectangle starting from 0,0 but expanding diagonally rather than (the much more popular) [y*width+x]. However, I'm baffled by the maxI=width+height and x=i-j calculations. How does this conversion work?
The thing to realize here is that x + y is a constant for each cell in a particular diagonal. For example, cells 3, 4, and 5 have coordinates {2, 0}; {1, 1}; {0, 2}. Notice that each of those add up to 2.
So maxI is really the maximum value of one of these sums. Since {width, height} is the top right, the sum for that diagonal is width + height. So that's where that comes from.
The i - j part comes about because it's basically solving the above equation. Each value of i is the sum of the coordinates. j is chosen to be the y-coordinate of a cell within that diagonal. Since we know x + y = i and that y = j, we get that x + j = i or x = i - j.
This can be also explained by geometric transformations:
1) Translation, so the rectangle's center is in origin:
x' = x - width/2
bounds: [-width/2,width/2)
y' = y - height/2
bounds: [-height/2,height/2)
2) Rotation by 45 degrees:
x'' = x'cos(45) - y'sin(45) = (sqrt(2)/2)x' - (sqrt(2)/2)y'
y'' = x'sin(45) + y'cos(45) = (sqrt(2)/2)x' + (sqrt(2)/2)y'
3) Scaling by sqrt(2)/2:
x''' = x' - y' = x - width/2 - y + height/2
bounds: [-width/2-height/2,width/2+height/2)
y''' = x' + y' = x - width/2 + y - height/2
bounds: [-width/2-height/2,width/2+height/2)
4) Translating back only on x axis:
x'''' = x''' + width/2 = x - y + height/2
bounds: [-height/2,width/2+height/2)
y'''' = y'''
bounds: [-width/2-height/2,width/2+height/2)
5) Introducing parametric variables:
i = y'''' + width/2 + height/2
bounds: [0,width+height)
j = x'''' + y'''' - width/2 - height/2
bounds: [-width-3*height/2,width/2+height/2)
For this transformation you get that:
x = i - j
y = j
And it will iterate point by point through diagonals going from bottom-right to top-left corner of the screen. Max and Min in the code you presented bound the result to a subset of these diagonals, representing a rectangle.
Related
Calculate the number of points with integer coordinates inside the ellipse1. Hint: check those values for x and y for which
< 1.
Can
and this be fulfilled? And what about y?
There is no point inside the ellipse whose |x| is greater than 13.
If you want to count the number of points with integer coordinates inside the ellipse I would do something like this:
int Points = 0;
for(int x = -13; x <= 13; x++)
{
for(int y = -16; y <= 16; y++)
{
if((Math.Pow(x, 2)/169) + (Math.Pow(y, 2)/256) <= 1)
{
Points++;
}
}
Clarify the question if you want a more detailed answer because it is hard to understand what you are asking.
You can query all the points within
x = {-13 .. 13}
y = {-16 .. 16}
square (follow the hint provided: you should analyze points such that |x| < 13 and |y| < 16). Let's do it with a help of Linq:
int a = 13;
int b = 16;
int result = Enumerable
.Range(-a, a * 2 + 1)
.SelectMany(x => Enumerable
.Range(-b, 2 * b + 1)
.Select(y => (x: x, y: y)))
.Count(p => (double) p.x * p.x / a / a + (double) p.y * p.y / b / b < 1);
Console.Write(result);
Outcome:
647
If you want to include points which on the ellipse (e.g. {13, 0}), just change < 1 into <= 1. In this case you'll have 651 points (points {-13, 0}, {13, 0}, {0, -16}, {0, 16} are added).
I could use some help creating some points for a sliced circle, I'm having a total brainfart and just can't figure it out.
I want to create a "field of view" circle for a game ai and would like to create the points in an alternating pattern covering roughly a Pi*1.75 area.
To make alternate rays, you can use parity of counter. Pseudocode
n = 11
for (i = 1; i <= n; i++) {
int j = i / 2
float angle = - j * Pi * 7 / 4 / n
if (i & 1)
angle = - angle
line end:
X = CX + R * Cos(angle - Pi/2))
Y = CY + R * Sin(angle - Pi/2))
working Delphi code for demonstration:
var
n, i, X, Y: Integer;
a: Double;
begin
n := 11;
for i := 1 to n do begin
Canvas.MoveTo(200, 200);
a := (i div 2)* Pi * 7 / 4 / n;
if (i and 1 = 0) then
a := - a;
X := 200 + Round(100 * Cos(a - Pi/2));
Y := 200 + Round(100 * Sin(a - Pi/2));
Canvas.LineTo(X, Y);
Canvas.TextOut(X, Y, i.ToString);
end;
I feel like I'm missing something terribly obvious, but I cannot seem to find the array pair with the lowest value.
I have an int[,] worldMapXY where a 2D map is stored, say worldMapXY[0,0] through worldMapXY[120,120]. All values of map's array are 1 (wall\invalid) or 0 (path/valid).
I'm writing a method that will find coordinates in one of the eight cardinal directions to create a spawn point. So I also have int[,] validSpotArr which has a subset of bounds of the map closest to the direction I'm setting the spawn. The values for wall/invalid locations are set to 9999, the values for path/valid locations are set to (x + y). This is all specific to the bottom left corner, nearest to [0,0], hence "BL" or "Bottom Left"
case "BL":
for (int x = (int)border + 1; x < worldX + (int)border / 4; x++)
{
for (int y = (int)border + 1; y < worldY + (int)border / 4; y++)
{
if (worldMapXY[x,y] = 0)
{
validSpotArr[x,y] = x + y;
}
else
{
validSpotArr[x,y] = 9999;
}
}
}
What I can't quite wrap my head around is how to determine the coordinates/index of validSpotArr with the lowest value in such a way that I could pass those as separate x and y coordinates to another function (to set the spawn point). I suspect there's a lambda operator that may help, but I literally don't understand lambdas. Clearly that needs to be my next point of study.
E.g. - if validSpotArr[23, 45] = 68, and 68 is the lowest value, how do I set x=23 and y=45?
Edit: I tried messing around with something like this, but it isn't right:
Array.IndexOf(validSpotArr, validSpotArr.Min());
While not precisely an answer to your question, in a strictly given situation I'd probably go for finding those from within the cycles, i.e.
int minValidSpot = int.MaxValue, minX, minY;
for (int x = (int)border + 1; x < worldX + int(border) / 4; x++)
{
for (int y = (int)border + 1; y < worldY + int(border) / 4; y++)
{
if (worldMapXY[x,y] = 0)
{
validSpotArr[x,y] = x + y;
}
else
{
validSpotArr[x,y] = 9999;
}
if ( minValidSpot > validSpotArr[x,y] )
{
minValidSpot = validSpotArr[x,y];
minX = x;
minY = y;
}
}
}
Other than that, if looking for some kind of more universal solution, I'd probably just flatten that array, the maths for index conversion (nD<=>1D) are pretty simple.
I want to create a simple square on C# which will be used as a game board.
I am trying to do it using nested loops and have looked into how people make squares this way however I am having difficulty understanding how its done.
This is my code so far for the board:
for (int x = 0; x < 8; x = x + 1)
for (int y = 0; y < 8; y = y + 1)
if (board[x, y] == SquareState.gotCheese)
Console.Write("C");
else
Console.Write("*");
It does print out a * if there is no cheese and a C is there is cheese on the board, however its all in a line and doesn't look like a board. Like this:
*****************C*******
This is the structure for the board if its any help
static SquareState[,] board = new SquareState[8, 8];
The fact that it is writing all in line is because you are now telling the console to create a new line. Console.write() just append strings inline with the precedent.
You for cycle should also be an y-first cycle, so you will cycle each horizontal value (x) and then pass to a new vertical one.
for (int y = 0; y < 8; y++){
for (int x = 0; x < 8; x++){
if (board[x, y] == SquareState.gotCheese)
Console.Write("C");
else
Console.Write("*");
}
Console.WriteLine();
}
If you don't swap the cycles your result will be wrong, for example in a 3 by 3 square where x goes from 0 to 2, from left to right and y goes from 0 to 2 from top to bottom, you will have:
External FOR entering x = 0
Internal FOR entering y = 0
writing the 'cell' (0, 0)
Internal FOR entering y = 1
writing the 'cell' (0, 1)
Internal FOR entering y = 2
writing the 'cell' (0, 2)
writing a new line
External FOR entering x = 1
...
The result of this will be:
(0,0)(0,1)(0,2)
(1,0)(1,1)(1,2)
(2,0)(2,1)(2,2)
That is wrong, it should be:
--------------------> x
(0,0)(1,0)(2,0) |
(0,1)(1,1)(2,1) |
(0,2)(1,2)(2,2) |
V y
You need to print a newline after the inner loop but inside the outer loop.
Console.WriteLine("");
for (int x = 0; x < 8; x = x + 1){
for (int y = 0; y < 8; y = y + 1){
if (board[x, y] == SquareState.gotCheese)
Console.Write("C");
else
Console.Write("*");
Console.WriteLine("");
}
}
say array with 12 rows and 10 columns
int[,] array = new int[12,10];
and I select 0,0 it must return all neighbors of 0,0
which will be
0,1
1,1
1,0
say I want neighbors of 2,3 it must return an array of neighbors
1,2
1,3
1,4
2,2
2,4
3,1
3,2
3,3
element [x, y]
neighbor1 = x + 1, y;
neighbor2 = x - 1, y;
neighbor3 = x, y + 1;
neighbor4 = x, y - 1;
neighbor5 = x + 1, y + 1;
neighbor6 = x + 1, y - 1;
neighbor7 = x - 1, y + 1;
neighbor8 = x - 1, y - 1;
Obviously you need to check if those elements coordinates exists just in case the element is in a "border" of the matrix. Hard? I say no.
Braindead and non-performing but illustrative and quick:
int[,] array = new int[12,10];
int refx=0, refy=10;
var neighbours = from x in Enumerable.Range(0,array.GetLength(0)).Where(x => Math.Abs(x - refx)<=1)
from y in Enumerable.Range(0,array.GetLength(1)).Where(y => Math.Abs(y - refy)<=1)
select new {x,y};
neighbours.ToList().ForEach(Console.WriteLine);
alternatively
neighbours = from x in Enumerable.Range(refx-1, 3)
from y in Enumerable.Range(refy-1, 3)
where x>=0 && y>=0 && x<array.GetLength(0) && y<array.GetLength(1)
select new {x,y};
neighbours.ToList().ForEach(Console.WriteLine);