/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ public class Percolation { private final WeightedQuickUnionUF smartField; private final int N; private boolean[][] isOpened; private boolean[] connectedToBottom; private boolean myPercolates = false; public Percolation(int N) { if (N <= 0) { throw new IllegalArgumentException(); } this.N = N; isOpened = new boolean[N + 2][N + 2]; for (int i = 0; i < N + 2; i++) { for (int j = 0; j < N + 2; j++) { isOpened[i][j] = false; } } smartField = new WeightedQuickUnionUF(N * N + 2); for (int i = 1; i <= N; i++) { smartField.union(0, i); } connectedToBottom = new boolean[N * N + 1]; for (int i = N * (N - 1) + 1; i <= N * N; i++) { connectedToBottom[smartField.find(i)] = true; } } public void open(int i, int j) { assertBounds(i, j); isOpened[i][j] = true; int smartCoord = getPlainCoordinates(i, j); if (isOpened[i - 1][j]) unionGroups(smartCoord, smartCoord - N); if (isOpened[i + 1][j]) unionGroups(smartCoord, smartCoord + N); if (isOpened[i][j - 1]) unionGroups(smartCoord, smartCoord - 1); if (isOpened[i][j + 1]) unionGroups(smartCoord, smartCoord + 1); if (connectedToBottom(smartField.find(smartCoord)) && isFull(i, j)) { myPercolates = true; } } private void unionGroups(int first, int second) { int firstGroupId = smartField.find(first); int secondGroupId = smartField.find(second); if (connectedToBottom(firstGroupId)) { setConnectedToBottom(secondGroupId); } else if (connectedToBottom(secondGroupId)) { setConnectedToBottom(firstGroupId); } smartField.union(first, second); } private void setConnectedToBottom(int secondGroupId) { connectedToBottom[secondGroupId] = true; } private boolean connectedToBottom(int firstGroupId) { return connectedToBottom[firstGroupId]; } public boolean isOpen(int i, int j) { assertBounds(i, j); return isOpened[i][j]; } public boolean isFull(int i, int j) { assertBounds(i, j); int coord = getPlainCoordinates(i, j); return isOpen(i, j) && smartField.connected(0, coord); } private int getPlainCoordinates(int i, int j) { return (i - 1) * N + j; } public boolean percolates() { return myPercolates; } private void assertBounds(int i, int j) { boolean inBounds = (i > 0 && i <= N) && (j > 0 && j <= N); if (!inBounds) { throw new IndexOutOfBoundsException("i: " + i + " j: " + j + " max N: " + N); } } }