How to simplify block of multiple repetitive If statements?
Array size/shape agnostic, takes care of edge cases automagically, call with player identifier, position, and current array, returns changed array:
fn = With[{cv = #1, cp = #2, cm = #3},
ReplacePart[cm, Select[Position[cm, cv], ChessboardDistance[#, cp] <= 1 &] -> 0]] &;
Use example:
fn[a, {5, 3}, mat]
Completely different approach, so I'm making it a separate answer:
board[[row - 1 ;; row + 1, col - 1 ;; col + 1]] =
board[[row - 1 ;; row + 1, col - 1 ;; col + 1]] /. clicked -> 0;
This has the advantage of only updating the neighbourhood of the clicked cell instead of mapping a function over the entire grid. I also think it's quite clear and readable. Here is how it works, with the example of row = col = 4
. We extract the neighbourhood of the clicked cell:
{{a, b, 0},
{a, a, 0},
{0, 0, 0}}
Then we replace the value that was clicked with 0
:
{{0, b, 0},
{0, 0, 0},
{0, 0, 0}}
And then we write this patch of the board back into the correct position:
{{0, 0, 0, 0, 0, 0},
{0, a, a, b, 0, 0},
{0, a, 0, b, 0, 0},
{0, b, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0}}
Note that this code, like yours, will fail if the clicked cell is on the boundary of the grid, but this can be fixed via some Min
and Max
operations on the grid indices. In that case, you'll probably want to save the Span
s in two variables so you don't have to write them twice.
Here is one way to do it, although I feel like there is probably an even more elegant solution:
MapIndexed[
If[
# === clicked
&& ChessboardDistance[#2, {row, col}] <= 1,
0,
#
] &,
board,
{2}
]
E.g. with row = col = 4
on your above example you'd get:
{{0, 0, 0, 0, 0, 0},
{0, a, a, b, 0, 0},
{0, a, 0, b, 0, 0},
{0, b, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0}}
MapIndexed
is like Map
except that the mapped function takes a second parameter which is a list of indices of the current element. We simply check whether that index is in the Moore neighbourhood of distance 1 from {row, col}
in addition to the equality check with clicked
.
Of course, this is somewhat less efficient than your current method for large boards, since the function is mapped over the entire board. If you're working with huge boards, this is probably not ideal. Otherwise, the runtime is going to be negligible either way.