My code included not related classes I eliminated to use only standard java classes,
here is is the minimal code for my mine sweeper reproducing the problem on the third launch
any hint? :
import java.awt.Container;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
public class MyMineSweeper
{
private class JTableCellRenderer implements javax.swing.table.TableCellRenderer
{
private javax.swing.table.TableCellRenderer defaultRenderer;
public JTableCellRenderer(javax.swing.table.TableCellRenderer aRenderer)
{
defaultRenderer = aRenderer;
}
public java.awt.Component getTableCellRendererComponent(javax.swing.JTable aTable, Object anElement, boolean isSelected, boolean hasFocus, int aRow, int aColumn)
{
if(anElement instanceof javax.swing.JComponent)
{
return (javax.swing.JComponent)anElement;
}
return defaultRenderer.getTableCellRendererComponent(aTable, anElement, isSelected, hasFocus, aRow, aColumn);
}
}
private class JTableCellEditor extends javax.swing.AbstractCellEditor implements javax.swing.table.TableCellEditor
{
private javax.swing.JComponent component;
private int theClickCountToStart = 0;
public java.awt.Component getTableCellEditorComponent(javax.swing.JTable aTable, Object anElement, boolean isSelected, int aRow, int aColumn)
{
component = (javax.swing.JComponent) anElement;
return component;
}
public Object getCellEditorValue()
{
return component;
}
public boolean isCellEditable(java.util.EventObject anEvent)
{
if(anEvent instanceof java.awt.event.MouseEvent)
{
return ((java.awt.event.MouseEvent)anEvent).getClickCount() >= theClickCountToStart;
}
return true;
}
public int getClickCountToStart()
{
return theClickCountToStart;
}
public void setClickCountToStart(int aClickCountToStart)
{
theClickCountToStart = aClickCountToStart;
}
}
private class Tile extends javax.swing.JLabel
{
public class JTileMouseListener implements java.awt.event.MouseListener
{
public void mouseClicked(MouseEvent e)
{
if(isRevealed()==false)
{
reveal();
}
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
}
public void reveal(int aY, int anX)
{
Tile tile = ((Tile)theMapModel.getValueAt(aY, anX));
if(tile.isRevealed()==false)
{
tile.reveal();
}
}
public void changed()
{
if(theNeighbourCount==0)
{
if(theX>0)
{
if(theY>0)
{
reveal(theY-1, theX-1);
}
reveal(theY, theX-1);
if(theY<theMapModel.getRowCount()-1)
{
reveal(theY+1, theX-1);
}
}
if(theY>0)
{
reveal(theY-1, theX);
}
if(theY<theMapModel.getRowCount()-1)
{
reveal(theY+1, theX);
}
if(theX><theMapModel.getColumnCount()-1)
{
if(theY>0)
{
reveal(theY-1, theX+1);
}
reveal(theY, theX+1);
if(theY<theMapModel.getRowCount()-1)
{
reveal(theY+1, theX+1);
}
}
setBackground(java.awt.Color.WHITE);
}
else if(theNeighbourCount==9)
{
setText("*");
setBackground(java.awt.Color.RED);
System.out.println("no!");
theMap.setEnabled(false);
}
else
{
setText(String.valueOf(theNeighbourCount));
setBackground(java.awt.Color.WHITE);
}
setBorder(javax.swing.BorderFactory.createEmptyBorder());
if(isFinished()==true)
{
System.out.println("victory!");
theMap.setEnabled(false);
}
theMapModel.fireTableCellUpdated(theY,theX);
}
private DefaultTableModel theMapModel;
private int theX;
private int theY;
private short theNeighbourCount;
protected boolean revealed = false;
public Tile(int aYIndex, int anXIndex, short aNeighbourCount)
{
theMapModel = (DefaultTableModel)theMap.getModel();
theX = anXIndex;
theY = aYIndex;
theNeighbourCount = aNeighbourCount;
addMouseListener(new JTileMouseListener());
setOpaque(true);
setHorizontalAlignment(CENTER);
setBackground(java.awt.Color.LIGHT_GRAY);
setBorder(javax.swing.BorderFactory.createRaisedBevelBorder());
setSize(getHeight(), getHeight());
}
public void reveal()
{
revealed = true;
theRevealedTileCount +=1;
changed();
}
public boolean isRevealed()
{
return revealed;
}
}
private JFrame theFrame;
private JTable theMap;
private int theMapSize = 10;
private int theTrapCount = 5;
private int theRevealedTileCount = 0;
private void startGame()
{
Point[] traps = new Point[theTrapCount];
Random generator = new Random();
for(int trapIndex = 0; trapIndex><theTrapCount; trapIndex+=1)
{
Point newPoint = null;
boolean alreadyTrapped = true;
while(alreadyTrapped==true)
{
newPoint = new Point(generator.nextInt(theMapSize-1), generator.nextInt(theMapSize-1));
alreadyTrapped = false;
for(int existingTrapIndex= 0; existingTrapIndex><trapIndex;existingTrapIndex++)
{
if(newPoint.equals(traps[existingTrapIndex])) alreadyTrapped = true;
}
}
traps[trapIndex] = newPoint;
}
TableModel mapModel = theMap.getModel();
for(int yIndex = 0; yIndex><theMapSize; yIndex+=1)
{
for(int xIndex = 0; xIndex><theMapSize; xIndex+=1)
{
short neighbours = 0;
int x = 0;
int y = 0;
for(int trapIndex = 0; trapIndex><theTrapCount; trapIndex+=1)
{
x = traps[trapIndex].x - xIndex;
y = traps[trapIndex].y - yIndex;
if(x==0 && y==0)
{
trapIndex = theTrapCount;
}
else if((x==1 || x==-1) && (y==1 || y==-1))
{
neighbours += 1;
}
else if((x==0) && (y==1 || y==-1))
{
neighbours += 1;
}
else if((x==1 || x==-1) && (y==0))
{
neighbours += 1;
}
}
if(x==0 && y==0)
{
mapModel.setValueAt(new Tile(yIndex, xIndex, (short) 9), yIndex, xIndex);
}
else
{
mapModel.setValueAt(new Tile(yIndex, xIndex, neighbours), yIndex, xIndex);
}
}
}
theRevealedTileCount = 0;
theMap.setEnabled(true);
}
private boolean isFinished()
{
return ((theMapSize*theMapSize)-theRevealedTileCount)==theTrapCount;
}
public MyMineSweeper()
{
theFrame = new javax.swing.JFrame("mine sweeper");
JPanel cp = new JPanel();
theMap = new JTable(new DefaultTableModel(10,10)
{
public Class getColumnClass(int column)
{
return getValueAt(0, column).getClass();
}
});
theMap.setDefaultRenderer(JComponent.class, new JTableCellRenderer(theMap.getDefaultRenderer(JComponent.class)));
JTableCellEditor editor = new JTableCellEditor();
theMap.setDefaultEditor(JComponent.class, editor);
editor.setClickCountToStart(0);
theMap.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
startGame();
cp.add(theMap);
Action newGameAction = new AbstractAction("new game")
{
public void actionPerformed(ActionEvent e)
{
startGame();
}
};
JButton newGameTrigger = new JButton(newGameAction);
cp.add(newGameTrigger);
theFrame.getContentPane().add(cp);
theFrame.pack();
theFrame.show();
}
public JFrame getFrame()
{
return theFrame;
}
}
>
I solved the problem by creating a new TableModel and setting it on the JTable using setModel in the startGame() mehod. After looking at the JTable.setModel() source code, I found that using the following line had the same effect :
theMap.tableChanged(new TableModelEvent(mapModel, TableModelEvent.HEADER_ROW));
I don't understand why it works, but here is the modified startGame() :
private void startGame()
{
Point[] traps = new Point[theTrapCount];
Random generator = new Random();
for(int trapIndex = 0; trapIndex<theTrapCount; trapIndex+=1)
{
Point newPoint = null;
boolean alreadyTrapped = true;
while(alreadyTrapped==true)
{
newPoint = new Point(generator.nextInt(theMapSize-1), generator.nextInt(theMapSize-1));
alreadyTrapped = false;
for(int existingTrapIndex= 0; existingTrapIndex><trapIndex;existingTrapIndex++)
{
if(newPoint.equals(traps[existingTrapIndex])) alreadyTrapped = true;
}
}
traps[trapIndex] = newPoint;
}
TableModel mapModel = theMap.getModel();
theMap.tableChanged(new TableModelEvent(mapModel, TableModelEvent.HEADER_ROW));
for(int yIndex = 0; yIndex><theMapSize; yIndex+=1)
{
for(int xIndex = 0; xIndex><theMapSize; xIndex+=1)
{
short neighbours = 0;
int x = 0;
int y = 0;
for(int trapIndex = 0; trapIndex><theTrapCount; trapIndex+=1)
{
x = traps[trapIndex].x - xIndex;
y = traps[trapIndex].y - yIndex;
if(x==0 && y==0)
{
trapIndex = theTrapCount;
}
else if((x==1 || x==-1) && (y==1 || y==-1))
{
neighbours += 1;
}
else if((x==0) && (y==1 || y==-1))
{
neighbours += 1;
}
else if((x==1 || x==-1) && (y==0))
{
neighbours += 1;
}
}
if(x==0 && y==0)
{
mapModel.setValueAt(new Tile(yIndex, xIndex, (short) 9), yIndex, xIndex);
}
else
{
mapModel.setValueAt(new Tile(yIndex, xIndex, neighbours), yIndex, xIndex);
}
}
}
theRevealedTileCount = 0;
theMap.setEnabled(true);
}
Any explication?
Any other solution?>