ライフゲーム
Posted feedbacks - Java
Swingで。特に工夫はなし。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | import java.awt.*;
import java.util.Random;
import java.util.concurrent.*;
import javax.swing.*;
public class Life extends JFrame {
private boolean[] cells;
private final int pitch, w, h;
public static void main(String[] args) {
Life f = new Life(20, 20, 0.3);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public Life(final int w, final int h, final double rate) {
super("Life");
this.w = w;
this.h = h;
pitch = 5;
cells = new boolean[h*w];
initialize(rate);
getContentPane().add(new JLabel(new Icon() {
public int getIconHeight() { return h * pitch + pitch; }
public int getIconWidth() { return w * pitch + pitch; }
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.BLUE);
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
if(cells[at(i, j)]) g.fillRect(j*pitch, i*pitch, pitch, pitch);
}
}));
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
public void run() {
update();
repaint();
}
}, 1000L, 200L, TimeUnit.MILLISECONDS);
}
private void initialize(double rate) {
final Random random = new Random(System.currentTimeMillis());
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
cells[at(i, j)] = random.nextDouble() < rate;
}
private int at(int i, int j) {
return i*w + j;
}
protected void update() {
boolean[] newG = cells.clone();
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
newG[at(i,j)] = next(i, j);
cells = newG;
}
private boolean next(int i, int j) {
final int u = (i+h-1)%h, d = (i+1)%h, l = (j+w-1)%w, r = (j+1)%w;
int count = 0;
if(cells[at(u, j)]) count++;
if(cells[at(u, r)]) count++;
if(cells[at(i, r)]) count++;
if(cells[at(d, r)]) count++;
if(cells[at(d, j)]) count++;
if(cells[at(d, l)]) count++;
if(cells[at(i, l)]) count++;
if(cells[at(u, l)]) count++;
return ((cells[at(i, j)] && (count == 2 || count == 3)) ||
(!cells[at(i, j)] && count == 3));
}
}
|
そのままだとつまらないので、再帰で書いてみました。 実行結果(3世代抜粋) ------------------------------------ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□■□□□ □□□□□■□□□□ □□□□□■■■□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□■□■□□ □□□□□■■□□□ □□□□□□■□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□□□□□□ □□□□□■□□□□ □□□□□■□■□□ □□□□□■■□□□ □□□□□□□□□□ □□□□□□□□□□ ------------------------------------
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | public class LifeGame {
private static class World {
private static class Cell {
private final Cell[] mAdjoiningCells = new Cell[8];
private int mGeneration = 0;
private boolean mIsOddLive = false;
private boolean mIsEvenLive = false;
public boolean next(int aGeneration) {
boolean tIsLive = (aGeneration & 1) == 0 ? mIsEvenLive : mIsOddLive;
if (aGeneration == mGeneration) {
return tIsLive;
}
mGeneration++;
int tLiveCells = 0;
for (int i = 0; i < 8; i++) {
tLiveCells += mAdjoiningCells[i].next(aGeneration) ? 1 : 0;
}
boolean tNext = tLiveCells == 3 ? true : tLiveCells == 2 ? tIsLive : false;
if ((aGeneration & 1) == 0) {
mIsOddLive = tNext;
} else {
mIsEvenLive = tNext;
}
return tIsLive;
}
}
private final Cell[][] mMap;
private final int mWidth;
private final int mHeight;
private int mGeneration;
public World(boolean[][] aInitialValues) {
int tHeight = aInitialValues.length;
int tWidth = aInitialValues[0].length;
mMap = new Cell[tWidth][tHeight];
mWidth = tWidth;
mHeight = tHeight;
mGeneration = 0;
createCell(0, 0);
for (int x = 0; x < tWidth; x++) {
for (int y = 0; y < tHeight; y++) {
mMap[x][y].mIsOddLive = aInitialValues[y][x];
}
}
}
private Cell createCell(int aX, int aY) {
aX = (aX < 0 ? aX + mWidth : aX) % mWidth;
aY = (aY < 0 ? aY + mHeight : aY) % mHeight;
if (mMap[aX][aY] != null) {
return mMap[aX][aY];
}
Cell tCell = new Cell();
mMap[aX][aY] = tCell;
tCell.mAdjoiningCells[0] = createCell(aX - 1, aY - 1);
tCell.mAdjoiningCells[1] = createCell(aX + 0, aY - 1);
tCell.mAdjoiningCells[2] = createCell(aX + 1, aY - 1);
tCell.mAdjoiningCells[3] = createCell(aX + 1, aY + 0);
tCell.mAdjoiningCells[4] = createCell(aX + 1, aY + 1);
tCell.mAdjoiningCells[5] = createCell(aX + 0, aY + 1);
tCell.mAdjoiningCells[6] = createCell(aX - 1, aY + 1);
tCell.mAdjoiningCells[7] = createCell(aX - 1, aY + 0);
return tCell;
}
public void next() {
mMap[0][0].next(++mGeneration);
}
@Override
public String toString() {
final boolean tIsEven = (mGeneration & 1) == 0;
StringBuilder tBuilder = new StringBuilder(mHeight * (mWidth + 1));
for (int y = 0; y < mHeight; y++) {
for (int x = 0; x < mWidth; x++) {
tBuilder.append((tIsEven ? mMap[x][y].mIsEvenLive : mMap[x][y].mIsOddLive) ? '■' : '□');
}
tBuilder.append('\n');
}
return new String(tBuilder);
}
}
public static void main(String[] args) {
boolean o = true;
boolean _ = false;
World tWorld = new World(new boolean[][] { // とりあえずグライダー
{_,_,_,_,_,_,_,_,_,_},
{_,_,_,_,_,_,_,_,_,_},
{_,_,_,_,_,_,_,_,_,_},
{_,_,_,_,_,_,_,_,_,_},
{_,_,_,_,_,_,o,_,_,_},
{_,_,_,_,_,o,_,_,_,_},
{_,_,_,_,_,o,o,o,_,_},
{_,_,_,_,_,_,_,_,_,_},
{_,_,_,_,_,_,_,_,_,_},
{_,_,_,_,_,_,_,_,_,_},
});
for (int i = 0; i < 100; i++) { // 100世代実行
tWorld.next();
System.out.println(tWorld);
}
}
}
|
計算結果をJTextAreaに表示します。 sawatさんのコードとは異なり、格子状の平面を独自に定義したFieldクラスによって表現しています。
see: mainメソッドでSwingを書かない訳(torutkの日記)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | // Doukaku126.java
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class Doukaku126 extends JFrame implements Runnable {
Field field;
JTextArea textArea;
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
public Doukaku126() {
super("ライフゲーム(どう書く?org #126)");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
field = new Field(10, 10);
field.makeLifes(0.3);
textArea = new JTextArea();
textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
add(textArea, BorderLayout.CENTER);
Thread t = new Thread(this);
t.start();
}
/**
* mainスレッドからGUIを構築しないために利用するメソッド
* 参考->http://d.hatena.ne.jp/torutk/20060928#p2
*/
private static void createAndShowGui() {
Doukaku126 frame = new Doukaku126();
frame.setSize(240, 240);
frame.setVisible(true);
}
public void run() {
StringBuffer sb = new StringBuffer();
try {
while (true) {
field.print(sb);
textArea.setText(sb.toString());
field.next();
Thread.sleep(200);
}
} catch (Exception e) {
}
}
final class Field {
private boolean[][] nowLife, nextLife, life;
private int width, height;
/**
* フィールドのコンストラクタ
*
* @param width
* フィールドの幅
* @param height
* フィールドの高さ
*/
public Field(final int width, final int height) {
nowLife = new boolean[width][height];
nextLife = new boolean[width][height];
this.width = width;
this.height = height;
}
/**
* フィールドに生命を生成する(ランダム)
*
* @param percent
* 1つのセルに生命が誕生する確率[0.0,1.0]
*/
public void makeLifes(final double percent) {
Random random = new Random();
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
nowLife[x][y] = random.nextDouble() < percent;
}
}
}
/**
* 時間を進め、生命の状態を変化させる
*/
public void next() {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
nextLife[x][y] = nextLife(nowLife[x][y], aroundLifesNum(x, y));
}
}
// 計算結果をコピー
/* for (int x = 0; x < width; ++x) {
System.arraycopy(nextLife[x], 0, nowLife[x], 0, height);
}
/*/
tmpLife = nowLife;
nowLife = nextLife;
nextLife = tmpLife;
//*/
}
/**
* 現在の生命の状態と周囲の生命数から、次の生命の状態を調べる
*
* @param nowLife
* 現在の生命の状態
* @param numLifes
* 周囲の生命数
* @return 次の生命の状態
*/
private boolean nextLife(final boolean nowLife, final int numLifes) {
return (nowLife && (numLifes == 2 || numLifes == 3))
|| (!nowLife && numLifes == 3);
}
/**
* 周囲の生命の数を返す
*/
private int aroundLifesNum(final int x, final int y) {
int num = 0;
for (int i = 0; i < 8; ++i) {
if (aroundLife(x, y, i)) {
++num;
}
}
return num;
}
// posと場所は次のように対応
// 0 1 2
// 7 * 3
// 6 5 4
private boolean aroundLife(int x, int y, final int pos) {
if (pos < 3) {
--y;
} else if (4 <= pos && pos <= 6) {
++y;
}
if (pos == 0 || pos == 6 || pos == 7) {
--x;
} else if (2 <= pos && pos <= 4) {
++x;
}
return nowLife[(x+width)%width][(y+height)%height];
}
/**
* 自分自身の文字表現をStringBufferへ代入
*/
public void print(final StringBuffer sb) {
sb.delete(0, sb.length());
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
sb.append(nowLife[x][y] ? "[*]" : "[ ]");
}
sb.append("\n");
}
}
}
}
|



saws
#5330()
Rating7/13=0.54
see: Wikipedia:ライフゲーム
[ reply ]