实例介绍
【实例截图】
【核心代码】
/* * Copyright (C) 2009 Roman Masek * * This file is part of OpenSudoku. * * OpenSudoku is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenSudoku is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenSudoku. If not, see <http://www.gnu.org/licenses/>. * */ package cz.romario.opensudoku.game; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.regex.Pattern; import android.os.Parcel; import android.os.Parcelable; /** * Collection of sudoku cells. This class in fact represents one sudoku board (9x9). * * @author romario * */ public class CellCollection { public static final int SUDOKU_SIZE = 9; /** * String is expected to be in format "00002343243202...", where each number represents * cell value, no other information can be set using this method. */ public static int DATA_VERSION_PLAIN = 0; /** * See {@link #DATA_PATTERN_VERSION_1} and {@link #serialize()}. */ public static int DATA_VERSION_1 = 1; // TODO: An array of ints is a much better than an array of Integers, but this also generalizes to the fact that two parallel arrays of ints are also a lot more efficient than an array of (int,int) objects // Cell's data. private Cell[][] mCells; // Helper arrays, contains references to the groups of cells, which should contain unique // numbers. private CellGroup[] mSectors; private CellGroup[] mRows; private CellGroup[] mColumns; private boolean mOnChangeEnabled = true; private final List<OnChangeListener> mChangeListeners = new ArrayList<OnChangeListener>(); /** * Creates empty sudoku. * @return */ public static CellCollection createEmpty() { Cell[][] cells = new Cell[SUDOKU_SIZE][SUDOKU_SIZE]; for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ) { cells[r][c] = new Cell(); } } return new CellCollection(cells); } /** * Return true, if no value is entered in any of cells. * * @return */ public boolean isEmpty() { for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ){ Cell cell = mCells[r][c]; if (cell.getValue() != 0) return false; } } return true; } /** * Generates debug game. * * @return */ public static CellCollection createDebugGame() { CellCollection debugGame = new CellCollection(new Cell[][] { { new Cell(), new Cell(), new Cell(), new Cell(4), new Cell(5), new Cell(6), new Cell(7), new Cell(8), new Cell(9),}, { new Cell(), new Cell(), new Cell(), new Cell(7), new Cell(8), new Cell(9), new Cell(1), new Cell(2), new Cell(3),}, { new Cell(), new Cell(), new Cell(), new Cell(1), new Cell(2), new Cell(3), new Cell(4), new Cell(5), new Cell(6),}, { new Cell(2), new Cell(3), new Cell(4), new Cell(), new Cell(), new Cell(), new Cell(8), new Cell(9), new Cell(1),}, { new Cell(5), new Cell(6), new Cell(7), new Cell(), new Cell(), new Cell(), new Cell(2), new Cell(3), new Cell(4),}, { new Cell(8), new Cell(9), new Cell(1), new Cell(), new Cell(), new Cell(), new Cell(5), new Cell(6), new Cell(7),}, { new Cell(3), new Cell(4), new Cell(5), new Cell(6), new Cell(7), new Cell(8), new Cell(9), new Cell(1), new Cell(2),}, { new Cell(6), new Cell(7), new Cell(8), new Cell(9), new Cell(1), new Cell(2), new Cell(3), new Cell(4), new Cell(5),}, { new Cell(9), new Cell(1), new Cell(2), new Cell(3), new Cell(4), new Cell(5), new Cell(6), new Cell(7), new Cell(8),}, }); debugGame.markFilledCellsAsNotEditable(); return debugGame; } public Cell[][] getCells() { return mCells; } /** * Wraps given array in this object. * @param cells */ private CellCollection(Cell[][] cells) { mCells = cells; initCollection(); } /** * Gets cell at given position. * @param rowIndex * @param colIndex * @return */ public Cell getCell(int rowIndex, int colIndex) { return mCells[rowIndex][colIndex]; } public void markAllCellsAsValid() { mOnChangeEnabled = false; for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ) { mCells[r][c].setValid(true); } } mOnChangeEnabled = true; onChange(); } /** * Validates numbers in collection according to the sudoku rules. Cells with invalid * values are marked - you can use getInvalid method of cell to find out whether cell * contains valid value. * * @return True if validation is successful. */ public boolean validate() { boolean valid = true; // first set all cells as valid markAllCellsAsValid(); mOnChangeEnabled = false; // run validation in groups for (CellGroup row : mRows) { if (!row.validate()) { valid = false; } } for (CellGroup column : mColumns) { if (!column.validate()) { valid = false; } } for (CellGroup sector : mSectors) { if (!sector.validate()) { valid = false; } } mOnChangeEnabled = true; onChange(); return valid; } public boolean isCompleted() { for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ) { Cell cell = mCells[r][c]; if (cell.getValue() == 0 || !cell.isValid()) { return false; } } } return true; } /** * Marks all cells as editable. */ public void markAllCellsAsEditable() { for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ){ Cell cell = mCells[r][c]; cell.setEditable(true); } } } /** * Marks all filled cells (cells with value other than 0) as not editable. */ public void markFilledCellsAsNotEditable() { for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ){ Cell cell = mCells[r][c]; cell.setEditable(cell.getValue() == 0); } } } /** * Returns how many times each value is used in <code>CellCollection</code>. * Returns map with entry for each value. * * @return */ public Map<Integer, Integer> getValuesUseCount() { Map<Integer, Integer> valuesUseCount = new HashMap<Integer, Integer>(); for (int value = 1; value <= CellCollection.SUDOKU_SIZE; value ) { valuesUseCount.put(value, 0); } for (int r = 0; r < CellCollection.SUDOKU_SIZE; r ) { for (int c = 0; c < CellCollection.SUDOKU_SIZE; c ) { int value = getCell(r, c).getValue(); if (value != 0) { valuesUseCount.put(value, valuesUseCount.get(value) 1); } } } return valuesUseCount; } /** * Initializes collection, initialization has two steps: * 1) Groups of cells which must contain unique numbers are created. * 2) Row and column index for each cell is set. */ private void initCollection() { mRows = new CellGroup[SUDOKU_SIZE]; mColumns = new CellGroup[SUDOKU_SIZE]; mSectors = new CellGroup[SUDOKU_SIZE]; for (int i=0; i<SUDOKU_SIZE; i ) { mRows[i] = new CellGroup(); mColumns[i] = new CellGroup(); mSectors[i] = new CellGroup(); } for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ) { Cell cell = mCells[r][c]; cell.initCollection(this, r, c, mSectors[((c/3) * 3) (r/3)], mRows[c], mColumns[r] ); } } } /** * Creates instance from given <code>StringTokenizer</code>. * * @param data * @return */ public static CellCollection deserialize(StringTokenizer data) { Cell[][] cells = new Cell[SUDOKU_SIZE][SUDOKU_SIZE]; int r = 0, c = 0; while (data.hasMoreTokens() && r < 9) { cells[r][c] = Cell.deserialize(data); c ; if (c == 9) { r ; c = 0; } } return new CellCollection(cells); } /** * Creates instance from given string (string which has been * created by {@link #serialize(StringBuilder)} or {@link #serialize()} method). * earlier. * * @param note */ public static CellCollection deserialize(String data) { // TODO: use DATA_PATTERN_VERSION_1 to validate and extract puzzle data String[] lines = data.split("\n"); if (lines.length == 0) { throw new IllegalArgumentException("Cannot deserialize Sudoku, data corrupted."); } if (lines[0].equals("version: 1")) { StringTokenizer st = new StringTokenizer(lines[1], "|"); return deserialize(st); } else { return fromString(data); } } /** * Creates collection instance from given string. String is expected * to be in format "00002343243202...", where each number represents * cell value, no other information can be set using this method. * * @param data * @return */ public static CellCollection fromString(String data) { // TODO: validate Cell[][] cells = new Cell[SUDOKU_SIZE][SUDOKU_SIZE]; int pos = 0; for (int r = 0; r < CellCollection.SUDOKU_SIZE; r ) { for (int c = 0; c < CellCollection.SUDOKU_SIZE; c ) { int value = 0; while (pos < data.length()) { pos ; if (data.charAt(pos - 1) >= '0' && data.charAt(pos - 1) <= '9') { // value=Integer.parseInt(data.substring(pos-1, pos)); value = data.charAt(pos - 1) - '0'; break; } } Cell cell = new Cell(); cell.setValue(value); cell.setEditable(value == 0); cells[r][c] = cell; } } return new CellCollection(cells); } public String serialize() { StringBuilder sb = new StringBuilder(); serialize(sb); return sb.toString(); } /** * Writes collection to given StringBuilder. You can later recreate the object instance * by calling {@link #deserialize(String)} method. * @return */ public void serialize(StringBuilder data) { data.append("version: 1\n"); for (int r=0; r<SUDOKU_SIZE; r ) { for (int c=0; c<SUDOKU_SIZE; c ) { Cell cell = mCells[r][c]; cell.serialize(data); } } } private static Pattern DATA_PATTERN_VERSION_PLAIN = Pattern.compile("^\\d{81}$"); private static Pattern DATA_PATTERN_VERSION_1 = Pattern.compile("^version: 1\\n((?#value)\\d\\|(?#note)((\\d,) |-)\\|(?#editable)[01]\\|){0,81}$"); /** * Returns true, if given <code>data</code> conform to format of given data version. * * @param data * @param dataVersion * @return */ public static boolean isValid(String data, int dataVersion) { if (dataVersion == DATA_VERSION_PLAIN) { return DATA_PATTERN_VERSION_PLAIN.matcher(data).matches(); } else if (dataVersion == DATA_VERSION_1) { return DATA_PATTERN_VERSION_1.matcher(data).matches(); } else { throw new IllegalArgumentException("Unknown version: " dataVersion); } } public void addOnChangeListener(OnChangeListener listener) { if (listener == null) { throw new IllegalArgumentException("The listener is null."); } synchronized (mChangeListeners) { if (mChangeListeners.contains(listener)) { throw new IllegalStateException("Listener " listener "is already registered."); } mChangeListeners.add(listener); } } public void removeOnChangeListener(OnChangeListener listener) { if (listener == null) { throw new IllegalArgumentException("The listener is null."); } synchronized (mChangeListeners) { if (!mChangeListeners.contains(listener)) { throw new IllegalStateException("Listener " listener " was not registered."); } mChangeListeners.remove(listener); } } /** * Returns whether change notification is enabled. * * If true, change notifications are distributed to the listeners * registered by {@link #addOnChangeListener(OnChangeListener)}. * * @return */ // public boolean isOnChangeEnabled() { // return mOnChangeEnabled; // } // // /** // * Enables or disables change notifications, that are distributed to the listeners // * registered by {@link #addOnChangeListener(OnChangeListener)}. // * // * @param onChangeEnabled // */ // public void setOnChangeEnabled(boolean onChangeEnabled) { // mOnChangeEnabled = onChangeEnabled; // } /** * Notify all registered listeners that something has changed. */ protected void onChange() { if (mOnChangeEnabled) { synchronized (mChangeListeners) { for (OnChangeListener l : mChangeListeners) { l.onChange(); } } } } public interface OnChangeListener { /** * Called when anything in the collection changes (cell's value, note, etc.) */ void onChange(); } }
标签: 游戏 九宫格 OpenSudoku
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论