challenge ライフゲーム

セルオートマトンに関するお題です. 
2次元タイプの'ライフゲーム'を実装して下さい. 
初期値としては10行10列程度の格子上の平面に0.3程度の人口(?)密度を考え, 
末端はループするようにして下さい. (例: 座標[-1, -1] = [10, 10])

それだけだと簡単すぎると思われる方は, 
過密状態で間引きが発生するような機能を組み込んで下さい. 
間引きは, 少なくともその後の1時間ステップにおける死亡率が, 
それをしなかった場合よりも小さくなれば結構です. 
(死亡率の最小化は複雑性が高すぎる感がありますし. )
サンプル:
t = 0
[ ][*][ ][ ][ ][ ][*][*][*][ ]
[ ][ ][ ][ ][*][ ][ ][*][*][ ]
[ ][ ][ ][*][ ][ ][*][ ][*][ ]
[*][ ][*][*][ ][ ][*][ ][ ][ ]
[ ][*][ ][ ][ ][ ][ ][ ][*][ ]
[*][ ][ ][ ][*][ ][*][*][ ][*]
[ ][*][ ][ ][ ][ ][*][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][*]
[*][ ][ ][ ][ ][ ][*][ ][ ][*]
[ ][ ][ ][ ][*][*][ ][ ][*][ ]
t = 1
[ ][ ][ ][ ][*][ ][ ][ ][ ][*]
[ ][ ][ ][ ][ ][*][ ][ ][ ][*]
[ ][ ][*][ ][*][*][*][ ][*][*]
[ ][*][ ][*][ ][ ][ ][ ][ ][*]
[ ][ ][*][*][ ][*][*][ ][*][ ]
[ ][*][ ][ ][ ][*][*][ ][*][*]
[ ][ ][ ][ ][ ][*][*][*][*][*]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][*]
[*][ ][ ][ ][ ][*][ ][ ][*][ ]
[*][ ][ ][ ][ ][ ][ ][ ][ ][ ]

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クラスによって表現しています。

  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");
            }
        }
    }
}

Index

Feed

Other

Link

Pathtraq

loading...