├── PuzzleEx.java ├── README.md ├── icesid.jpg └── puzzle.png /PuzzleEx.java: -------------------------------------------------------------------------------- 1 | package com.zetcode; 2 | 3 | import javax.imageio.ImageIO; 4 | import javax.swing.AbstractAction; 5 | import javax.swing.BorderFactory; 6 | import javax.swing.ImageIcon; 7 | import javax.swing.JButton; 8 | import javax.swing.JComponent; 9 | import javax.swing.JFrame; 10 | import javax.swing.JOptionPane; 11 | import javax.swing.JPanel; 12 | import java.awt.BorderLayout; 13 | import java.awt.Color; 14 | import java.awt.EventQueue; 15 | import java.awt.GridLayout; 16 | import java.awt.Image; 17 | import java.awt.Point; 18 | import java.awt.event.ActionEvent; 19 | import java.awt.event.MouseAdapter; 20 | import java.awt.event.MouseEvent; 21 | import java.awt.image.BufferedImage; 22 | import java.awt.image.CropImageFilter; 23 | import java.awt.image.FilteredImageSource; 24 | import java.io.File; 25 | import java.io.IOException; 26 | import java.util.ArrayList; 27 | import java.util.Collections; 28 | import java.util.List; 29 | 30 | class MyButton extends JButton { 31 | 32 | private boolean isLastButton; 33 | 34 | public MyButton() { 35 | 36 | super(); 37 | 38 | initUI(); 39 | } 40 | 41 | public MyButton(Image image) { 42 | 43 | super(new ImageIcon(image)); 44 | 45 | initUI(); 46 | } 47 | 48 | private void initUI() { 49 | 50 | isLastButton = false; 51 | BorderFactory.createLineBorder(Color.gray); 52 | 53 | addMouseListener(new MouseAdapter() { 54 | 55 | @Override 56 | public void mouseEntered(MouseEvent e) { 57 | setBorder(BorderFactory.createLineBorder(Color.yellow)); 58 | } 59 | 60 | @Override 61 | public void mouseExited(MouseEvent e) { 62 | setBorder(BorderFactory.createLineBorder(Color.gray)); 63 | } 64 | }); 65 | } 66 | 67 | public void setLastButton() { 68 | 69 | isLastButton = true; 70 | } 71 | 72 | public boolean isLastButton() { 73 | 74 | return isLastButton; 75 | } 76 | } 77 | 78 | public class PuzzleEx extends JFrame { 79 | 80 | private JPanel panel; 81 | private BufferedImage source; 82 | private BufferedImage resized; 83 | private Image image; 84 | private MyButton lastButton; 85 | private int width, height; 86 | 87 | private List buttons; 88 | private List solution; 89 | 90 | private final int NUMBER_OF_BUTTONS = 12; 91 | private final int DESIRED_WIDTH = 300; 92 | 93 | 94 | public PuzzleEx() { 95 | 96 | initUI(); 97 | } 98 | 99 | private void initUI() { 100 | 101 | solution = new ArrayList<>(); 102 | 103 | solution.add(new Point(0, 0)); 104 | solution.add(new Point(0, 1)); 105 | solution.add(new Point(0, 2)); 106 | solution.add(new Point(1, 0)); 107 | solution.add(new Point(1, 1)); 108 | solution.add(new Point(1, 2)); 109 | solution.add(new Point(2, 0)); 110 | solution.add(new Point(2, 1)); 111 | solution.add(new Point(2, 2)); 112 | solution.add(new Point(3, 0)); 113 | solution.add(new Point(3, 1)); 114 | solution.add(new Point(3, 2)); 115 | 116 | buttons = new ArrayList<>(); 117 | 118 | panel = new JPanel(); 119 | panel.setBorder(BorderFactory.createLineBorder(Color.gray)); 120 | panel.setLayout(new GridLayout(4, 3, 0, 0)); 121 | 122 | try { 123 | source = loadImage(); 124 | int h = getNewHeight(source.getWidth(), source.getHeight()); 125 | resized = resizeImage(source, DESIRED_WIDTH, h, 126 | BufferedImage.TYPE_INT_ARGB); 127 | 128 | } catch (IOException ex) { 129 | JOptionPane.showMessageDialog(this, "Could not load image", "Error", 130 | JOptionPane.ERROR_MESSAGE); 131 | } 132 | 133 | width = resized.getWidth(null); 134 | height = resized.getHeight(null); 135 | 136 | add(panel, BorderLayout.CENTER); 137 | 138 | for (int i = 0; i < 4; i++) { 139 | 140 | for (int j = 0; j < 3; j++) { 141 | 142 | image = createImage(new FilteredImageSource(resized.getSource(), 143 | new CropImageFilter(j * width / 3, i * height / 4, 144 | (width / 3), height / 4))); 145 | 146 | var button = new MyButton(image); 147 | button.putClientProperty("position", new Point(i, j)); 148 | 149 | if (i == 3 && j == 2) { 150 | 151 | lastButton = new MyButton(); 152 | lastButton.setBorderPainted(false); 153 | lastButton.setContentAreaFilled(false); 154 | lastButton.setLastButton(); 155 | lastButton.putClientProperty("position", new Point(i, j)); 156 | } else { 157 | 158 | buttons.add(button); 159 | } 160 | } 161 | } 162 | 163 | Collections.shuffle(buttons); 164 | buttons.add(lastButton); 165 | 166 | for (int i = 0; i < NUMBER_OF_BUTTONS; i++) { 167 | 168 | var btn = buttons.get(i); 169 | panel.add(btn); 170 | btn.setBorder(BorderFactory.createLineBorder(Color.gray)); 171 | btn.addActionListener(new ClickAction()); 172 | } 173 | 174 | pack(); 175 | 176 | setTitle("Puzzle"); 177 | setResizable(false); 178 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 179 | setLocationRelativeTo(null); 180 | } 181 | 182 | private int getNewHeight(int w, int h) { 183 | 184 | double ratio = DESIRED_WIDTH / (double) w; 185 | int newHeight = (int) (h * ratio); 186 | return newHeight; 187 | } 188 | 189 | private BufferedImage loadImage() throws IOException { 190 | 191 | var bimg = ImageIO.read(new File("src/resources/icesid.jpg")); 192 | 193 | return bimg; 194 | } 195 | 196 | private BufferedImage resizeImage(BufferedImage originalImage, int width, 197 | int height, int type) { 198 | 199 | var resizedImage = new BufferedImage(width, height, type); 200 | var g = resizedImage.createGraphics(); 201 | g.drawImage(originalImage, 0, 0, width, height, null); 202 | g.dispose(); 203 | 204 | return resizedImage; 205 | } 206 | 207 | private class ClickAction extends AbstractAction { 208 | 209 | @Override 210 | public void actionPerformed(ActionEvent e) { 211 | 212 | checkButton(e); 213 | checkSolution(); 214 | } 215 | 216 | private void checkButton(ActionEvent e) { 217 | 218 | int lidx = 0; 219 | 220 | for (MyButton button : buttons) { 221 | if (button.isLastButton()) { 222 | lidx = buttons.indexOf(button); 223 | } 224 | } 225 | 226 | var button = (JButton) e.getSource(); 227 | int bidx = buttons.indexOf(button); 228 | 229 | if ((bidx - 1 == lidx) || (bidx + 1 == lidx) 230 | || (bidx - 3 == lidx) || (bidx + 3 == lidx)) { 231 | Collections.swap(buttons, bidx, lidx); 232 | updateButtons(); 233 | } 234 | } 235 | 236 | private void updateButtons() { 237 | 238 | panel.removeAll(); 239 | 240 | for (JComponent btn : buttons) { 241 | 242 | panel.add(btn); 243 | } 244 | 245 | panel.validate(); 246 | } 247 | } 248 | 249 | private void checkSolution() { 250 | 251 | var current = new ArrayList(); 252 | 253 | for (JComponent btn : buttons) { 254 | current.add((Point) btn.getClientProperty("position")); 255 | } 256 | 257 | if (compareList(solution, current)) { 258 | JOptionPane.showMessageDialog(panel, "Finished", 259 | "Congratulation", JOptionPane.INFORMATION_MESSAGE); 260 | } 261 | } 262 | 263 | public static boolean compareList(List ls1, List ls2) { 264 | 265 | return ls1.toString().contentEquals(ls2.toString()); 266 | } 267 | 268 | public static void main(String[] args) { 269 | 270 | EventQueue.invokeLater(() -> { 271 | 272 | var puzzle = new PuzzleEx(); 273 | puzzle.setVisible(true); 274 | }); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Puzzle-game-in-Java-Swing 2 | Sources from the ZetCode's Puzzle game in Java Swing 3 | 4 | http://zetcode.com/javagames/puzzle/ 5 | 6 | ![Puzzle game screenshot](puzzle.png) 7 | 8 | Available under 2-Clause BSD License https://opensource.org/licenses/BSD-2-Clause 9 | -------------------------------------------------------------------------------- /icesid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Puzzle-game-in-Java-Swing/84ac2fa77a6007f6859f017ee68f3e1c7270ffae/icesid.jpg -------------------------------------------------------------------------------- /puzzle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Puzzle-game-in-Java-Swing/84ac2fa77a6007f6859f017ee68f3e1c7270ffae/puzzle.png --------------------------------------------------------------------------------