package com.netbeetle.minesweeper; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.awt.geom.Rectangle2D; import java.awt.font.FontRenderContext; public class JMineSweeper extends JComponent implements MouseListener, KeyListener { private Board board; private int rows, cols, rowHeight, colWidth, mines; public JMineSweeper(int width, int height, int cols, int rows, int mines) { super(); board = new Board(cols, rows, mines); rowHeight = height / rows; colWidth = width / cols; this.rows = rows; this.cols = cols; this.mines = mines; setPreferredSize(new Dimension(cols * colWidth + 1, rows * rowHeight + 1)); addMouseListener(this); addKeyListener(this); } protected void paintComponent(Graphics g) { super.paintComponent(g); for (int i = 0; i < cols * rows; i++) { Cell cell = board.getCell(i); if (cell == null) continue; if (cell.isEmpty()) g.setColor(new Color(0, 0, 0)); else if (cell.isMine()) g.setColor(new Color(255, 0, 0)); else if (cell.hasGuess()) { if (cell.getGuess()) g.setColor(new Color(255, 128, 128)); else g.setColor(new Color(128, 0, 0)); } else g.setColor(new Color(1.0f - (float)cell.getMineProbability(), 1.0f - (float)cell.getMineProbability(), 1.0f)); g.fillRect(1 + (i % cols) * colWidth, 1 + (i / cols) * rowHeight, colWidth - 1, rowHeight - 1); if (cell.isEmpty() && cell.getMines() != 0) { // draw the number on the image Graphics2D g2 = (Graphics2D) g; FontRenderContext frc = g2.getFontRenderContext(); Font font = new Font("Arial", Font.BOLD, Math.min(colWidth, rowHeight) / 2); String number = new Integer(cell.getMines()).toString(); // find the location to draw the string Rectangle2D rect = font.getStringBounds(number, frc); float x = (float) (colWidth - rect.getWidth()) / 2.0f; float y = (float) (rowHeight + rect.getHeight() / 2) / 2.0f; g2.setFont(font); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // draw the text g2.setPaint(new Color(255, 255, 255)); g2.drawString(number, x + 1 + (i % cols) * colWidth, y + 1 + (i / cols) * rowHeight); } } } // implementation of mouse listener public void mouseClicked(MouseEvent event) { // TODO: check bounds Cell cell = board.getCell(event.getX() / colWidth + event.getY() / rowHeight * cols); if (cell == null) return; switch (event.getButton()) { case MouseEvent.BUTTON1: cell.reveal(); break; case MouseEvent.BUTTON3: if (cell.isEmpty() && cell.isSatisfied()) cell.revealNeighbors(); else if (cell.hasGuess()) { if (cell.getGuess() == true) cell.guess(false); else cell.clearGuess(); } else cell.guess(true); break; } repaint(); } public void mouseEntered(MouseEvent event) {} public void mouseExited(MouseEvent event) {} public void mousePressed(MouseEvent event) { requestFocusInWindow(); } public void mouseReleased(MouseEvent event) {} // implementation of key listener public void keyTyped(KeyEvent event) {} public void keyReleased(KeyEvent event) {} public void keyPressed(KeyEvent event) { switch (event.getKeyCode()) { case KeyEvent.VK_F2: board = new Board(cols, rows, mines); repaint(); break; case KeyEvent.VK_F3: board.adjustProbabilities(); repaint(); break; case KeyEvent.VK_F4: board.makeSureMoves(); repaint(); break; case KeyEvent.VK_F5: board.makeBestMove(); repaint(); break; } } }