How to get matrix positions surrounded by common data? - java

I have a defined matrix in Java
int[][] a={
{0,0,0,0,0,0},
{0,0,0,1,0,0},
{0,1,1,0,1,0},
{1,0,0,0,0,1},
{0,1,0,1,0,1},
{0,0,1,0,1,0}
};
So I want to know what positions on matrix are surrounded by the lines made of "1" values, i.e., the group of positions with value of "0", as if the "1" were the perimeter of a irregular figure, and "0" values within the perimeter its area (in this case: a[2][3], a[3][1], a[3][2], a[3][3], a[3][4], a[4][2] and a[4][4]).
How can I get these positions automatically?

One way to do what you want is to use flood fill, with no filling across diagonals. This will not help you by itself, but you can fill all regions that are connected to the edges of your array with some non-zero value. The remaining zeros in the array will be the elements that you crave.
Here is a simple implementation of flood fill:
import java.util.ArrayDeque;
import java.awt.Point; // This is probably superfluous, an int[] with two elements would do fine here too
public class Test
{
private static int[][] a = new int[][] {
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0},
{0, 1, 1 ,0, 1, 0},
{1, 0, 0, 0, 0, 1},
{0, 1, 0, 1, 0, 1},
{0, 0, 1, 0, 1, 0}
};
/*
* Applies flood fills all elements accessible from array[row][col] with
* value. If the element at (row, col) is already value, this method does
* nothing.
*/
private static void floodFill(int[][] array, int row, int col, int value)
{
int oldValue = array[row][col];
if(oldValue == value)
return;
ArrayDeque<Point> queue = new ArrayDeque<>();
queue.add(new Point(col, row));
while(queue.size() > 0) {
// Technically, removeLast would be more efficient, especially
// since the order does not matter, but this is just an example
Point point = queue.pop();
int r = point.y;
int c = point.x;
array[r][c] = value;
if(r > 0 && array[r - 1].length > c && array[r - 1][c] == oldValue)
queue.add(new Point(c, r - 1));
if(r < array.length - 1 && array[r + 1].length > c && array[r + 1][c] == oldValue)
queue.add(new Point(c, r + 1));
if(c > 0 && array[r][c - 1] == oldValue)
queue.add(new Point(c - 1, r));
if(c < array[r].length - 1 && array[r][c + 1] == oldValue)
queue.add(new Point(c + 1, r));
}
}
/*
* Walks around the edges of the array and floods everthing connected to
* them with ones. This relies on floodFill exiting early for areas that
* were already filled.
*/
private static void fillEdges(int[][] array)
{
// top row
for(int col = 0; col < array[0].length; col++)
floodFill(array, 0, col, 1);
// left column
for(int row = 0; row < array.length; row++)
floodFill(array, row, 0, 1);
// bottom row
for(int col = 0; col < array[array.length - 1].length; col++)
floodFill(array, array.length - 1, col, 1);
// all trailing row segments (allows for ragged arrays)
for(int row = 1; row < array.length - 1; row++) {
int lengthToFill = array[row].length - Math.min(array[row - 1].length, array[row + 1].length);
lengthToFill = (lengthToFill < 0) ? 1 : lengthToFill + 1;
for(int col = array[row].length - lengthToFill; col < array[row].length; col++)
floodFill(array, row, col, 1);
}
}
public static void main(String[] args)
{
fillEdges(a);
for(int row = 0; row < a.length; row++) {
for(int col = 0; col < a[row].length; col++) {
if(a[row][col] == 0)
System.out.println("[" + row + "][" + col + "]");
}
}
}
}
This particular implementation is nice because it will work for arrays of arbitrary size and shape. I added a bit to check if a point is on the edge of a ragged array as well (comparing the lengths of the rows).
The output is exactly what you expect:
[2][3]
[3][1]
[3][2]
[3][3]
[3][4]
[4][2]
[4][4]

Here is a simple algorithm that uses helper functions to compute the indexes of the predecessor and successor of each element.
public class Test {
public static final int N = 6;
public static int isucc(int i, int j) {
return (i * N + j + 1) / N;
}
public static int jsucc(int i, int j) {
return (i * N + j + 1) % N;
}
public static int ipred(int i, int j) {
return (i * N + j - 1) / N;
}
public static int jpred(int i, int j) {
return (i * N + j - 1) % N;
}
public static void main(String[] args) {
int[][] a={
{0,0,0,0,0,0},
{0,0,0,1,0,0},
{0,1,1,0,1,0},
{1,0,0,0,0,1},
{0,1,0,1,0,1},
{0,0,1,0,1,0}
};
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (i * N + j > 0 && i * N + j < N * N - 1
&& a[ipred(i,j)][jpred(i,j)] == 1
&& a[isucc(i,j)][jsucc(i,j)] == 1) {
System.out.println(i + "," + j);
}
}
}
}
}
It prints:
2,3
2,5
4,0
4,2
4,4
5,3
Note that it can easily be extended to non-square matrices.
Dominique Ubersfeld

Related

Remove a Column from a 2D Array

I have little problem with removing col from a 2d array.
The goal is to remove from every row specific index "2" and give it back.
Its how it need to be
I made it but got little problem with 0 at the end.
Its how I got
private static void removeEntry(int[][] workArray, int col) {
int row = workArray.length;
//largest row count
int max = 0;
int tempNum = 0;
for (int[] ints : workArray) {
tempNum = 0;
for (int j = 0; j < ints.length; j++) {
tempNum++;
if (tempNum > max) {
max = tempNum;
}
}
}
int [][] newArray = new int[row][max];
for(int i = 0; i < row; i++) {
for(int j = 0; j < max; j++) {
if(j < col && j < workArray[i].length) {
newArray[i][j] = workArray[i][j];
}else if (j == col) {
// Do nothing
} else if (j > col && j < workArray[i].length) {
newArray[i][j - 1] = workArray[i][j];
}
}
}
for (int i = 0; i < workArray.length; i++) {
for (int j = 0; j < workArray[i].length; j++) {
workArray[i][j] = newArray[i][j];
}
}
Then I tried to remove 0 but don't work
int remIndex = 0;
for (int i = 0; i < workArray.length; i++) {
for (int j = remIndex; j < workArray[i].length-1; j++) {
if(workArray[i][j] == remIndex){
workArray[i][j] = workArray[i][j + 1];
}
}
}
An array is a container of data that occupies a contiguous block of memory, its size should be defined when the array is being instantiated and can't be changed.
If you need an array of smaller or greater length, then you need to create a new one and copy all previously added elements that should be retained.
There's also no such thing in Java as "2D" arrays, we can create a nested array, i.e. an array containing other arrays.
And similarly to how we can reassign an integer value at a particular index in a plain array int[], we can change a reference in the array of arrays, i.e. we can make it point to another (newly created) array.
And that's what is required according to do in your assignment since the method is void. I.e. the given array needs to be changed by replacing all of its "rows", that greater or equal in length than the given column to remove col, with a new array that will retain all the previous element except for the one at index col.
private static void removeEntry(int[][] workArray, int col) {
for (int row = 0; row < workArray.length; row++) {
if (workArray[row].length <= col) { // no need to change anything
continue;
}
int newLength = workArray[row].length - 1;
int[] newRow = new int[newLength]; // creating a new row shorter by 1
for (int oldCol = 0, newCol = 0; oldCol < workArray[row].length; oldCol++, newCol++) {
if (oldCol == col) { // skipping the target column
newCol--; // newCol would be incremented automatically at the end of the iteration, but we want it to remain the same
continue;
}
newRow[newCol] = workArray[row][oldCol];
}
workArray[row] = newRow; // reassigning the row
}
}
main()
public static void main(String[] args) {
int[][] testArr =
{{1, 2},
{1, 2, 3},
{1, 2, 3, 4}};
removeEntry(testArr, 2);
// printing the testArr
for (int[] arr: testArr) {
System.out.println(Arrays.toString(arr));
}
}
Output:
[1, 2]
[1, 2]
[1, 2, 4]
A link to the Online Demo
If you've made the method to be void by mistake, you are required to return a new array, i.e. the return type int[] (check the requirements of your assignment carefully). Then a minor change needs to be applied to the logic explained and implemented above: every array should be replaced with a new one and then placed into the newly created resulting array.
Note Arrays.copyOf() allows creating a duplicate of the hole array, and System.arraycopy() can help you to copy the elements in the given range from one array into another, but because you are working on an assignment I suggest you to do it manually with loops because you are expected to demonstrate the knowledge on how to manipulate with arrays, not the knowledge of special utility features (unless otherwise specified in the assignment).
private static int[][] removeEntry(int[][] workArray, int col) {
int[][] result = new int[workArray.length][];
for (int row = 0; row < workArray.length; row++) {
int newLength = col < workArray[row].length ? workArray[row].length - 1 : workArray[row].length;
int[] newRow = new int[newLength];
for (int oldCol = 0, newCol = 0; oldCol < workArray[row].length; oldCol++, newCol++) {
if (oldCol == col) {
newCol--;
continue;
}
newRow[newCol] = workArray[row][oldCol];
}
result[row] = newRow; // reassigning the row
}
return result;
}
main()
public static void main(String[] args) {
int[][] testArr =
{{1, 2},
{1, 2, 3},
{1, 2, 3, 4}};
int[][] newArr = removeEntry(testArr, 2);
// printing the testArr
for (int[] arr: newArr) {
System.out.println(Arrays.toString(arr));
}
}
Output:
[1, 2]
[1, 2]
[1, 2, 4]
A link to the Online Demo
Here is my approach on this. I used System.arraycopy() to copy the array up to the removed column and from directly after the removed column to the end. This way, we remove the column completely from the array.
private static int[][] removeEntry(int[][] workArray, int col) {
int[][] resultArray = new int[workArray.length][];
int index = 0;
for (int[] row : workArray) {
if (row.length - 1 < col) {
resultArray[index] = row;
index++;
continue;
}
int[] arrayCopy = new int[row.length - 1];
System.arraycopy(row, 0, arrayCopy, 0, col);
System.arraycopy(row, col + 1, arrayCopy, col, row.length - col - 1);
resultArray[index] = arrayCopy;
index++;
}
return resultArray;
}
Arrays are of fixed size. At the time of initializing array, a default value is stored in it. Here, 0 is stored as default. So I would suggest you to not initialize "col" as "max" but rather do it in for loop like this :-
int [][] newArray = new int[row][];
for(int i = 0; i < row; i++) {
if(col <= workArray[i].length){
newArray[i] = new int[workArray[i].length-1]; //initialize it here
}
for(int j = 0; j < workArray[i].length; j++) {
if(j < col) {
newArray[i][j] = workArray[i][j];
}else if (j == col) {
// Do nothing
} else if (j > col) {
newArray[i][j - 1] = workArray[i][j];
}
}
}
return newArray;
You are also supposed to return modified array as we can't changed the size of array and thus we had to create a new one ( newArray ). So do change the method definition as :-
private static int[][] removeEntry(int[][] workArray, int col)
Finally, whole method would look like :-
private static int[][] removeEntry(int[][] workArray, int col) {
int row = workArray.length;
//largest row count
int [][] newArray = new int[row][];
for(int i = 0; i < row; i++) {
if(col <= workArray[i].length){
newArray[i] = new int[workArray[i].length-1]; //initialize it here
}
for(int j = 0; j < workArray[i].length; j++) {
if(j < col) {
newArray[i][j] = workArray[i][j];
}else if (j == col) {
// Do nothing
} else if (j > col) {
newArray[i][j - 1] = workArray[i][j];
}
}
}
return newArray;
}
and you can use it like :-
workArray = removeEntry(workArray, 2);

Common DFS question "Connect cell" or "find island" but only find rectangular shape

I've just learned an algorithm called DFS and when I watched the videos, the most popular practice or example to use DFS is the Connected Cells or find islands one which is a 2D array with 0 and 1. But I really wish to know if I want the island shape only to be rectangular(or square), what should I do or how can I change the if or for loop in the program. Here's the code I'm looking at:
// No. of rows and columns
static final int ROW = 3, COL = 5;
// A function to check if a given cell (row, col) can
// be included in DFS
boolean isSafe(int M[][], int row, int col,
boolean visited[][])
{
// row number is in range, column number is in range
// and value is 1 and not yet visited
return (row >= 0) && (row < ROW) && (col >= 0) && (col < COL) && (M[row][col] == 1 && !visited[row][col]);
}
// A utility function to do DFS for a 2D boolean matrix.
// It only considers the 8 neighbors as adjacent vertices
void DFS(int M[][], int row, int col, boolean visited[][])
{
// These arrays are used to get row and column numbers
// of 8 neighbors of a given cell
int rowNbr[] = new int[] { -1, -1, -1, 0, 0, 1, 1, 1 };
int colNbr[] = new int[] { -1, 0, 1, -1, 1, -1, 0, 1 };
// Mark this cell as visited
visited[row][col] = true;
// Recur for all connected neighbours
for (int k = 0; k < 8; ++k)
if (isSafe(M, row + rowNbr[k], col + colNbr[k], visited))
DFS(M, row + rowNbr[k], col + colNbr[k], visited);
}
// The main function that returns count of islands in a given
// boolean 2D matrix
int countIslands(int M[][])
{
boolean visited[][] = new boolean[ROW][COL];
int count = 0;
for (int i = 0; i < ROW; ++i)
for (int j = 0; j < COL; ++j)
if (M[i][j] >= 100 && !visited[i][j])
{
DFS(M, i, j, visited);
++count;
}
return count;
}

Symmetric 2D array of random numbers

public static int[][] Matrix(int n, int max, int min) {
int[][] grid = new int[3][3];
Random rand = new Random();
rand.setSeed(System.currentTimeMillis());
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
int value = Math.abs((min + rand.nextInt((max - min) + 1)));
grid[i][j] = value;
grid[j][i] = value;
}
}
return grid;
}
The following code prints a 2D symmetric array where the values are random numbers between a range (min and max) which prints the following result as example:
0 14 11
14 0 17
11 17 0
My problem with the code is it only prints 0 as the diagonal value. How can I change it to print the diagonal values where they are set as int min instead of 0? For example, in the code above int min is 8 hence it would give this result:
8 14 11
14 8 17
11 17 8
If you want to set the diagonal to the lower variable, you need to do two things.
One, because you set j < i, j will never equal i, meaning the diagonal will be set to 0 because Java initializes integers to 0 if they aren't given an explicit initialization value. I was able to access the diagonal by simply changing the < to an <=:
for(int i = 0; i < n; i++)
{
for(int j = 0; j <= i; j++)
{
...
}
}
Two, once i equals j, you need to add an if statement that checks for the case where they're equal. When they are, simply set the current grid cell to the lower variable. Don't forget to enclose the other half of the second for code block with an else block or you'll get unintended behavior:
for(int j = 0; j <= i; j++)
{
if(i == j)
{
grid[i][j] = lower;
}
else
{
...
}
}
Finally, your whole for loop block should look like this:
for(int i = 0; i < n; i++)
{
for( int j = 0; j <= i; j++)
{
if(i == j)
{
grid[i][j] = lower;
}
else
{
int value = Math.abs((lower + rand.nextInt((upper - lower) + 1)));
grid[i][j] = value;
grid[j][i] = value;
}
}
}
You are generating random value for all i and j except when i==j, which are the diagonal values. Also, all the values of the diagonals will be same. So before returning the grid, you can generate one last random value and put it to the diagonals. Something like this
int diagonalValue = Math.abs((min+ rand.nextInt((max- min) + 1)));
for( int k=0 ; k<n ; k++)
{
grid[k][k] = diagonalValue;
}
Code review:
Add invalid syntax checks to the beginning of the method;
Math.abs is redundant;
The inner loop should include the upper bound;
Your code might look something like this:
public static int[][] matrix(int n, int max, int min) {
// incorrect matrix size
if (n <= 0)
return new int[][]{{}};
int[][] grid = new int[n][n];
// incorrect random value bound
if (max - min <= 0)
return grid;
Random rand = new Random();
// interval excluding upper bound
IntStream.range(0, n).forEach(i ->
// interval including upper bound
IntStream.rangeClosed(0, i).forEach(j -> {
if (i == j) {
// main diagonal
grid[i][j] = min;
} else {
// peripheral elements
int value = min + rand.nextInt((max - min) + 1);
grid[i][j] = value;
grid[j][i] = value;
}
}));
return grid;
}
public static void main(String[] args) {
Arrays.stream(matrix(5, 9, 1))
.map(Arrays::toString)
.forEach(System.out::println);
}
Output:
[1, 6, 3, 3, 2]
[6, 1, 9, 4, 2]
[3, 9, 1, 6, 7]
[3, 4, 6, 1, 9]
[2, 2, 7, 9, 1]

Game of life - edges do not change

I saw Conway's Game of Life and wanted to make my own. However the cells at the edges somehow don't follow the rules and just stay alive (or dead) the whole time. Does anybody know where I made the mistake?
This is my code: (I only uploaded the class where I applied the rules. If the other classes are needed to solve the problem, I can upload them as well)
import java.util.Arrays;
/**
* The class Grid does the initialization of the game of life and the application of the rules.
* It is a 2D array of the type Cell. It saves the cells and uses a copy of it to apply the rules.
*
*/
public class Grid
{
public int col;
public int row;
public int x,y;
public Cell [][] array; //2D array of the type Cell
public Cell [][] arraycopy;
/**
* This constructor is to create the initial generation of cells and set the state of random 20% to true (=alive).
* #param col the number of columns
* #param row the number of rows
*
*/
public Grid(int col, int row)
{
this.col = col;
this.row = row;
this.array = new Cell [col][row];
//Loops through every spot in the 2D array
for (int x = 0; x < col; x++)
{
for (int y=0; y < row; y++)
{
//set randomly 20% of the cells' state to "true"
if (Math.random() <= 0.2)
{
Cell cell = new Cell (true);
this.array[x][y]= cell;
}
else
{
Cell cell = new Cell (false);
this.array[x][y]= cell;
}
}
}
}
/**
* This method will count the alive cells in a 3*3 neighboorhood and apply the rules of life.
* This method uses arraycopy.
*
*/
public void lifeSteps()
{
//Works with a copy of the array and the cells
this.arraycopy = new Cell [col][row];
for (int x = 0; x < col; x++)
{
for (int y=0; y < row; y++)
{
this.arraycopy [x][y] = new Cell(this.array[x][y].getState());
}
}
//Looping through the cells, but the cells at the edge are skipped
for (int x = 1; x < col-1; x++)
{
for (int y= 1; y < row-1; y++)
{
//Looping through all the neighbors
int numNeighborsAlive = 0;
for (int i = x-1; i <= x+1; i++)
{
for (int j = y-1; j <= y+1; j++)
{
//In a 3x3 neighborhood the middle cell needs to be skipped
if ((x != i) && (y != j))
{
//Only the cells that are alive (true) are added
if (arraycopy [i][j].getState() == true)
{
numNeighborsAlive += 1;
}
}
}
}
//Apply the rules of life
if ((array [x][y].getState()) && (numNeighborsAlive < 2 || numNeighborsAlive >3)) //Loneliness and Overpopulation
{
array[x][y].setState(false);
}
else if ((array [x][y].getState() == false) && (numNeighborsAlive ==3)) //Birth
{
array[x][y].setState(true);
}
else
{ //stasis
}
}
}
}
/**
* This method will return the statement for the array.
* #return the 2D array of the type Cell
*/
public Cell[][] returnGrid ()
{
return this.array;
}
/**
* This method will test if everything is working well by printing zeros and ones.
*
*/
public void printTest()
{
System.out.println("\t"); // a new line
for (int x = 0; x < col; x++)
{
for (int y=0; y < row; y++)
{
// assigns 1 if the cell is alive and 0 if it is dead
if (array[x][y].getState() == true)
{
System.out.print("1");
}
else
{
System.out.print("0");
}
}
System.out.println(""); // will be displayed as colums and rows
}
System.out.println("\t"); // a new line
}
}
The borders are not processed, so there are always 8 neighbors.
One can handle all array positions, and determine the neighbors. These could be hardwired in the cell at initialisation, or - as below - determined dynamically.
For that I use an offset vector with a delta x and delta y in -1, 0, 1.
private static final int[][] MIDDLE_NEIGHBORS =
{
{-1, -1}, {-1, 0}, {-1, 1},
{0, -1}, {0, 1},
{1, -1}, {1, 0}, {1, 1}
};
private static final int[][] LEFT_TOP_NEIGHBORS =
{
{0, 1},
{1, 0}, {1, 1}
};
...
int[][] neighborDeltaXY(int x, int y, int col, int row) {
if (1 < x && x < col-1 && 1 < y && y < row-1) {
return MIDDLE_NEIGHBORS;
}
if (x == 0 && row == 0) {
return LEFT_TOP_NEIGHBORS;
}
...
}
Or you might be more comfortable with nested conditions:
int[][] neighborDeltaXY(int x, int y, int col, int row) {
if (x == 0) {
if (y == 0) {
return LEFT_TOP_NEIGHBORS;
} else if (y == row - 1) {
return ...;
} else {
return ...;
}
} else if (x == col - 1) {
if (y == 0) {
return ...;
} else if (y == row - 1) {
return ...;
} else {
return ...;
}
} else {
if (y == 0) {
return ...;
} else if (y == row - 1) {
return ...;
} else {
return MIDDLE_NEIGHBORS;
}
}
}
Useful is to have a method doing the actual counting on the board:
int countNeighborsAlive(Cell[][] old, int x, int y, int col, int row) {
int numNeighborsAlive = 0;
int[][] neighbors = neighborDeltaXY(x, y, col, row);
for (int[] neighbor : neighbors) {
int xn = x + neighbor[0];
int yn = y + neighbor[1];
if (old[xn][yn].getState()) {
++numNeighborsAlive;
}
}
return numNeighborsAlive;
}
So the time loop becomes simpler:
for (int x = 0; x < col; x++) {
for (int y= 0; y < row; y++) {
int numNeighborsAlive = countNeighborAlive(arraycopy, x, y, col, row);
... numNeighborsAlive
In the game of life one could make different geometries, having above y == 0 the y == row - 1, so the world wraps around the borders.
Also feasible is to take the original board and place it in a larger grid, so the visible cells are in [1, col - 1), [1, row - 1). The invisible borders then always remain 0. Not so nice for the game of life, but other grid based games are so walled in.
Instead Do Or
x += 1; ++x; x++
if (c == true) if (c)
if (d == false) if (!d)

Knight's Tour recursive method in Java, code execution is stuck on the 5th move (on a 25 square board)?

Since the board is 5x5 there should be 25 moves.
I used a print statement to verify that the recursive method only runs 5 times successfully.
When it gets to the fifth move in the last row it doesn't keep going, even though there are 4 valid moves from that position. It's able to change direction horizontally after hitting the right-most column.
I'm not sure why it can't recover from reaching the bottom row.
public class KnightsTour {
public boolean isSafe(int[][] board, int y, int x) {
if (y >= 0 && x >= 0 && y < board.length && x < board.length) {
return true;
}
return false;
}
public boolean knightsTour(int[][] board, int y, int x, int move) {
if (board[y][x] != 0) {
// already been here
return false;
}
System.out.println("Move " + move + " happened!");
board[y][x] = move;
move++;
if (move == (board.length * board.length)) {
// board is full, you completed the tour, end game
return true;
}
int[][] moves =
{
{1, 2},
{1, -2},
{-1, 2},
{-1, -2},
{2, 1},
{2, -1},
{-2, -1},
{-2, 1}
};
for (int i = 0; i < moves.length; i++) {
if (isSafe(board, y + moves[i][0], x + moves[i][1])) {
return knightsTour(board, y + moves[i][0], x + moves[i][1], move);
}
}
// if the board isn't full and there are no valid moves you can make
// from here then this is not a part of the valid solution
board[y][x] = 0;
return false;
}
public static void main(String[] args) {
KnightsTour tour = new KnightsTour();
int[][] board = new int[5][5];
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
board[i][j] = 0;
}
}
tour.knightsTour(board, 0, 0, 1);
// print board
System.out.println("Board:");
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
System.out.print(board[i][j] + "\t");
}
System.out.println("");
}
}
}
I believe your problem lies in this section of code:
for (int i = 0; i < moves.length; i++) {
if (isSafe(board, y + moves[i][0], x + moves[i][1])) {
return knightsTour(board, y + moves[i][0], x + moves[i][1], move);
}
}
For the first 'isSafe' move, you send the knight there, and if it has already been, you will fully return out false from the Tour. You should either modify this section to continue checking the moves if the tour fails, or modify your 'isSafe' method to say that board positions of non-zero are not actually safe.

Categories