src/main/java/de/uapcore/sudoku/Field.java

Tue, 28 Jul 2020 14:27:14 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 28 Jul 2020 14:27:14 +0200
changeset 22
06170a0be62a
parent 12
1c62c6009161
permissions
-rw-r--r--

bugfix: modified state is reset even when saving fails + more tests

     1 /*
     2  * Copyright 2013 Mike Becker. All rights reserved.
     3  *
     4  * Redistribution and use in source and binary forms, with or without
     5  * modification, are permitted provided that the following conditions are met:
     6  *
     7  * 1. Redistributions of source code must retain the above copyright
     8  *    notice, this list of conditions and the following disclaimer.
     9  *
    10  * 2. Redistributions in binary form must reproduce the above copyright
    11  *    notice, this list of conditions and the following disclaimer in the
    12  *    documentation and/or other materials provided with the distribution.
    13  *
    14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    24  * POSSIBILITY OF SUCH DAMAGE.
    25  */
    27 package de.uapcore.sudoku;
    29 import javax.swing.*;
    30 import java.awt.*;
    31 import java.awt.image.BufferedImage;
    33 /**
    34  * A panel rendering the Sudoku field.
    35  * <p>
    36  * Cells are identified by zero-based indices from top-left to bottom-right.
    37  */
    38 public final class Field extends JPanel {
    39     private final SudokuTextField[][] cells;
    41     /**
    42      * Constructs a new 9x9 Sudoku grid.
    43      */
    44     public Field() {
    45         setBackground(Color.WHITE);
    47         setLayout(new GridBagLayout());
    48         GridBagConstraints c = new GridBagConstraints();
    49         c.insets = new Insets(5, 5, 5, 5);
    51         cells = new SudokuTextField[9][9];
    52         for (int x = 0; x < 9; x++) {
    53             for (int y = 0; y < 9; y++) {
    54                 cells[x][y] = new SudokuTextField();
    55                 c.gridx = x;
    56                 c.gridy = y;
    57                 add(cells[x][y], c);
    58             }
    59         }
    60     }
    62     /**
    63      * Paints the grid and all contained cells.
    64      *
    65      * @param graphics the graphics context
    66      */
    67     @Override
    68     public void paint(Graphics graphics) {
    69         final int w = getWidth();
    70         final int h = getHeight();
    71         final int cw = w / 9;
    72         final int ch = h / 9;
    74         BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    75         Graphics2D g = img.createGraphics();
    76         g.setBackground(Color.WHITE);
    77         g.clearRect(0, 0, w, h);
    79         g.setColor(Color.BLACK);
    80         g.drawRect(1, 1, w - 2, h - 2);
    81         g.drawRect(2, 2, w - 4, h - 4);
    82         for (int x = cw; x < w; x += cw) {
    83             for (int y = ch; y < h; y += ch) {
    84                 g.drawLine(x, 2, x, h - 2);
    85                 g.drawLine(2, y, w - 2, y);
    86                 if ((x / cw) % 3 == 0) {
    87                     g.drawLine(x + 1, 2, x + 1, h - 2);
    88                 }
    89                 if ((y / ch) % 3 == 0) {
    90                     g.drawLine(2, y + 1, w - 2, y + 1);
    91                 }
    92             }
    93         }
    95         graphics.drawImage(img, 0, 0, this);
    96         super.paintChildren(graphics);
    97     }
    99     /**
   100      * Checks whether a cell is empty
   101      *
   102      * @param x horizontal position
   103      * @param y vertical position
   104      * @return true if the cell is empty, false otherwise
   105      */
   106     public boolean isCellEmpty(int x, int y) {
   107         return getCellValue(x, y) == 0;
   108     }
   110     /**
   111      * Returns value of a specific cell.
   112      *
   113      * @param x horizontal position
   114      * @param y vertical position
   115      * @return the cell's value
   116      */
   117     public int getCellValue(int x, int y) {
   118         return cells[x][y].getValue();
   119     }
   121     /**
   122      * Sets the value of a specific cell.
   123      *
   124      * @param x horizontal position
   125      * @param y vertical position
   126      * @param v the cells value
   127      * @throws IllegalArgumentException if v is not between 0 and 9
   128      */
   129     public void setCellValue(int x, int y, int v) {
   130         cells[x][y].setValue(v);
   131     }
   133     /**
   134      * Clears the value of a specific cell.
   135      *
   136      * @param x horizontal position
   137      * @param y vertical position
   138      */
   139     public void clearCellValue(int x, int y) {
   140         setCellValue(x, y, 0);
   141     }
   143     /**
   144      * Sets the modified state of a specific cell.
   145      *
   146      * @param x        horizontal position
   147      * @param y        vertical position
   148      * @param modified the modified state
   149      */
   150     public void setCellModified(int x, int y, boolean modified) {
   151         cells[x][y].setModified(modified);
   152     }
   154     /**
   155      * Checks the modified state of a specific cell.
   156      *
   157      * @param x horizontal position
   158      * @param y vertical position
   159      * @return the modified state
   160      */
   161     public boolean isCellModified(int x, int y) {
   162         return cells[x][y].isModified();
   163     }
   165     /**
   166      * Sets the modified state of all cells.
   167      *
   168      * @param modified the modified state
   169      */
   170     public void setAllCellsModified(boolean modified) {
   171         for (int x = 0; x < 9; x++) {
   172             for (int y = 0; y < 9; y++) {
   173                 cells[x][y].setModified(modified);
   174             }
   175         }
   176     }
   178     /**
   179      * Checks whether any cell is modified.
   180      *
   181      * @return true if any cell is modified, false otherwise
   182      */
   183     public boolean isAnyCellModified() {
   184         for (int x = 0; x < 9; x++) {
   185             for (int y = 0; y < 9; y++) {
   186                 if (cells[x][y].isModified()) {
   187                     return true;
   188                 }
   189             }
   190         }
   191         return false;
   192     }
   194     /**
   195      * Clears all cells.
   196      */
   197     public void clear() {
   198         for (int x = 0; x < 9; x++) {
   199             for (int y = 0; y < 9; y++) {
   200                 cells[x][y].setValue(0);
   201             }
   202         }
   203     }
   205     /**
   206      * Returns a square identified by square coordinates.
   207      * <p>
   208      * Cells within the square are identified by the same coordinate system.
   209      *
   210      * @param x horizontal position from 0 to 2
   211      * @param y vertical position from 0 to 2
   212      * @return a two-dimensional array containing the square cell values
   213      * @throws IllegalArgumentException if the coordinates are out of bounds
   214      */
   215     public int[][] getSquare(int x, int y) {
   216         if (x < 0 || x > 2 || y < 0 || y > 2) {
   217             throw new IllegalArgumentException("Invalid square coordinates");
   218         }
   219         int[][] square = new int[3][3];
   221         for (int u = 0; u < 3; u++) {
   222             for (int v = 0; v < 3; v++) {
   223                 square[u][v] = getCellValue(3 * x + u, 3 * y + v);
   224             }
   225         }
   227         return square;
   228     }
   230     /**
   231      * Returns an entire row.
   232      *
   233      * @param y the row position
   234      * @return an array containing the row values
   235      * @throws IllegalArgumentException if y is not between 0 and 8
   236      */
   237     public int[] getRow(int y) {
   238         if (y < 0 || y > 8) {
   239             throw new IllegalArgumentException("Invalid row number");
   240         }
   241         int[] row = new int[9];
   243         for (int x = 0; x < 9; x++) {
   244             row[x] = getCellValue(x, y);
   245         }
   247         return row;
   248     }
   250     /**
   251      * Returns an entire column
   252      *
   253      * @param x the column position
   254      * @return an array containing the column values
   255      * @throws IllegalArgumentException if x is not between 0 and 8
   256      */
   257     public int[] getColumn(int x) {
   258         if (x < 0 || x > 8) {
   259             throw new IllegalArgumentException("Invalid column number");
   260         }
   261         int[] column = new int[9];
   263         for (int y = 0; y < 9; y++) {
   264             column[y] = getCellValue(x, y);
   265         }
   267         return column;
   268     }
   269 }

mercurial