001/* 002 * Main.java 003 */ 004package minesweeper; 005 006import java.awt.*; 007import java.awt.event.*; 008//import java.awt.image.*; 009//import javax.imageio.*; 010import javax.swing.*; 011//import javax.swing.border.*; 012//import java.text.*; 013//import java.io.*; 014import java.util.*; 015 016import org.apache.logging.log4j.*; 017 018/** 019 * DESCRIBE {@link Main} HERE. 020 * 021 * @author 2017-2018 APCS 022 * @author ADD @author TAG FOR EVERYONE WHO CONTRIBUTED TO THIS FILE 023 * @author <a href="https://github.com/wps-dpetty">David C. Petty</a> 024 */ 025public class Main extends JFrame { 026 027 //////////////////////////////// FIELDS //////////////////////////////// 028 029 /** 030 * log4j {@link Logger}. 031 */ 032 private static Logger logger = LogManager.getLogger(Minesweeper.SHORT); 033 /** 034 * Number of rows in grid. 035 */ 036 private static int rows; 037 /** 038 * Number of cols in grid. 039 */ 040 private static int cols; 041 /** 042 * Number of mines in grid. 043 */ 044 private static int mines; 045 046 /** 047 * {@link Stopwatch} <strong>FOR WHAT?</strong> 048 */ 049 private static Stopwatch sw; 050 051 /** 052 * Single {@link JPanel} in main {@link JFrame} so as to accurately 053 * calculate drawing area. 054 */ 055 private static JPanel panel; 056 /** 057 * {@link JLabel} to display timer. 058 */ 059 private static JLabel timerLabel; 060 /** 061 * {@link Grid} of {@link Button}s. 062 */ 063 private static Grid grid; 064 065 ///////////////////////////// CONSTRUCTORS ///////////////////////////// 066 067 /** 068 * Construct a {@link Main} frame. 069 * 070 * @param name frame title 071 * @param rows number of rows in grid 072 * @param cols number of columns in grid 073 * @param mines number of mines in grid 074 */ 075 public Main(String name, int rows, int cols, int mines) { 076 super(name); 077 Main.rows = rows; 078 Main.cols = cols; 079 Main.mines = mines; 080 logger.info("{}: {} ({}x{}) {}", 081 getClass().getName(), name, rows, cols, mines); 082 } 083 084 //////////////////////////////// CLASSES /////////////////////////////// 085 086 /** 087 * PanelListener listens for resize events and adjusts grid accordingly. 088 */ 089 private static class PanelListener extends ComponentAdapter { 090 public void componentResized(ComponentEvent e) { 091 // Log layoutDimensions from GridBagLayout to help calculate resize. 092 GridBagLayout layout = (GridBagLayout) panel.getLayout(); 093 int[][] dims = layout.getLayoutDimensions(); 094 int xSum = 0, ySum = 0; 095 for (int i = 0; i < dims[0].length; i++) xSum += dims[0][i]; 096 for (int j = 0; j < dims[1].length; j++) ySum += dims[1][j]; 097 int igw = grid.getCols() * grid.getSide(); // initial grid width 098 int igh = grid.getRows() * grid.getSide(); // initial grid height 099 double rgw = xSum; // reset grid width 100 double rgh = dims[1][2] + panel.getHeight() - ySum; // reset grid height 101 logger.info("{} {} ({},{}) [{}x{} {}x{}: {} {}]", 102 e, Arrays.deepToString(dims), xSum, ySum, igw, igh, rgw, rgh, 103 rgw / grid.getCols(), rgh / grid.getRows()); 104 // Calculate minimum square button size & set grid size accordingly. 105 int side = (int) Math.min(rgw / grid.getCols(), rgh / grid.getRows()); 106 grid.setSize(side * grid.getCols(), side * grid.getRows()); 107 } 108 } 109 110 //////////////////////////////// METHODS /////////////////////////////// 111 112 /** 113 * Return {@link Grid} component. 114 * 115 * @return grid component 116 */ 117 public static Grid getGrid() { 118 return grid; 119 } 120 121 /** 122 * Create and show main graphical user interface. 123 */ 124 private static void createAndShowGUI() { 125 // Create and set up the window frame. 126 // REDFLAG: mines should be a function of level, rows, and cols 127 Main frame = new Main("Minesweeper", 16, 30, 99); 128 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 129 130 // Use single JPanel in frame to get full width & height. 131 panel = new JPanel(); 132 panel.addComponentListener(new PanelListener()); 133 134 // Initialize panel layout. 135 GridBagLayout layout = new GridBagLayout(); 136 panel.setLayout(layout); 137 GridBagConstraints c = new GridBagConstraints(); 138 139 // Display mineCount. 140 JLabel mineCount = new JLabel("0" + mines, SwingConstants.CENTER); 141 mineCount.setFont(new Font("Verdana", 1, 20)); 142 c = new GridBagConstraints(); 143 c.anchor = GridBagConstraints.FIRST_LINE_START; 144 c.anchor = GridBagConstraints.CENTER; 145 c.fill = GridBagConstraints.HORIZONTAL; 146 c.gridx = 0; 147 c.gridy = 0; 148 c.ipadx = 10; 149 c.weightx = 0.5; 150 panel.add(mineCount, c); 151 152 // Display smile. 153 Image image = Images.getImage("/images/smiley1.jpeg"); 154 ImageIcon icon = new ImageIcon(image); 155 Dimension size = new Dimension(icon.getIconWidth(), icon.getIconHeight()); 156 JButton smile = new JButton(icon); 157 smile.setPreferredSize(size); 158 c = new GridBagConstraints(); 159 c.anchor = GridBagConstraints.PAGE_START; 160 c.anchor = GridBagConstraints.CENTER; 161 c.fill = GridBagConstraints.NONE; 162 c.gridx = 1; 163 c.gridy = 0; 164 c.ipadx = 10; 165 c.weightx = 0.5; 166 panel.add(smile, c); 167 168 sw = new Stopwatch();// initialize sw 169 170 // Display timerLabel. 171 timerLabel = new JLabel("00:00", SwingConstants.CENTER); 172 timerLabel.setFont(new Font("Verdana", 1, 20)); 173 c = new GridBagConstraints(); 174 c.anchor = GridBagConstraints.FIRST_LINE_END; 175 c.anchor = GridBagConstraints.CENTER; 176 c.fill = GridBagConstraints.HORIZONTAL; 177 c.gridx = 2; 178 c.gridy = 0; 179 c.ipadx = 10; 180 c.weightx = 0.5; 181 panel.add(timerLabel, c); 182 183 // Display separator. 184 JSeparator separator = new JSeparator(); 185 c = new GridBagConstraints(); 186 c.anchor = GridBagConstraints.CENTER; 187 c.fill = GridBagConstraints.BOTH; 188 c.gridx = 0; 189 c.gridy = 1; 190 c.ipadx = 0; 191 c.gridwidth = 3; 192 c.weightx = 0.5; 193 panel.add(separator, c); 194 195 // Display grid. 196 grid = new Grid(rows, cols); 197 c = new GridBagConstraints(); 198 c.anchor = GridBagConstraints.SOUTH; 199 c.fill = GridBagConstraints.NONE; 200 c.gridx = 0; 201 c.gridy = 2; 202 c.ipadx = 0; 203 c.gridwidth = 3; 204 c.weightx = 0.5; 205 panel.add(grid, c); 206 207 // Display frame. 208 frame.add(panel); 209 frame.pack(); 210 frame.setMinimumSize(frame.getSize()); // layout will not get smaller 211 frame.setVisible(true); 212 } 213 214 public static void startTimer(boolean resetTimer) { 215 //resetTimer(); 216 if (resetTimer || (!sw.isStopWatchRunning())) { 217 sw.startStopWatch();// Traditionally Stopwatch is only started after the first click on the grid... 218 javax.swing.Timer mainTimer = new javax.swing.Timer(100, new ActionListener() { 219 public void actionPerformed(ActionEvent e) { 220 timerLabel.setText(sw.getFormattedElapsedTime()); 221 } 222 }); 223 mainTimer.start(); 224 } 225 } 226 227 public static void youDied() { 228 Main frame = new Main("Minesweeper", 16, 30, 99); 229 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 230 231 // Use single JPanel in frame to get full width & height. 232 panel = new JPanel(); 233 panel.addComponentListener(new PanelListener()); 234 235 // Initialize panel layout. 236 GridBagLayout layout = new GridBagLayout(); 237 panel.setLayout(layout); 238 GridBagConstraints c = new GridBagConstraints(); 239 // Display dead emoticon. 240 Image image = Images.getImage("/images/youLost1.jpeg"); 241 ImageIcon icon = new ImageIcon(image); 242 Dimension size = new Dimension(icon.getIconWidth(), icon.getIconHeight()); 243 JButton smile = new JButton(icon); 244 smile.setPreferredSize(size); 245 c = new GridBagConstraints(); 246 c.anchor = GridBagConstraints.PAGE_START; 247 c.anchor = GridBagConstraints.CENTER; 248 c.fill = GridBagConstraints.NONE; 249 c.gridx = 1; 250 c.gridy = 0; 251 c.ipadx = 10; 252 c.weightx = 0.5; 253 panel.add(smile, c); 254 } 255 256 /** 257 * Minesweeper main method. 258 * 259 * @param args command-line arguments 260 */ 261 public static void main(String[] args) { 262 javax.swing.SwingUtilities.invokeLater(new Runnable() { 263 public void run() { 264 createAndShowGUI(); 265 } 266 }); 267 } 268}