how to mathematically have array border without actually increasing the array size? - arrays

So I have a game board represented by a 1d array of 64 squares and I wish to know when a piece is trying to escape the borders.
So for example:
Assume a king in the game of chess is on the X:
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 X 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
it is easy to calculate the attacked squares with a direction vector:
-9, -8, -7,
-1, 1,
7, 8, 9
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0
0 0 0 1 X 1 0 0
0 0 0 1 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
also if he is on the upper or lower edges of the board:
I just add an if that checks if the square + directionvector[i] > 63 or
square + directionvector[i] < 0
so:
0 0 0 1 X 1 0 0
0 0 0 1 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 0 0 0 0 0 0
The problem then comes when it sits on the side edges:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1
1 0 0 0 0 0 1 X
1 0 0 0 0 0 1 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
This is what will happen it will "jump" to the wrong place as you see above.
Do you know of any way of checking this?
thanks

At the beginning of your program, you can precompute the legal moves for every piece and every square and store them somewhere.
Assuming that your squares are numbered from 0 to 63, then KING_MOVES[i] will store the legal moves for a king on square i (where i ranges from 0 to 63). For example, KING_MOVES[0] = { 1, 8, 9 } and KING_MOVES[31] = { 22, 23, 30, 38, 39 }. Similarly, for a knight in the corner, KNIGHT_MOVES[0] = { 10, 17 }.
0 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63
The number of legal moves is different from every square (a king has 8 moves in the center, but only 3 in the corner). You can store the number of legal moves separately (such as NUM_KING_MOVES[31] = 5) or you can terminate each list with a special value like -1 or 64.
To precompute these lists, you can convert each 1-D number to a pair of (row, column) coordinates and generate moves naively, with boundary checks. For a king on square 31, you convert 31 to (row 3, column 7). When moving to the right, you end up on (row 3, column 8), which is illegal, so you discard this move. When moving to the top-left, you end up on (row 2, column 6), which is legal, so you convert that back to a 1-D representation: 2 * 8 + 6 = 22. You append this move to KING_MOVES[31] and so forth.
This gives you the best of both worlds: faster and shorter code for move generation with no wasted memory on every board due to padding. The downside is a few kilobytes of extra memory.
If you're going down this path, you could also take a look at bitboards for even faster move generation.

You could get the row number from the cell index as i / 8 (floored), and use that to check if e.g. a step to the right or left passed to another row.
E.g. here, on a four-column board, stepping to the "right" from position 7, we go to position 8. The row numbers for these are 7 / 4 = 1 and 8 / 4 = 2, so we changed to another row.
....
...7
8...
....
But that's harder to do for diagonal moves, because you expect them to change the row. In the end, this is pretty much just turning the board into a 2D array, and the step offsets into 2D values, where you can check for overflow in the obvious way.
IMO, in principle what you're asking is impossible for a 1D board. With the board defined as a 1D vector (and similarly, the offsets as 1D offsets), then there are no edges within the board, and nothing to escape. Instead of this:
.ab.
....
...c
d...
you really just have this:
.ab........cd...
And it's obvious that c and d are just as adjacent to each other as a and b are.

Related

Why does summing the rows in this matrix give me 0?

I created an array A by first using the command A = [1:10]'.
Then I created a 10x10 matrix, only containing 0's. I then overwrote this matrix with my A, resulting in this new matrix:
A =
1 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0
10 0 0 0 0 0 0 0 0 0
Now the problem is, when I run the command sum((A(1,1)):(A(1,end))), I keep getting 0 when I should be getting 1, as it is the sum of the first row. I tried running the same command on other matrices and they give me the correct answer, so why isn't it working here?
The term
(A(1,1)):(A(1,end))
creates and empty array, as A(1,1) = 1 and A(1,end) = 0 which makes it impossible for colon : to create a vector, so the sum over it is zero. But its not what you want anyway, I guess.
What you supposedly want is
sum(A(1,:))
or in respect to whole matrix, by specifying the dimension of the sum, e.g.
sum(A,2)
ans =
1
2
3
4
5
6
7
8
9
10
Edit
If you want to start from a different column index you can do the following:
sum( A(rowIndex,firstColumnIndex:lastColumnIndex) )
while end can be used as macro variable for the last index of the corresponding column or row.

Replacing specific elements in a table with a specific element from a range in APLX

I'm learning a spread of programming languages in a class, and we're working on an APLX project at the moment. A restriction we have to work around is we cannot use If, For, While, etc. No loops or conditionals. I have to be able to take a plane of numbers, ranging 0-7, and replace each number 2 or greater into the depth of that number, and, ideally, change the 1's to 0's. For example:
0100230 => 0000560
I have no idea how I'm supposed to do the replacement with depth aspect, though the change from ones to zeros is quite simple. I'm able to produce the set of integers in a table and I understand how to replace specific values, but only with other specific values, not values that would have to be determined during the function. The depth should be the row depth, rather than the multi-dimensional depth.
For the record this is not the whole of the program, the program itself is a poker dealing and scoring program. This is a specific aspect of the scoring methodology that my professor recommended I use.
TOTALS„SCORE PHAND;TYPECOUNT;DEPTH;ISCOUNT;TEMPS;REPLACE
:If (½½PHAND) = 0
PHAND„DEAL PHAND
:EndIf
TYPECOUNT„CHARS°.¹PHAND
DEPTH„2Þ(½TYPECOUNT)
REPLACE „ 2 3 4 5 6 7
ISCOUNT „ +/ TYPECOUNT
ISCOUNT „ ³ISCOUNT
((1=,ISCOUNT)/,ISCOUNT)„0
©((2=,ISCOUNT)/,ISCOUNT)„1
©TEMPS „ ISCOUNT
Œ„ISCOUNT
Œ„PHAND
You may have missed the first lessons of your prof and it might help to look at at again to learn about vectors and how easy you can work with them - once you unlearned the ideas of other programming languages ;-)
Assume you have a vector A with numbers from 1 to 7:
A←⍳7
A
1 2 3 4 5 6 7
Now, if you wanted to search for values > 3, you'd do:
A>3
0 0 0 1 1 1 1
The result is a vector, too, and you can easily combine the two in lots of operations:
multiplication to only keep values > 0 and replace others with 0:
A×A>3
0 0 0 4 5 6 7
or add 500 to values >3
A+500×A>3
1 2 3 504 505 506 507
or, find the indices of values > 3:
(A>3)×⍳⍴A
0 0 0 4 5 6 7
Now, looking at your q again, the word 'depth' has a specific meaning in APL and I guess you meant something different. Do I understand correctly that you want to replace values > 2 with the ' indices' of these values?
Well, with what I've shown before, this is easy:
A←0 1 0 0 2 3 0
(A≥2)×⍳⍴A
0 0 0 0 5 6 0
edit: looking at multi-dimensional arrays:
let's look into this example:
A←(⍳5)∘.×⍳10
A
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
Now, which numbers are > 20 and < 30?
z←(A>20)∧A<30
z
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 1 1 1 0
0 0 0 0 0 1 1 0 0 0
0 0 0 0 1 0 0 0 0 0
Then, you can multiply the values with that boolean result to filter out only the ones satisfying the condition:
A×z
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 21 24 27 0
0 0 0 0 0 24 28 0 0 0
0 0 0 0 25 0 0 0 0 0
Or, perhaps you're interested in the column-index of the values?
z×[2]⍳¯1↑⍴z
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 7 8 9 0
0 0 0 0 0 6 7 0 0 0
0 0 0 0 5 0 0 0 0 0
NB: this statement might not work in all APL-dialects. Here's another way to formulate this:
z×((1↑⍴z)⍴0)∘.+⍳¯1↑⍴z
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 7 8 9 0
0 0 0 0 0 6 7 0 0 0
0 0 0 0 5 0 0 0 0 0
I hope this gives you some ideas to play with. In general, using booleans to manipulate arrays in mathematical operations is an extremely powerful idea in APL which will take you loooooong ways ;-)
Also, if you'd like to see more of the same, have a look at the FinnAPL Idioms - some useful shorties grown over the years ;-)
edit re. "maintaining untouched values":
going back to example array A:
A←(⍳5)∘.×⍳10
A
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
Replacing values between 20 and 30 with the power 2 of these values, keeping all others unchanged:
touch←(A>20)∧A<30
(touch×A*2)+A×~touch
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 441 576 729 30
4 8 12 16 20 576 784 32 36 40
5 10 15 20 625 30 35 40 45 50
I hope you get the idea...
Or better: ask a new q, as otherwise this would truly take epic dimensions, whereas the idea of stackoverflow is more like "one issue - one question"...

How does this Matlab/Octave code create a Boolean matrix from a vector?

The first line of code creates some vector with "discrete labels", and the second line of code creates a sparse matrix with ones at the index that the label represents. "eye" creates an identity matrix, but then even if the vector "a" is much longer, this effect of creating a sparse matrix still works!?
Could you please help me understand what is going on?
octave:4> a = [1 3 5 7 9 2 4 6 8 10]
a =
1 3 5 7 9 2 4 6 8 10
octave:5> eye(10)(a,:)
ans =
Permutation Matrix
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 1
The notation eye(10)(a,:) in Octave means: build the size-10 identity matrix (eye(10)) and then pick its rows in the order given by a (note that a is used as the first index, which corresponds to rows, and : as second index, which means "take all columns"). So, for example, the 4th row of the result is row 7 of the identity matrix, because the 4th entry of a contains 7.
From this explanation it's clear that a can be as long as you want, provided that all its values are integers in the range 1...10 (these are the rows available in eye(10)).
Note that in Matlab this "chained" indexing is not allowed. You would have to first assign eye(10) to a variable, and then index into that variable:
m = eye(10);
m(a,:)
Lastly, a minor "technical" note: the obtained matrix is not of type logical (Matlab's Boolean data type), nor is it sparse. Rather, it's a full matrix of type double.

matlab matrix from array

I have large array. Now I need a matrix with 8 elements in every row. My array looks like this:
A= Columns 1 through 18
0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0
Columns 19 through 36
0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0
and so on. How I can get [nx8] matrix? For example:
B=[0 0 0 0 0 0 0 0
0 0 1 1 0 1 1 1
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0]
I've tried reshape, but it didn't work correctly. I get one 1 where shouldn't be.
B=reshape(A,[],8)
You almost have it. The problem is that Matlab fills the matrix column-wise, whereas you seem to want it filled row-rise. So create an 8-row matrix and then transpose:
reshape(A,8,[]).'
What about vec2mat
vec2mat
vec2mat(A,8)

Assign sequential number to integer element in array

Good morning/afternoon~
I have an array like this,
A= [12 0 0 0 0 3 0 0 0 66 0 0 0 0 20 0 0 2 0 31 0 0 42 0 32 0 38]
the output should be:
B= [ 1 0 0 0 0 2 0 0 0 3 0 0 0 0 4 0 0 5 0 6 0 0 7 0 8 0 9]
What should I do to replace the non-zero elements in A with sequential number?
This will do it:
A(A ~= 0) = 1:nnz(A)
A(ismember(A,A(A(:) ~=0))) = 1:numel(A(A(:) ~=0))
With the image processing toolbox (will give the same label to adjacent non-zero values, though):
B = bwlabel(A)
B = cumsum(A ~= 0) .* (A ~= 0);

Resources