import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.Random;


public class Sample123 {
	public static void main(String[] args) {
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter("result.txt"));

			long start = System.currentTimeMillis();
			Iterator<String> ite = new MazeLineIterator(4, 5, 6);
			while (ite.hasNext()) {
				writer.append(ite.next());
				writer.newLine();
			}
			long end = System.currentTimeMillis();

			writer.close();
			System.out.println("elapse: " + (end - start) + "(ms)");
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
}

class MazeLineIterator implements Iterator<String> {
	public static final String WALL_CHAR = "■";
	public static final String SPACE_CHAR = "　";

	private static final int WALL_AREA = 0;

	private final Random random_;

	private long line_ = -1;
	private boolean oddLine_ = false;	// oddLine_ == true の時が通路の行、falseの時が柱の行
	private int counter_ = 1;

	private final int maxCol_;
	private final long maxRow_;
	private final int[] mazeLine_;

	public MazeLineIterator(int col, long row) {
		maxCol_ = col;
		maxRow_ = row;
		mazeLine_ = new int[col * 2 + 1];
		random_ = new Random();
	}
	public MazeLineIterator(int col, long row, long seed) {
		maxCol_ = col;
		maxRow_ = row;
		mazeLine_ = new int[col * 2 + 1];
		random_ = new Random(seed);
	}


	public boolean hasNext() {
		return (line_ < maxRow_);
	}

	public String next() {
		if (line_ < 0 || (line_ == maxRow_ - 1 && !oddLine_)) {
			for (int index = 0; index < mazeLine_.length; index++) {
				mazeLine_[index] = WALL_AREA;
			}
		} else {
			if (oddLine_) {
				createOddLine();
			} else {
				createEvenLine();
			}
		}

		if (!oddLine_) line_++;
		oddLine_ = !oddLine_;
		return createDisplay(mazeLine_);
	}

	private String createDisplay(int[] line) {
		StringBuilder builder = new StringBuilder(line.length);
		for (int index: line) {
			//builder.append(index);
			builder.append(isWall(index)? WALL_CHAR: SPACE_CHAR);
		}
		return builder.toString();
	}


	private void createOddLine() {
		int area = 0;
		for (int index = 0; index < maxCol_; index++) {
			int lastArea = mazeLine_[index * 2 + 1];
			if (isWall(lastArea)) {
				if (isWall(area)) {
					area = counter_++;
				}
				mazeLine_[index * 2 + 1] = area;
			} else {
				if (!isWall(area)) {
					if (area == lastArea) {
						mazeLine_[index * 2] = WALL_AREA;
					} else {
						area = replaceArea(area, lastArea);
					}
				} else {
					area = lastArea;
				}
			}

			if (index > 0 && line_ == maxRow_ - 1) {
				if (mazeLine_[index * 2 + 1] != mazeLine_[index * 2 - 1]) {
					area = replaceArea(mazeLine_[index * 2 - 1], mazeLine_[index * 2 + 1]);
					mazeLine_[index * 2] = area;
				}
			}
			if (index == maxCol_ - 1) break;
			if (random_.nextBoolean()) {
				area = WALL_AREA;
			}
			mazeLine_[(index + 1) * 2] = area;
		}
	}

	private void createEvenLine() {
		for (int index = 0; index < maxCol_; index++) {
			int lastArea = mazeLine_[index * 2 + 1];
			if (searchArea(lastArea, index * 2 + 1) && random_.nextBoolean()) {
				mazeLine_[index * 2 + 1] = WALL_AREA;
			}
			mazeLine_[(index + 1) * 2] = WALL_AREA;
		}
	}

	private boolean isWall(int area) {
		return (area == WALL_AREA);
	}
	private int replaceArea(int oldArea, int newArea) {
		if (oldArea < newArea) {
			return replaceArea(newArea, oldArea);
		}
		for (int index = 0; index < mazeLine_.length; index++) {
			if (mazeLine_[index] == oldArea) {
				mazeLine_[index] = newArea;
			}
		}
		if (oldArea == counter_) {
			counter_--;
		}
		return newArea;
	}

	private boolean searchArea(int area, int excludeIndex) {
		for (int index = 0; index < mazeLine_.length; index++) {
			if (index == excludeIndex) continue;
			if (mazeLine_[index] == area) return true;
		}
		return false;
	}

	public void remove() {
		throw new UnsupportedOperationException();
	}
}