数独(ナンプレ)を解きます。現時点では9×9の問題にしか対応していません。解く問題をCSVファイルで指定します。値のないところは空欄で大丈夫です。
- 構文
- Sudoku.Solved( path )
- 引数
- path
- 解きたい問題を記述したCSVファイル
- 戻値
プログラム
//////////////////////////////////////////////////
// 【引数】
// path : 解きたい問題を記述したCSVファイル
// 【戻値】
//
//////////////////////////////////////////////////
MODULE Sudoku
PROCEDURE Sudoku()
PUBLIC data[9][9]
SETCLEAR(data, 0)
PUBLIC candidate[9][9]
SETCLEAR(candidate, 511)
PUBLIC Excel
Excel = ExcelBoot()
Excel.Range("A:I").Columns.ColumnWidth = 10
Excel.Application.DisplayAlerts = FALSE
FEND
// 罫線を描く
PROCEDURE drawBorder(vertical, horizontal = vertical)
CONST xlContinuous = 1
CONST xlMedium = -4138
WITH Excel
.Range(.Cells(1, 1), .Cells(vertical, horizontal)).Borders.LineStyle = xlContinuous
v = SQRT(vertical)
h = SQRT(horizontal)
FOR r = 1 TO v
FOR c = 1 TO h
.Range(.Cells(r * v - (v - 1), c * h - (h - 1)), .Cells(r * v, c * h)).BorderAround(xlContinuous, xlMedium)
NEXT
NEXT
ENDWITH
FEND
// 解く
PROCEDURE Solved(path)//, Var data[][], Var candidate[][])
drawBorder(9)
Sudoku.readQuestion(path, data, candidate)
REPEAT
DIM sum = CALCARRAY(data, CALC_ADD)
Sudoku.FullHouse(data, candidate)
Sudoku.Single(data, candidate)
UNTIL CALCARRAY(data, CALC_ADD) = sum
FEND
// 問題を取得
PROCEDURE readQuestion(path, Var data[][], Var candidate[][])
DIM FID = FOPEN(path)
FOR row = 0 TO 8
FOR col = 0 TO 8
FUKIDASI(row + ", " + col)
DIM str = FGET(FID, row + 1, col + 1)
num = POWER(2, VAL(str) - 1)
IFB num >= 1 THEN
data[row][col] = num
IFB data[row][col] <> 0 THEN
Excel.Cells(row+1, col+1).Font.Bold = TRUE
setValue(data[row][col], row, col, data, candidate)
ENDIF
ENDIF
NEXT
NEXT
FCLOSE(FID)
FEND
PROCEDURE FullHouse(Var data[][], Var candidate[][])
FEND
PROCEDURE Single(Var data[][], Var candidate[][])
// 行
FOR col = 0 TO 8
FOR n = 1 TO 9
rCnt = 0
targetRow = 0
FOR row = 0 TO 8
IFB data[row][col] = 0 THEN
IFB candidate[row][col] AND POWER(2, n - 1)
targetRow = row
rCnt = rCnt + 1
ENDIF
ENDIF
NEXT
IFB rCnt = 1 THEN
setValue(POWER(2, n - 1), targetRow, col, data, candidate)
ENDIF
NEXT
NEXT
// 列
FOR row = 0 TO 8
FOR n = 1 TO 9
cCnt = 0
targetCol = 0
FOR col = 0 TO 8
IFB data[row][col] = 0 THEN
IFB candidate[row][col] AND POWER(2, n - 1) THEN
targetCol = col
cCnt = cCnt + 1
ENDIF
ENDIF
NEXT
IFB cCnt = 1 THEN
setValue(POWER(2, n - 1), row, targetCol, data, candidate)
ENDIF
NEXT
NEXT
FEND
PROCEDURE setValue(num, row, col, Var data[], Var candidate[])
IFB num <> 0 THEN
data[row][col] = LOGN(2, num) + 1
Excel.Cells(row+1, col+1) = data[row][col]
candidate[row][col] = num
Excel.Cells(row+11, col+1) = "'" + bit(candidate[row][col], 9)
setRow(num, row, col, candidate)
setColumn(num, row, col, candidate)
setBlock(num, row, col, candidate)
ENDIF
FEND
PROCEDURE setRow(num, row, col, Var array[][])
FOR r = 0 TO 8
IFB r <> row THEN
DIM a = array[r][col]
DIM b = NOT(num, 9)
array[r][col] = a AND b
Excel.Cells(r+11, col+1) = "'" + bit(array[r][col], 9)
ENDIF
NEXT
FEND
PROCEDURE setColumn(num, row, col, Var array[][])
FOR c = 0 TO 8
IFB c <> col THEN
DIM a = array[row][c]
DIM b = NOT(num, 9)
array[row][c] = a AND b
Excel.Cells(row+11, c+1) = "'" + bit(array[row][c], 9)
ENDIF
NEXT
FEND
PROCEDURE setBlock(num, row, col, Var array[][])
DIM ofsRow = INT(row / 3) * 3
DIM ofsCol = INT(col / 3) * 3
FOR r = ofsRow TO ofsRow + 2
FOR c = ofsCol TO ofsCol + 2
IF r = row AND c = col THEN CONTINUE
array[r][c] = array[r][c] AND NOT(num, 9)
Excel.Cells(r+11, c+1) = "'" + bit(array[r][c], 9)
NEXT
NEXT
FEND
ENDMODULE
//////////////////////////////////////////////////
// 【引数】
// path : 開くファイルのパス名
// 【戻値】
// Excelオブジェクト
//////////////////////////////////////////////////
FUNCTION ExcelBoot(path = "")
DIM Excel = CREATEOLEOBJ("Excel.Application")
Excel.Visible = TRUE
IFB path = "" THEN
Excel.Workbooks.Add
ELSE
DIM FSO = CREATEOLEOBJ("Scripting.FileSystemObject")
IFB FSO.GetParentFolderName(path) = "" THEN
path = GET_CUR_DIR + "\" + path
ENDIF
Excel.Workbooks.Open(path)
ENDIF
RESULT = Excel
FEND