Skip to content

Instantly share code, notes, and snippets.

@satokitty
Created December 9, 2012 17:27
Show Gist options
  • Save satokitty/4246197 to your computer and use it in GitHub Desktop.
Save satokitty/4246197 to your computer and use it in GitHub Desktop.
Coderetreat2012 Lifegame実装例(Java)
package coderetreat.lifegame;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
/**
* 誕生:指定セル 死亡、隣接セル 生存数が3であった場合、次の世代では生存になる
* 維持:指定セル 生存、隣接セル 2 <= 生存数 <= 3の場合、次の世代では生存
* 過疎:指定セル 生存、隣接セル 生存数 < 2の場合、次の世代では死亡
* 過密:指定セル 生存、隣接セル 3 < 生存数の場合、次の世代では死亡
*/
enum Cell {
LIVE {
@Override
public boolean isAliveNextGen(int aliveCount) {
return 1 < aliveCount && aliveCount < 4;
}
},
DEAD {
@Override
public boolean isAliveNextGen(int aliveCount) {
return aliveCount == 3;
}
};
abstract public boolean isAliveNextGen(int aliveCount);
}
class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public Point add(int x, int y) {
return new Point(this.x + x, this.y + y);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Point other = (Point) obj;
if (x != other.x) return false;
if (y != other.y) return false;
return true;
}
}
class Size {
public final int x;
public final int y;
public Size(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Size other = (Size) obj;
if (x != other.x) return false;
if (y != other.y) return false;
return true;
}
}
class Board {
private final Set<Point> alivePoints;
private final Size size;
private final Set<Point> allPoints;
public Board(Size size, Set<Point> alivePoints) {
this.size = size;
this.alivePoints = Collections.unmodifiableSet(alivePoints);
Set<Point> allPoints = new HashSet<Point>();
for (int i = 0; i < size.y; i++) {
for (int j = 0; j < size.x; j++) {
allPoints.add(new Point(j, i));
}
}
this.allPoints = Collections.unmodifiableSet(allPoints);
}
public Board next() {
return new Board(size, nextAlivePoints());
}
private Set<Point> nextAlivePoints() {
Set<Point> next = new HashSet<Point>();
for (Point p : allPoints) {
if (cell(p).isAliveNextGen(aliveNeighbors(p).size())) {
next.add(p);
}
}
return next;
}
private Cell cell(Point point) {
return alivePoints.contains(point) == true ? Cell.LIVE : Cell.DEAD;
}
Set<Point> aliveNeighbors(Point point) {
Set<Point> neighbors = getNeighborPoints(point);
neighbors.retainAll(alivePoints);
return neighbors;
}
Set<Point> getNeighborPoints(Point point) {
Set<Point> neighbors = new HashSet<Point>();
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0) continue;
neighbors.add(point.add(i, j));
}
}
return neighbors;
}
public String toString() {
StringBuilder str = new StringBuilder();
for (int i = 0; i < size.y; i++) {
for (int j = 0; j < size.x; j++) {
str.append(cell(new Point(j, i)) == Cell.LIVE ? "O" : "X");
}
str.append("\n");
}
return str.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((alivePoints == null) ? 0 : alivePoints.hashCode());
result = prime * result + ((size == null) ? 0 : size.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Board other = (Board) obj;
if (alivePoints == null) {
if (other.alivePoints != null) return false;
} else if (!alivePoints.equals(other.alivePoints)) return false;
if (size == null) {
if (other.size != null) return false;
} else if (!size.equals(other.size)) return false;
return true;
}
public static Board buildBoard(Size size, Point... alivePoints) {
return new Board(size, new HashSet<Point>(Arrays.asList(alivePoints)));
}
}
@RunWith(Enclosed.class)
public class LifeGameTest {
public static class CellTest {
@Test
public void LIVEの場合近傍セルの生存数が1以下の場合次世代では死亡() throws Exception {
assertThat(Cell.LIVE.isAliveNextGen(1), is(false));
}
@Test
public void LIVEの場合近傍セルの生存数が4以上の場合次世代では死亡() throws Exception {
assertThat(Cell.LIVE.isAliveNextGen(4), is(false));
}
@Test
public void LIVEの場合近傍セルの生存数が2または3の場合次世代では生存() throws Exception {
assertThat(Cell.LIVE.isAliveNextGen(2), is(true));
assertThat(Cell.LIVE.isAliveNextGen(3), is(true));
}
@Test
public void DEADの場合近傍セルの生存数が3の場合次世代では生存() throws Exception {
assertThat(Cell.DEAD.isAliveNextGen(3), is(true));
}
@Test
public void DEADの場合近傍セルの生存数が3以外の場合次世代では死亡() throws Exception {
assertThat(Cell.DEAD.isAliveNextGen(2), is(false));
assertThat(Cell.DEAD.isAliveNextGen(4), is(false));
}
}
public static class PointTest {
@Test
public void Point同士で比較できる_同値の場合true() throws Exception {
Point sut1 = new Point(0, 1);
Point sut2 = new Point(0, 1);
assertThat(sut1, is(sut2));
}
@Test
public void Point同士で比較できる_同値でない場合false() throws Exception {
Point sut1 = new Point(0, 1);
Point sut2 = new Point(1, 0);
assertThat(sut1, is(not(sut2)));
}
@Test
public void addメソッドでオフセットを加算したPointオブジェクトを取得できる() throws Exception {
Point sut = new Point(2, 3);
Point actual = sut.add(1, 2);
Point expected = new Point(3, 5);
assertThat(actual, is(expected));
}
@Test
public void addメソッドに負の値を指定することもできる() throws Exception {
Point sut = new Point(2, 3);
Point actual = sut.add(-2, -3);
assertThat(actual, is(new Point(0, 0)));
}
}
public static class BoardTest {
@Test
public void buildBoardメソッドでボードを生成できる() throws Exception {
// given
Size size = new Size(3, 3);
// when
Board board = Board.buildBoard(size, new Point(0, 0), new Point(0, 1), new Point(1, 0));
// then
assertThat(board.toString(), is("OOX\nOXX\nXXX\n"));
}
@Test
public void 与えたサイズと生存セルの座標でボードを作る() throws Exception {
// given
Set<Point> alivePoints = new HashSet<Point>(Arrays.asList(
new Point(0, 0), new Point(0, 1), new Point(1, 0)
));
Size size = new Size(3, 3);
// when
Board board = new Board(size, alivePoints);
// then
assertThat(board.toString(), is("OOX\nOXX\nXXX\n"));
}
@Test
public void equalsメソッドでBoardインスタンス同士を値で比較できる() throws Exception {
Board sut1 = Board.buildBoard(new Size(3, 3), new Point(0, 0), new Point(0, 1), new Point(1, 0));
Board sut2 = Board.buildBoard(new Size(3, 3), new Point(0, 0), new Point(0, 1), new Point(1, 0));
assertThat(sut1, is(sut2));
}
@Test
public void nextメソッドで一世代後のボードが取得できる() throws Exception {
// given
/*
* oox
* oxx
* xxx
*/
Board sut = Board.buildBoard(new Size(3, 3), new Point(0, 0), new Point(0, 1), new Point(1, 0));
// when
Board actual = sut.next();
// then
/*
* oox
* oox
* xxx
*/
Board expected = Board.buildBoard(new Size(3, 3),
new Point(0, 0), new Point(0, 1), new Point(1, 0), new Point(1, 1));
assertThat(actual, is(expected));
}
@Test
public void nextメソッドで一世代後のボードが取得できる_2() throws Exception {
// given
/*
* oxx
* oxx
* oxx
*/
Board sut = Board.buildBoard(new Size(3, 3), new Point(0, 0), new Point(0, 1), new Point(0, 2));
// when
Board actual = sut.next();
// then
/*
* xxx
* oox
* xxx
*/
Board expected = Board.buildBoard(new Size(3, 3),
new Point(0, 1), new Point(1, 1));
assertThat(actual, is(expected));
}
@Test
public void aliveNeighborsメソッドで指定したセルを含まない生存している近傍セルを取得() throws Exception {
// given
/*
* OOXX
* OXOX
* XXXX
* XXXX
*/
Board sut = Board.buildBoard(new Size(4, 4),
new Point(0, 0), new Point(0, 1),
new Point(1, 0), new Point(1, 2)
);
// when
Set<Point> actual = sut.aliveNeighbors(new Point(1, 2));
// then
Set<Point> expected = new HashSet<Point>(Arrays.asList(
new Point(0, 1)
));
assertThat(actual, is(expected));
}
@Test
public void aliveNeighborsメソッドで隅を指定した場合_範囲外のセルは無いものとして扱われる() throws Exception {
// given
/*
* OOXX
* OXOX
* XXXX
* XXXX
*/
Board sut = Board.buildBoard(new Size(4, 4),
new Point(0, 0), new Point(0, 1),
new Point(1, 0), new Point(1, 2)
);
// when
Set<Point> actual = sut.aliveNeighbors(new Point(0, 0));
// then
Set<Point> expected = new HashSet<Point>(Arrays.asList(
new Point(0, 1),
new Point(1, 0)
));
assertThat(actual, is(expected));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment