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

Tue, 28 Jul 2020 14:44:48 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 28 Jul 2020 14:44:48 +0200
changeset 23
07b9adaed78e
parent 22
06170a0be62a
permissions
-rw-r--r--

adds solver test

/*
 * Copyright 2013 Mike Becker. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package de.uapcore.sudoku;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * A panel rendering the Sudoku field.
 * <p>
 * Cells are identified by zero-based indices from top-left to bottom-right.
 */
public final class Field extends JPanel {
    private final SudokuTextField[][] cells;

    /**
     * Constructs a new 9x9 Sudoku grid.
     */
    public Field() {
        setBackground(Color.WHITE);

        setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(5, 5, 5, 5);

        cells = new SudokuTextField[9][9];
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                cells[x][y] = new SudokuTextField();
                c.gridx = x;
                c.gridy = y;
                add(cells[x][y], c);
            }
        }
    }

    /**
     * Paints the grid and all contained cells.
     *
     * @param graphics the graphics context
     */
    @Override
    public void paint(Graphics graphics) {
        final int w = getWidth();
        final int h = getHeight();
        final int cw = w / 9;
        final int ch = h / 9;

        BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = img.createGraphics();
        g.setBackground(Color.WHITE);
        g.clearRect(0, 0, w, h);

        g.setColor(Color.BLACK);
        g.drawRect(1, 1, w - 2, h - 2);
        g.drawRect(2, 2, w - 4, h - 4);
        for (int x = cw; x < w; x += cw) {
            for (int y = ch; y < h; y += ch) {
                g.drawLine(x, 2, x, h - 2);
                g.drawLine(2, y, w - 2, y);
                if ((x / cw) % 3 == 0) {
                    g.drawLine(x + 1, 2, x + 1, h - 2);
                }
                if ((y / ch) % 3 == 0) {
                    g.drawLine(2, y + 1, w - 2, y + 1);
                }
            }
        }

        graphics.drawImage(img, 0, 0, this);
        super.paintChildren(graphics);
    }

    /**
     * Checks whether a cell is empty
     *
     * @param x horizontal position
     * @param y vertical position
     * @return true if the cell is empty, false otherwise
     */
    public boolean isCellEmpty(int x, int y) {
        return getCellValue(x, y) == 0;
    }

    /**
     * Returns value of a specific cell.
     *
     * @param x horizontal position
     * @param y vertical position
     * @return the cell's value
     */
    public int getCellValue(int x, int y) {
        return cells[x][y].getValue();
    }

    /**
     * Sets the value of a specific cell.
     *
     * @param x horizontal position
     * @param y vertical position
     * @param v the cells value
     * @throws IllegalArgumentException if v is not between 0 and 9
     */
    public void setCellValue(int x, int y, int v) {
        cells[x][y].setValue(v);
    }

    /**
     * Clears the value of a specific cell.
     *
     * @param x horizontal position
     * @param y vertical position
     */
    public void clearCellValue(int x, int y) {
        setCellValue(x, y, 0);
    }

    /**
     * Sets the modified state of a specific cell.
     *
     * @param x        horizontal position
     * @param y        vertical position
     * @param modified the modified state
     */
    public void setCellModified(int x, int y, boolean modified) {
        cells[x][y].setModified(modified);
    }

    /**
     * Checks the modified state of a specific cell.
     *
     * @param x horizontal position
     * @param y vertical position
     * @return the modified state
     */
    public boolean isCellModified(int x, int y) {
        return cells[x][y].isModified();
    }

    /**
     * Sets the modified state of all cells.
     *
     * @param modified the modified state
     */
    public void setAllCellsModified(boolean modified) {
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                cells[x][y].setModified(modified);
            }
        }
    }

    /**
     * Checks whether any cell is modified.
     *
     * @return true if any cell is modified, false otherwise
     */
    public boolean isAnyCellModified() {
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                if (cells[x][y].isModified()) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Clears all cells.
     */
    public void clear() {
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                cells[x][y].setValue(0);
            }
        }
    }

    /**
     * Returns a square identified by square coordinates.
     * <p>
     * Cells within the square are identified by the same coordinate system.
     *
     * @param x horizontal position from 0 to 2
     * @param y vertical position from 0 to 2
     * @return a two-dimensional array containing the square cell values
     * @throws IllegalArgumentException if the coordinates are out of bounds
     */
    public int[][] getSquare(int x, int y) {
        if (x < 0 || x > 2 || y < 0 || y > 2) {
            throw new IllegalArgumentException("Invalid square coordinates");
        }
        int[][] square = new int[3][3];

        for (int u = 0; u < 3; u++) {
            for (int v = 0; v < 3; v++) {
                square[u][v] = getCellValue(3 * x + u, 3 * y + v);
            }
        }

        return square;
    }

    /**
     * Returns an entire row.
     *
     * @param y the row position
     * @return an array containing the row values
     * @throws IllegalArgumentException if y is not between 0 and 8
     */
    public int[] getRow(int y) {
        if (y < 0 || y > 8) {
            throw new IllegalArgumentException("Invalid row number");
        }
        int[] row = new int[9];

        for (int x = 0; x < 9; x++) {
            row[x] = getCellValue(x, y);
        }

        return row;
    }

    /**
     * Returns an entire column
     *
     * @param x the column position
     * @return an array containing the column values
     * @throws IllegalArgumentException if x is not between 0 and 8
     */
    public int[] getColumn(int x) {
        if (x < 0 || x > 8) {
            throw new IllegalArgumentException("Invalid column number");
        }
        int[] column = new int[9];

        for (int y = 0; y < 9; y++) {
            column[y] = getCellValue(x, y);
        }

        return column;
    }
}

mercurial