我正在尝试基于六边形网格实现Conways Game of Life。除了线程处理不正确之外,一切都正常:每次运行应用程序时,我都会得到不同的结果,所以我认为这是一个与非同步线程相关的问题。我是java的新手,所以收到任何建议会很有帮助。感谢。
package hexautamata;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
/**
*
* @author Walter
*/
public class LifeEngine extends JPanel implements MouseListener, ComponentListener, Runnable {
private final int BOARD_WIDTH = 29;
private final int BOARD_HEIGHT = 24;
private final int L_ON = 1;
private final int L_OFF = 2;
private final int NUM_HEX_CORNERS = 6;
private final int CELL_RADIUS = 16;
private int[][] mCells = new int[BOARD_HEIGHT][BOARD_WIDTH];
private int[] mCornersX = new int[NUM_HEX_CORNERS];
private int[] mCornersY = new int[NUM_HEX_CORNERS];
HexGridCell mCellMetrics = new HexGridCell(CELL_RADIUS);
public LifeEngine(){
//setBounds(0, 0, BOARD_WIDTH * mCellMetrics.WIDTH, BOARD_HEIGHT * mCellMetrics.HEIGHT + CELL_RADIUS);
addMouseListener(this);
fillCells();
setBackground(Color.WHITE);
}
private void fillCells(){
try {
BufferedReader reader = new BufferedReader(new FileReader(new File("C:\\Users\\user\\Documents\\NetBeansProjects\\HexAutamata\\src\\hexautamata\\HEXAGON")));
String line;
int i = 0, j = 0;
while((line = reader.readLine()) != null){
Scanner scanner = new Scanner(line);
while(scanner.hasNext()){
mCells[i][j] = scanner.nextInt();
++j;
}
i++;
j = 0;
}
} catch (FileNotFoundException ex) {
Logger.getLogger(LifeEngine.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(LifeEngine.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int j = 0; j < BOARD_HEIGHT; j++) {
for (int i = 0; i < BOARD_WIDTH; i++) {
mCellMetrics.setCellIndex(i, j);
if (mCells[j][i] != 0) {
mCellMetrics.computeCorners(mCornersX, mCornersY);
g.setColor((mCells[j][i] == L_ON) ? Color.ORANGE : Color.GRAY);
g.fillPolygon(mCornersX, mCornersY, NUM_HEX_CORNERS);
g.setColor(Color.BLACK);
g.drawPolygon(mCornersX, mCornersY, NUM_HEX_CORNERS);
}
}
}
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.RED);
g2.setStroke(new BasicStroke(0x8));
g2.drawOval(55, 30, 642, 642);
}
private boolean isInsideBoard(int i, int j) {
return i >= 0 && i < BOARD_HEIGHT && j >= 0 && j < BOARD_WIDTH
&& mCells[i][j] != 0;
}
private void toggleCell(int i, int j) {
mCells[j][i] = (mCells[j][i] == L_ON) ? L_OFF : L_ON;
}
public void resetGame() {
for (int j = 0; j < BOARD_HEIGHT; j++) {
for (int i = 0; i < BOARD_WIDTH; i++) {
if (mCells[j][i] == L_OFF) {
mCells[j][i] = L_ON;
}
}
}
repaint();
}
@Override
public void mouseReleased(MouseEvent arg0) {
mCellMetrics.setCellByPoint(arg0.getX(), arg0.getY());
int clickI = mCellMetrics.getIndexI();
int clickJ = mCellMetrics.getIndexJ();
if (isInsideBoard(clickJ, clickI)) {
toggleCell(clickI, clickJ);
}
this.repaint();
}
@Override
public void mouseClicked(MouseEvent arg0) {
mCellMetrics.setCellByPoint(arg0.getX(), arg0.getY());
int clickI = mCellMetrics.getIndexI();
int clickJ = mCellMetrics.getIndexJ();
//System.out.println("i = " + clickI + " j = " + clickJ);
}
@Override
public void mouseEntered(MouseEvent arg0) {
}
@Override
public void mouseExited(MouseEvent arg0) {
}
@Override
public void mousePressed(MouseEvent arg0) {
}
@Override
public void componentResized(ComponentEvent e) {
}
@Override
public void componentMoved(ComponentEvent e) {
}
@Override
public void componentShown(ComponentEvent e) {
}
@Override
public void componentHidden(ComponentEvent e) {
}
private synchronized void setCellIndex(int j, int i){
mCellMetrics.setCellIndex(j, i);
}
private synchronized int getIndexI(){
return mCellMetrics.getIndexI();
}
private synchronized int getIndexJ(){
return mCellMetrics.getIndexJ();
}
@Override
public void run() {
int[][] buffer = new int[mCells.length][mCells[0].length];
for(int i = 0; i < mCells.length; ++i){
buffer[i] = Arrays.copyOf(mCells[i], mCells[i].length);
}
for(int i = 0; i < BOARD_HEIGHT; ++i){
for(int j = 0; j < BOARD_WIDTH; ++j){
synchronized(mCellMetrics){
int neigbourCounter = 0;
mCellMetrics.setCellIndex(j, i);
int clickI = mCellMetrics.getIndexI();
int clickJ = mCellMetrics.getIndexJ();
System.out.println(Thread.currentThread().getName() + " i = " + clickI + " j = " + clickJ);
if(isInsideBoard(clickJ, clickI)) {
for(int k = 0; k < 6; k++){
//System.out.println(Thread.currentThread().getName() + " i = " + mCellMetrics.getIndexI() + " j = " +mCellMetrics.getIndexJ());
int nI = mCellMetrics.getNeighborI(k);
int nJ = mCellMetrics.getNeighborJ(k);
if(isInsideBoard(nJ, nI) && mCells[nJ][nI] == 2) {
System.out.println("And its neigbours : i = " + nI + " j = " + nJ);
neigbourCounter++;
}
}
if(mCells[i][j] == L_ON){
if(neigbourCounter == 3){
buffer[i][j] = L_OFF;
}
} else if(mCells[i][j] == L_OFF){
if(neigbourCounter > 3 || neigbourCounter < 2){
buffer[i][j] = L_ON;
}
}
}
}
}
}
for(int i = 0; i < buffer.length; ++i){
mCells[i] = Arrays.copyOf(buffer[i], buffer[i].length);
}
repaint();
try {
Thread.sleep(5000);
run();
} catch(InterruptedException e){}
}
}
package hexautamata;
/**
*
* @author Walter
*/
public class HexGridCell {
private final int[] NEIGHBORS_DI = { 0, 1, 1, 0, -1, -1 };
private final int[][] NEIGHBORS_DJ = {
{ -1, -1, 0, 1, 0, -1 }, { -1, 0, 1, 1, 1, 0 } };
private final int[] CORNERS_DX; // array of horizontal offsets of the cell's corners
private final int[] CORNERS_DY; // array of vertical offsets of the cell's corners
private final int SIDE;
private int mX = 0; // cell's left coordinate
private int mY = 0; // cell's top coordinate
private int mI = 0; // cell's horizontal grid coordinate
private int mJ = 0; // cell's vertical grid coordinate
/**
* Cell radius (distance from center to one of the corners)
*/
public final int RADIUS;
public final int HEIGHT;
public final int WIDTH;
public final int NUM_NEIGHBORS = 6;
/**
* @param radius Cell radius (distance from the center to one of the corners)
*/
public HexGridCell(int radius) {
RADIUS = radius;
WIDTH = radius * 2;
HEIGHT = (int) (((float) radius) * Math.sqrt(3));
SIDE = radius * 3 / 2;
int cdx[] = { RADIUS / 2, SIDE, WIDTH, SIDE, RADIUS / 2, 0 };
CORNERS_DX = cdx;
int cdy[] = { 0, 0, HEIGHT / 2, HEIGHT, HEIGHT, HEIGHT / 2 };
CORNERS_DY = cdy;
}
public int getLeft() {
return mX;
}
public int getTop() {
return mY;
}
public int getCenterX() {
return mX + RADIUS;
}
public int getCenterY() {
return mY + HEIGHT / 2;
}
public int getIndexI() {
return mI;
}
public int getIndexJ() {
return mJ;
}
public int getNeighborI(int neighborIdx) {
return mI + NEIGHBORS_DI[neighborIdx];
}
public int getNeighborJ(int neighborIdx) {
return mJ + NEIGHBORS_DJ[mI % 2][neighborIdx];
}
public void computeCorners(int[] cornersX, int[] cornersY) {
for (int k = 0; k < NUM_NEIGHBORS; k++) {
cornersX[k] = mX + CORNERS_DX[k];
cornersY[k] = mY + CORNERS_DY[k];
}
}
public void setCellIndex(int i, int j) {
mI = i;
mJ = j;
mX = i * SIDE;
mY = HEIGHT * (2 * j + (i % 2)) / 2;
}
public void setCellByPoint(int x, int y) {
int ci = (int)Math.floor((float)x/(float)SIDE);
int cx = x - SIDE*ci;
int ty = y - (ci % 2) * HEIGHT / 2;
int cj = (int)Math.floor((float)ty/(float)HEIGHT);
int cy = ty - HEIGHT*cj;
if (cx > Math.abs(RADIUS / 2 - RADIUS * cy / HEIGHT)) {
setCellIndex(ci, cj);
} else {
setCellIndex(ci - 1, cj + (ci % 2) - ((cy < HEIGHT / 2) ? 1 : 0));
}
}
}
package hexautamata;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/**
*
* @author Walter
*/
public class MainToolbar extends JFrame implements ActionListener {
private static final Dimension DEFAULT_WINDOW_SIZE = new Dimension(800, 750);
private static final Dimension MINIMUM_WINDOW_SIZE = new Dimension(400, 400);
private final LifeEngine lifeengine;
private JMenuBar my_menu;
private JMenu m_file, m_game;
private JMenuItem m_start, m_stop, m_reset;
private Thread game;
public MainToolbar(){
super("Tool bar");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(DEFAULT_WINDOW_SIZE);
setMinimumSize(MINIMUM_WINDOW_SIZE);
setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - this.getWidth())/2,
(Toolkit.getDefaultToolkit().getScreenSize().height - this.getHeight())/2);
my_menu = new JMenuBar();
m_file = new JMenu("File");
my_menu.add(m_file);
m_game = new JMenu("Game");
my_menu.add(m_game);
m_start = new JMenuItem("Start");
m_start.addActionListener(this);
m_game.add(m_start);
m_game.add(new JSeparator());
m_stop = new JMenuItem("Stop");
m_stop.addActionListener(this);
m_game.add(m_stop);
m_game.add(new JSeparator());
m_reset = new JMenuItem("Reset");
m_reset.addActionListener(this);
m_game.add(m_reset);
setJMenuBar(my_menu);
lifeengine = new LifeEngine();
add(lifeengine);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(m_reset)){
lifeengine.resetGame();
} else if(e.getSource().equals(m_start)){
setGameBeingPlayed(true);
} else if(e.getSource().equals(m_stop)){
setGameBeingPlayed(false);
}
}
public void setGameBeingPlayed(boolean isBeingPlayed){
if(isBeingPlayed){
m_start.setEnabled(false);
m_stop.setEnabled(true);
game = new Thread(lifeengine);
game.start();
} else {
m_start.setEnabled(true);
m_stop.setEnabled(false);
game.interrupt();
}
}
}
package hexautamata;
import java.awt.Dimension;
/**
*
* @author Walter
*/
public class HexAutomata {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
MainToolbar mtb = new MainToolbar();
mtb.setResizable(false);
}
}
答案 0 :(得分:1)
而不是使用此
阻止EventDispatcherThread try {
Thread.sleep(5000);
run();
} catch(InterruptedException e){}
使用javax.swing.Timer
并在actionPerformed()
Timer
动作中添加您的代码