实例介绍
【实例截图】


【核心代码】
/*
* 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小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论