原文www.zhangman523.cn/401.htmlhtml
先看看效果圖java
先看佈局,咱們能夠看到數獨由9x9
的格子組成,每一個格子中間有一個數字。android
Cell (單個格子、android
中咱們能夠先用TextView
代替)git
Grid (由3x3
的Cell
組成)github
Borad (由3x3
的 Grid
組成)數組
數獨是由
9x9
的格子組成,咱們能夠分爲3個3x3
的Grid
組成 佈局方式用RelativeLayout
來佈局。bash
數獨遊戲在每一行,每一列 和每一個Grid
中 1-9
數字不能重複佈局
每次輸入時檢查是否遊戲結束和錯誤。this
RelativeLayout
來實現 Grid
public class Grid extends RelativeLayout {
...
}
複製代碼
咱們定義3x3
的Cell
數組spa
private List<List<TextView>> mTextArrays;
複製代碼
用TextView
來表示單個格子
初始化Cell
mTextArrays = new ArrayList<>();
for (int i = 0; i < 3; i++) {
List<TextView> viewList = new ArrayList<>();
for (int j = 0; j < 3; j++) {
TextView textView = new TextView(context);
textView.setWidth(TEXT_SIZE);
textView.setHeight(TEXT_SIZE);
textView.setBackgroundColor(Color.WHITE);
textView.setId(View.generateViewId());
textView.setGravity(Gravity.CENTER);
addView(textView);
viewList.add(textView);
LayoutParams params = (LayoutParams) textView.getLayoutParams();
if (j == 0) {
if (i == 0) {
params.addRule(RelativeLayout.ALIGN_PARENT_START);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
} else if (i == 1) {
params.addRule(RelativeLayout.BELOW, mTextArrays.get(0).get(0).getId());
params.topMargin = DensityUtils.dp2px(context,1);
} else {
params.addRule(RelativeLayout.BELOW, mTextArrays.get(1).get(0).getId());
params.topMargin = DensityUtils.dp2px(context,1);
}
} else if (j == 1) {
params.addRule(RelativeLayout.RIGHT_OF, viewList.get(j - 1).getId());
params.addRule(ALIGN_TOP, viewList.get(j - 1).getId());
params.leftMargin = DensityUtils.dp2px(context,1);
} else {
params.addRule(RelativeLayout.RIGHT_OF, viewList.get(j - 1).getId());
params.addRule(ALIGN_TOP, viewList.get(j - 1).getId());
params.leftMargin = DensityUtils.dp2px(context,1);
}
}
mTextArrays.add(viewList);
}
複製代碼
RelativeLayout
來實現 Board
public class Board extends RelativeLayout{
...
}
複製代碼
實現也是跟Grid
實現同樣,只是Grid
做爲子View
private List<List<Grid>> mGridArray = new ArrayList<>(); //3x3 的Grid
private List<List<TextView>> mCellArray; //9x9的Cell
private TextView mCurrentCell; //當前選中的Cell
private String mErrorTextColor = "#ff0000";//錯誤時候的文字顏色
private String mLightTextColor = "#ffffff";//選中時候的文字顏色
private String mDefaultTextColor = "#000000";//默認文字顏色
private String mLightBgColor = "#4fe8fc";//選中的背景顏色
private String mDefaultBgColor = "#ffffff";//默認背景顏色
private String mDisableTextColor = "#e2e2e2";//不可編輯的文字顏色
複製代碼
初始化 mGridArray
的邏輯和Grid
同樣就不貼代碼了。本身去看>_<!
mCellArray = new ArrayList<>();
for (int i = 0; i < 9; i++) {//初始化Cell Array
List<TextView> cellArray = new ArrayList<>();
for (int j = 0; j < 9; j++) {
int x = i < 3 ? 0 : i < 6 ? 1 : 2; //3x3 的格子
int y = j < 3 ? 0 : j < 6 ? 1 : 2;
Grid grid = mGridArray.get(x).get(y);
List<List<TextView>> gridTextArrays = grid.getTextArrays();
TextView cell = gridTextArrays.get(i - x * 3).get(j - y * 3);
cell.setTag(R.id.row, i);//設置tag 信息
cell.setTag(R.id.column, j);
cell.setTag(R.id.isLoad, false);
cell.setTextColor(Color.parseColor(mDefaultTextColor));
cell.setBackgroundColor(Color.parseColor(mDefaultBgColor));
cell.setOnClickListener(this);
cellArray.add(j, cell);
}
mCellArray.add(i, cellArray);
}
複製代碼
map
數獨的map
咱們用81位長度的字符串來表示 0表示須要補全的,1-9 爲默認的數字
找一個默認的地圖
005406000000000201007380000062700090050023804704109060823590010490867020576031948
複製代碼
加載方法
/** * load sudoku map * * @param map map */
public void loadMap(String map) {
if (TextUtils.isEmpty(map)) return;
for (int i = 0; i < mCellArray.size(); i++) {
List<TextView> array = mCellArray.get(i);
for (int j = 0; j < array.size(); j++) {
TextView cell = array.get(j);//將81位的字符串 轉爲 9x9 的數組
String s = map.substring(9 * i + j, 9 * i + j + 1);
if (!"0".equals(s)) {
cell.setText(s);
cell.setTag(R.id.isLoad, true);
cell.setTextColor(Color.parseColor(mDisableTextColor));
}
}
}
}
複製代碼
/** * Highlight the grid by row and column * * @param row row * @param column column */
private void lightUpCellByRowAndColumn(int row, int column) {
boolean lightText = !TextUtils.isEmpty(mCellArray.get(row).get(column).getText().toString());
//這裏作了個判斷 若是是有數字 則高亮全部同樣的數字 不然高亮選中行和列
if (lightText) {
lightSameNumber(row, column, false);
} else {
lightRowAndColumn(row, column);
}
}
複製代碼
遍歷Cell
數組選中相同的數字
/** * Highlight the same number * * @param row row * @param column column * @param isError error */
private void lightSameNumber(int row, int column, boolean isError) {
String value = mCellArray.get(row).get(column).getText().toString();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (value.equals(mCellArray.get(i).get(j).getText().toString())) {
//change number color
if (i == row && column == j) {
//If it is wrong, change the text color without changing the background.
if (isError || mCellArray.get(i).get(j).getCurrentTextColor() == Color.parseColor(mErrorTextColor)) {
mCellArray.get(i).get(j).setBackgroundColor(Color.parseColor(mErrorTextColor));
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mLightTextColor));
} else {
mCellArray.get(i).get(j).setBackgroundColor(Color.parseColor(mLightBgColor));
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mLightTextColor));
}
} else {
if (mCellArray.get(i).get(j).getCurrentTextColor() == Color.parseColor(mErrorTextColor)) {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mErrorTextColor));
} else {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mLightTextColor));
}
mCellArray.get(i).get(j).setBackgroundColor(Color.parseColor(mLightBgColor));
}
} else {
if ((Boolean) mCellArray.get(i).get(j).getTag(R.id.isLoad)) {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mDisableTextColor));
} else {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mDefaultTextColor));
}
mCellArray.get(i).get(j).setBackgroundColor(Color.parseColor(mDefaultBgColor));
}
}
}
}
複製代碼
遍歷Cell
數組高亮行和列
/** * Highlight row and column * * @param row row * @param column column */
private void lightRowAndColumn(int row, int column) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (i == row || j == column) {
if (mCellArray.get(i).get(j).getCurrentTextColor() == Color.parseColor(mErrorTextColor)) {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mErrorTextColor));
}
mCellArray.get(i).get(j).setBackgroundColor(Color.parseColor(mLightBgColor));
} else {
if ((Boolean) mCellArray.get(i).get(j).getTag(R.id.isLoad)) {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mDisableTextColor));
} else {
if (mCellArray.get(i).get(j).getCurrentTextColor() == Color.parseColor(mErrorTextColor)) {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mErrorTextColor));
} else {
mCellArray.get(i).get(j).setTextColor(Color.parseColor(mDefaultTextColor));
}
}
mCellArray.get(i).get(j).setBackgroundColor(Color.parseColor(mLightTextColor));
}
}
}
mCellArray.get(row).get(column).setBackgroundColor(Color.parseColor(mLightBgColor));
}
複製代碼
每次輸入咱們須要判斷遊戲是否結束(數字重複或者完成數獨)
/** * Enter a number from 1-9 * * @param number number */
public void inputText(String number) {
if (mCurrentCell == null) return;
if (!(Boolean) mCurrentCell.getTag(R.id.isLoad)) {
mCurrentCell.setText(number);
boolean gameOver = checkFinish();
if (gameOver) {
if (mGameOverCallBack != null) mGameOverCallBack.gameOver();
}
}
}
複製代碼
checkFinish()
方法中包括檢查錯誤的方法,重複的數字須要高亮。須要檢查行、列和宮(3x3的Grid
)
/** * check game error * * @param row row * @param column column * @return boolean */
private boolean checkGameError(int row, int column) {
boolean result = false;
result = checkSection(row, column);
if (result) return result;
//check row
for (int i = 0; i < 9; i++) {
String value = mCellArray.get(i).get(column).getText().toString();
if (TextUtils.isEmpty(value)) continue;
for (int j = i; j < 9; j++) {
if (i == j) continue;
if (value.equals(mCellArray.get(j).get(column).getText().toString())) {
Log.d(TAG, String.format("row error,value:%1$s in row:%2$d and column:%3$d", value, row, column));
result = true;
break;
}
}
}
if (result) return result;
//check column
for (int i = 0; i < 9; i++) {
String value = mCellArray.get(row).get(i).getText().toString();
if (TextUtils.isEmpty(value)) continue;
for (int j = i; j < 9; j++) {
if (i == j) continue;
if (value.equals(mCellArray.get(row).get(j).getText().toString())) {
Log.d(TAG, String.format("column error,value:%1$s in row:%2$d and column:%3$d", value, row, column));
result = true;
break;
}
}
}
return result;
}
複製代碼
檢查3x3
格子中是否有重複的數字
/** * check duplicate numbers in the 3x3 grid * * @param row row * @param column column * @return true or false */
private boolean checkSection(int row, int column) {
boolean result = false;
String value = mCellArray.get(row).get(column).getText().toString();
if (TextUtils.isEmpty(value)) {
return result;
}
int start_i = row < 3 ? 0 : (row < 6 ? 3 : 6);//3x3 格子的邊界
int start_j = column < 3 ? 0 : (column < 6 ? 3 : 6);
int end_i = start_i + 3;
int end_j = start_j + 3;
for (int i = start_i; i < end_i; i++) {
for (int j = start_j; j < end_j; j++) {
if (i == row && j == column) continue;
if (value.equals(mCellArray.get(i).get(j).getText().toString())) {//若是3x3格子的內容有重複的數字則返回錯誤
Log.d(TAG, String.format("section error,value:%1$s in row:%2$d and column:%3$d", value, row, column));
result = true;
break;
}
}
}
return result;
}
複製代碼
遊戲的邏輯已經完成了。你們能夠去下載代碼運行玩玩!
工程已經放在GITHUB