package org.goplayer.game;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.goplayer.go.Goban;
import org.goplayer.go.Stone;
import org.goplayer.go.StoneColor;
import org.goplayer.util.Coord;

public class Block implements Iterable<Stone> {
	private final Set<Stone> stones;
	private final Set<Coord> liberties;

	private Block(Collection<Stone> stones, Collection<Coord> liberties) {
		this.stones = Collections.unmodifiableSet(new HashSet<Stone>(stones));
		this.liberties = Collections.unmodifiableSet(new HashSet<Coord>(
				liberties));
	}

	public Collection<Stone> getStones() {
		return stones;
	}

	public Integer size() {
		return getStones().size();
	}

	public StoneColor getColor() {
		return stones.iterator().next().getColor();
	}

	public Set<Coord> getLiberties() {
		return liberties;
	}

	public boolean contains(Stone stone) {
		return stones.contains(stone);
	}

	public static Block generateFrom(Goban goban, Coord start) {
		return generateFrom(goban, start.getRow(), start.getCol());
	}

	public static Block generateFrom(Goban goban, int startRow, int startCol) {
		final Stone reference = goban.getCoordContent(startRow, startCol);
		if (reference == null) {
			throw new IllegalArgumentException("No stone is at "
					+ new Coord(startRow, startCol));
		} else {
			final List<Stone> stones = new ArrayList<Stone>();
			final List<Coord> liberties = new ArrayList<Coord>();
			final List<Coord> check = new ArrayList<Coord>();
			final Set<Coord> explored = new HashSet<Coord>();
			for (int row = 0; row < goban.getRowCount(); row++) {
				explored.add(new Coord(row, -1));
				explored.add(new Coord(row, goban.getColCount()));
			}
			for (int col = 0; col < goban.getColCount(); col++) {
				explored.add(new Coord(-1, col));
				explored.add(new Coord(goban.getRowCount(), col));
			}

			check.add(new Coord(startRow, startCol));
			StoneColor refColor = reference.getColor();
			while (!check.isEmpty()) {
				Coord coord = check.remove(0);
				int row = coord.getRow();
				int col = coord.getCol();
				Stone stone = goban.getCoordContent(row, col);
				if (stone == null) {
					liberties.add(coord);
				} else if (stone.getColor() == refColor) {
					stones.add(stone);
					explored.add(coord);
					check.add(new Coord(row + 1, col));
					check.add(new Coord(row - 1, col));
					check.add(new Coord(row, col + 1));
					check.add(new Coord(row, col - 1));
					check.removeAll(explored);
				} else {
					continue;
				}
			}
			return new Block(stones, liberties);
		}
	}

	@Override
	public Iterator<Stone> iterator() {
		return stones.iterator();
	}
}

@@ -333,16 +333,56 @@
 l.Coord;
+%0Aimport org.goplayer.util.StoneIterator;
 %0A%0Apublic
@@ -2701,16 +2701,865 @@
 %09%09%7D%0A%09%7D%0A%0A
+%09public static Set%3CBlock%3E getAllBlocks(Goban goban) %7B%0A%09%09Set%3CBlock%3E blocks = getAllBlocks(goban, StoneColor.BLACK);%0A%09%09blocks.addAll(getAllBlocks(goban, StoneColor.WHITE));%0A%09%09return blocks;%0A%09%7D%0A%0A%09public static Set%3CBlock%3E getAllBlocks(Goban goban, StoneColor color) %7B%0A%09%09final Set%3CBlock%3E blocks = new HashSet%3CBlock%3E();%0A%09%09StoneIterator iterator = new StoneIterator(goban, color);%0A%09%09while (iterator.hasNext()) %7B%0A%09%09%09Stone stone = (Stone) iterator.next();%0A%09%09%09if (isStoneInAllBlocks(stone, blocks)) %7B%0A%09%09%09%09continue;%0A%09%09%09%7D else %7B%0A%09%09%09%09Block block = generateFrom(goban, goban.getStoneCoord(stone));%0A%09%09%09%09blocks.add(block);%0A%09%09%09%7D%0A%09%09%7D%0A%09%09return blocks;%0A%09%7D%0A%0A%09private static boolean isStoneInAllBlocks(Stone stone, Set%3CBlock%3E blocks) %7B%0A%09%09for (Block block : blocks) %7B%0A%09%09%09if (block.contains(stone)) %7B%0A%09%09%09%09return true;%0A%09%09%09%7D else %7B%0A%09%09%09%09continue;%0A%09%09%09%7D%0A%09%09%7D%0A%09%09return false;%0A%09%7D%0A%0A
 %09@Overri

Add methods to get packages of blocks from a goban.