package nyc.angus.wordbrain.util;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class Grids {

	public static void main(String[] args) {
		char[][] grid = createGrid();
		printGrid(grid);

		Set<Position> positionsSeen = new HashSet<>();

		positionsSeen.add(new Position(0, 2));
		positionsSeen.add(new Position(0, 1));

		char[][] newGrid = createNewGrid(grid, positionsSeen);

		System.out.println("");
		printGrid(newGrid);
	}

	public static char[][] createNewGrid(char[][] grid, Set<Position> positionsSeen) {

		char[][] newGrid = cloneArray(grid);

		for (Position position : positionsSeen) {
			newGrid[position.y][position.x] = ' ';
		}

		for (int y = 0; y < grid.length; y++) {
			for (int x = 0; x < grid[0].length; x++) {

				if (newGrid[y][x] == ' ') {
					char prev = ' ';
					for (int i = 0; i <= y; i++) {
						char temp = newGrid[i][x];
						newGrid[i][x] = prev;
						prev = temp;
					}
				}

			}
		}
		return newGrid;
	}

	private static char[][] cloneArray(char[][] original){
		   return Arrays.stream(original)
		             .map((char[] row) -> row.clone())
		             .toArray((int length) -> new char[length][]);
	}

	private static void printGrid(char[][] grid) {
		for (int y = 0; y < grid.length; y++) {
			for (int x = 0; x < grid[0].length; x++) {
				System.out.print(grid[y][x] + " ");
			}
			System.out.println("");
		}
	}

	private static char[][] createGrid() {
		char[][] grid = new char[4][4];
		// y, x
		grid[0][0] = 'p';
		grid[0][1] = 'e';
		grid[0][2] = 'o';
		grid[0][3] = 'r';
		grid[1][0] = 'o';
		grid[1][1] = 'g';
		grid[1][2] = 'b';
		grid[1][3] = 't';
		grid[2][0] = 't';
		grid[2][1] = 'l';
		grid[2][2] = 'e';
		grid[2][3] = 'o';
		grid[3][0] = 'u';
		grid[3][1] = 'e';
		grid[3][2] = 'v';
		grid[3][3] = 'n';
		return grid;
	}
}

package nyc.angus.wordbrain.util;

import java.util.Arrays;
import java.util.Set;

/**
 * Utility for working with 2D grids of characters.
 */
public class Grids {

	/**
	 * Create a new grid, removing the specified grid elements, and dropping any characters above these elements down,
	 * so that the only empty (' ') characters are at the top of the grid. The latter operation is termed 'gravity',
	 * since the remaining letters fall down if there is nothing but space below them.
	 * 
	 * @param grid
	 *        The grid to be changed (a copy is made before alteration, so this isn't changed).
	 * @param positionsToRemove
	 *        The grid positions to remove.
	 * @return A new grid, with the specified grid positions removed, and gravity applied to the remaining elements.
	 */
	public static char[][] removeElementsAndApplyGravity(final char[][] grid, final Set<Position> positionsToRemove) {

		final char[][] newGrid = cloneGrid(grid);

		clearSpecifiedPositions(newGrid, positionsToRemove);

		applyGravity(newGrid);

		return newGrid;
	}

	/**
	 * Clear the specified positions in the grid, replacing the previous character with the ' ' character.
	 */
	private static void clearSpecifiedPositions(final char[][] grid, final Set<Position> positionsToRemove) {
		for (final Position position : positionsToRemove) {
			grid[position.y][position.x] = ' ';
		}
	}

	/**
	 * If there is an empty space (a ' ' char) beneath any item in the grid, drop the character down.
	 * <p>
	 * This operation leaves space only at the top of the grid.
	 * <p>
	 * The grid passed in to this operation is modified.
	 */
	private static void applyGravity(final char[][] newGrid) {
		for (int y = 0; y < newGrid.length; y++) {
			for (int x = 0; x < newGrid[0].length; x++) {

				if (newGrid[y][x] == ' ') {
					char prev = ' ';
					for (int i = 0; i <= y; i++) {
						final char temp = newGrid[i][x];
						newGrid[i][x] = prev;
						prev = temp;
					}
				}

			}
		}
	}

	/**
	 * Clone the provided grid.
	 */
	private static char[][] cloneGrid(final char[][] original) {
		return Arrays.stream(original).map((final char[] row) -> row.clone()).toArray((final int length) -> new char[length][]);
	}

	/**
	 * Pretty print the contents of a grid to standard out.
	 * 
	 * @param grid
	 *        The grid to be printed.
	 */
	public static void printGrid(final char[][] grid) {
		for (final char[] element : grid) {
			for (int x = 0; x < grid[0].length; x++) {
				System.out.print(element[x] + " ");
			}

			System.out.println("");
		}
	}
}

comment (util): add comments