如何让我的生命游戏程序面向对象?

时间:2015-10-15 20:13:21

标签: java oop conways-game-of-life

我正在努力让我的生活游戏程序面向对象遵循我教授的风格指南,而不是失去分数,但我无法弄清楚如何以我的程序编码的方式这样做。

import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;

import javax.swing.*;

public class GameOfLife2 extends JFrame implements ActionListener {
static final Color[] color = { Color.LIGHT_GRAY, Color.BLUE };
// size in pixel of every label
static final int size = 15;
static final Dimension dim = new Dimension(size, size);

// the cells labels
private LifeLabel[][] label;
// timer that fires the next feneration
private Timer timer;
// generation counter
private int generation = 0;
private JLabel generationLabel = new JLabel("Generation: 0");
// the 3 buttons
private JButton bClear = new JButton("Clear"), bPause = new JButton("Pause"), bGo = new JButton("Go");
// the slider for the speed
JSlider slider = new JSlider(0, 5000); // 0 to 5000 milliseconds (5 seconds)
// state of the game (running or pause)
private boolean gameRunning = false;
// if the mouse is down or not
private boolean mouseDown = false;

GameOfLife2(int nbRow, int nbCol) {
    super("GameOfLife");
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    // create the labels (2 more on each size) these wont be shown
    // but will be used in calculating the cells alive around
    label = new LifeLabel[nbRow + 2][nbCol + 2];
    for (int r = 0; r < nbRow + 2; r++) {
        for (int c = 0; c < nbCol + 2; c++) {
            label[r][c] = new LifeLabel();
        }
    }

    // panel in the center with the labels
    JPanel panel = new JPanel(new GridLayout(nbRow, nbCol, 1, 1));
    panel.setBackground(Color.BLACK);
    panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));

    // add each label (not the one on the border) to the panel and add to
    // each of them its neighbours
    for (int r = 1; r < nbRow + 1; r++) {
        for (int c = 1; c < nbCol + 1; c++) {
            panel.add(label[r][c]);
            label[r][c].addNeighbour(label[r - 1][c]); // North
            label[r][c].addNeighbour(label[r + 1][c]); // South
            label[r][c].addNeighbour(label[r][c - 1]); // West
            label[r][c].addNeighbour(label[r][c + 1]); // East
            label[r][c].addNeighbour(label[r - 1][c - 1]); // North West
            label[r][c].addNeighbour(label[r - 1][c + 1]); // North East
            label[r][c].addNeighbour(label[r + 1][c - 1]); // South West
            label[r][c].addNeighbour(label[r + 1][c + 1]); // South East
        }
    }

    // now the panel can be added
    add(panel, BorderLayout.CENTER);

    // the bottom panel with the buttons the generation label and the slider
    // this panel is formed grid panels
    panel = new JPanel(new GridLayout(1, 3));
    // another panel for the 3 buttons
    JPanel buttonPanel = new JPanel(new GridLayout(1, 3));
    bClear.addActionListener(this);
    buttonPanel.add(bClear);
    bPause.addActionListener(this);
    bPause.setEnabled(false); // game is pause the pause button is disabled
    buttonPanel.add(bPause);
    bGo.addActionListener(this);
    buttonPanel.add(bGo);
    // add the 3 buttons to the panel
    panel.add(buttonPanel);
    // the generation label
    generationLabel.setHorizontalAlignment(SwingConstants.CENTER);
    panel.add(generationLabel);
    // the slider
    slider.setMajorTickSpacing(1000);
    slider.setMinorTickSpacing(250);
    slider.setPaintTicks(true);
    // the labels for the Slider
    Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
    for (int i = 0; i <= 5; i++) {
        labelTable.put(new Integer(i * 1000), new JLabel("" + i));
    }
    slider.setLabelTable(labelTable);
    slider.setPaintLabels(true);

    panel.add(slider);
    // in the JFrame
    add(panel, BorderLayout.SOUTH);

    // put the frame on
    setLocation(20, 20);
    pack();
    setVisible(true);
    // start the thread that run the cycles of life
    timer = new Timer(5000 - slider.getValue(), this);
}

// called by the Timer and the JButtons
public synchronized void actionPerformed(ActionEvent e) {
    // test the JButtons first
    Object o = e.getSource();
    // the clear button
    if (o == bClear) {
        timer.stop(); // stop timer
        gameRunning = false; // flag gamme not running
        bPause.setEnabled(false); // disable pause button
        bGo.setEnabled(true); // enable go button
        // clear all cells
        for (int r = 1; r < label.length - 1; r++) {
            for (int c = 1; c < label[r].length - 1; c++) {
                label[r][c].clear();
            }
        }
        // reset generation number and its label
        generation = 0;
        generationLabel.setText("Generation: 0");
        return;
    }
    // the pause button
    if (o == bPause) {
        timer.stop(); // stop timer
        gameRunning = false; // flag not running
        bPause.setEnabled(false); // disable myself
        bGo.setEnabled(true); // enable go button
        return;
    }
    // the go button
    if (o == bGo) {
        bPause.setEnabled(true); // enable pause button
        bGo.setEnabled(false); // disable myself
        gameRunning = true; // flag game is running
        timer.setDelay(5000 - slider.getValue());
        timer.start();
        return;
    }
    // not a JButton so it is the timer
    // set the delay for the next time
    timer.setDelay(5000 - slider.getValue());
    // if the game is not running wait for next time
    if (!gameRunning)
        return;
    ++generation;
    generationLabel.setText("Generation: " + generation);
    for (int r = 0; r < label.length; r++) {
        for (int c = 0; c < label[r].length; c++) {
            label[r][c].checkState();
        }
    }
    for (int r = 0; r < label.length; r++) {
        for (int c = 0; c < label[r].length; c++) {
            label[r][c].updateState();
        }
    }
}

// to start the whole thing as a Java application
public static void main(String[] arg) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            new GameOfLife2(30, 50);
        }
    });
}

// A class that extends JLabel but also check for the neigbour
// when asked to do so
class LifeLabel extends JLabel implements MouseListener {
    private int state, newState;
    private int nbNeighbour;
    private LifeLabel[] neighbour = new LifeLabel[8];

    LifeLabel() {
        state = newState = 0; // Dead
        setOpaque(true); // so color will be showed
        setBackground(color[0]);
        addMouseListener(this); // to select new LIVE cells
        this.setPreferredSize(dim);
    }

    // to add a neibour
    void addNeighbour(LifeLabel n) {
        neighbour[nbNeighbour++] = n;
    }

    // to see if I should live or not
    void checkState() {
        // number alive around
        int nbAlive = 0;
        // see the state of my neighbour
        for (int i = 0; i < nbNeighbour; i++)
            nbAlive += neighbour[i].state;
        // newState
        if (state == 1) { // if alive
            if (nbAlive < 2) // 1.Any live cell with fewer than two live
                                // neighbours dies
                newState = 0;
            if (nbAlive > 3) // 2.Any live cell with more than three live
                                // neighbours dies
                newState = 0;
        } else {
            if (nbAlive == 3) // 4.Any dead cell with exactly three live
                                // neighbours becomes a live cell
                newState = 1;
        }
    }

    // after the run switch the state to new state
    void updateState() {
        if (state != newState) { // do the test to avoid re-setting same
                                    // color for nothing
            state = newState;
            setBackground(color[state]);
        }
    }

    // called when the game is reset/clear
    void clear() {
        if (state == 1 || newState == 1) {
            state = newState = 0;
            setBackground(color[state]);
        }
    }

    @Override
    public void mouseClicked(MouseEvent arg0) {
    }

    // if the mouse enter a cell and it is down we make the cell alive
    public void mouseEntered(MouseEvent arg0) {
        if (mouseDown) {
            state = newState = 1;
            setBackground(color[1]);
        }
    }

    @Override
    public void mouseExited(MouseEvent arg0) {
    }

    // if the mouse is pressed on a cell you register the fact that it is
    // down
    // and make that cell alive
    public void mousePressed(MouseEvent arg0) {
        mouseDown = true;
        state = newState = 1;
        setBackground(color[1]);
    }

    // turn off the fact that the cell is down
    public void mouseReleased(MouseEvent arg0) {
        mouseDown = false;
    }
}
}

我从来没有非常擅长使我的程序面向对象并且通常坚持一个类,但我目前被迫使这个程序面向对象。

如果你不仅可以帮助我将这个程序改为OOP,而且还可以给我一些关于如何使用非OOP程序并使其成为那样的程序的提示,那将是非常棒的。

2 个答案:

答案 0 :(得分:3)

只有一种方法可以真正进入OO:练习。想出要解决的问题的表示,在您看到的元素中寻找可辨别的实体,并设计表示这些元素的类。规划这些元素之间的互动和关系。

然后实施,看看哪些有效,哪些无效。即使你选择不好,你也会学到它,即使它只是一个特定的选择效果不佳。

首先,想象生命游戏,如果它是一个真实的,物理世界在你眼前。不同的实体应该是容易接近的,这是设计的良好开端。

当然,我们可以建议你将这个和那个抽象成一个或另一个对象,但如果你自己不做这项工作,那么很多选择对你来说将永远是个谜。只有实际做出自己的选择,你才能真正学到一些东西。

答案 1 :(得分:1)

OOP是关于对象(顾名思义:))。因此,为了改进您的OOP编程,首先要考虑游戏中组件之间的共同属性。

你已经为lifeLabel做了这件事。已被设置为邻居。而不是这种方法,每个邻居应该是一个对象,你可以有一个List。然后,可以最小化并更容易理解更新状态和检查状态。

使您的代码OOP

没有太多变化