数独Sudoku游戏解题C语言和Golang(Go语言)实现

Go语言实现

package main

import (
	"fmt"
	"os"
)

const (
	N         = 9
	EmptyCell = '0'
)

func main() {
	if len(os.Args) != 2 || len(os.Args[1]) != 81 {
		fmt.Println("错误:程序需要一个正好包含 81 位数字的参数。")
		os.Exit(1)
	}

	board := parseBoard(os.Args[1])
	fmt.Println("未解决的数独:")
	printGrid(board)
	if solveSudoku(&board) {
		fmt.Println("已解决数独:")
		printGrid(board)
	} else {
		fmt.Println("没有解决方案")
	}
}

// parseBoard
// 将字符串转换为 81 位数字的二维数组
func parseBoard(input string) [N][N]rune {
	var board [N][N]rune
	for i, char := range input {
		board[i/N][i%N] = char
	}
	return board
}

// solveSudoku
// 采用部分填充的网格,并尝试将值分配给所有未分配的位置,以满足数独解决方案的要求
func solveSudoku(grid *[N][N]rune) bool {
	row, col := findEmptyCell(grid)
	if row == -1 {
		return true
	}

	for num := '1'; num <= '9'; num++ {
		if isSafe(grid, row, col, num) {
			grid[row][col] = num
			if solveSudoku(grid) {
				return true
			}
			grid[row][col] = EmptyCell // 回溯
		}
	}

	return false
}

// findEmptyCell
// 返回未填充的单元格的行和列
func findEmptyCell(board *[N][N]rune) (int, int) {
	for i := 0; i < N; i++ {
		for j := 0; j < N; j++ {
			if board[i][j] == EmptyCell {
				return i, j
			}
		}
	}
	return -1, -1
}

// isSafe
// 检查将 num 分配给给定的行是否合法
func isSafe(board *[N][N]rune, row, col int, num rune) bool {
	// 检查此行
	for x := 0; x < N; x++ {
		if board[row][x] == num {
			return false
		}
	}

	// 检查此列
	for y := 0; y < N; y++ {
		if board[y][col] == num {
			return false
		}
	}

	// 选中此框
	startRow := row - row%3
	startCol := col - col%3
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			if board[i+startRow][j+startCol] == num {
				return false
			}
		}
	}

	return true
}

// printGrid
// 打印网格
func printGrid(board [N][N]rune) {
	for i := 0; i < N; i++ {
		for j := 0; j < N; j++ {
			fmt.Printf("%c ", board[i][j])
		}
		fmt.Println()
	}
}

C语言实现

#include <stdio.h>
#include <string.h>
#include <locale.h>

#define UNASSIGNED 0
#define N 9

// 检查将 num 分配给给定行是否合法的函数
int isSafe(int grid[N][N], int row, int col, int num);

// 打印网格
void printGrid(int grid[N][N]) {
    for (int row = 0; row < N; row++) {
        for (int col = 0; col < N; col++)
            printf("%2d", grid[row][col]);
        printf("\n");
    }
}

// 此函数在网格中查找仍未分配的条目
int findUnassignedLocation(int grid[N][N], int *row, int *col) {
    for (*row = 0; *row < N; (*row)++)
        for (*col = 0; *col < N; (*col)++)
            if (grid[*row][*col] == UNASSIGNED)
                return 1;
    return 0;
}

// 检查将 num 分配给给定的行是否合法
int isSafe(int grid[N][N], int row, int col, int num) {
    // 检查“num”是否尚未放置在当前行、当前列和当前 3x3 框中
    int boxStartRow = row - row % 3;
    int boxStartCol = col - col % 3;

    for (int i = 0; i < N; i++)
        if (grid[row][i] == num || grid[i][col] == num || grid[boxStartRow + i / 3][boxStartCol + i % 3] == num)
            return 0;

    return 1;
}

// 采用部分填充的网格,并尝试将值分配给所有未分配的位置,以满足数独解决方案的要求
int solveSudoku(int grid[N][N]) {
    int row, col;

    // 如果没有未分配的位置,我们就完成了
    if (!findUnassignedLocation(grid, &row, &col))
        return 1; // 成功!

    // 数字 1 到 9
    for (int num = 1; num <= N; num++) {
        // 如果合法
        if (isSafe(grid, row, col, num)) {
            // 进行暂定分配
            grid[row][col] = num;

            // 如果成功,则返回
            if (solveSudoku(grid))
                return 1;

            // 失败,取消并重试
            grid[row][col] = UNASSIGNED;
        }
    }

    return 0; // 触发回溯
}

int main(int argc, char *argv[]) {
    // 设置C库函数使用的locale
    setlocale(LC_ALL, "");
    int grid[N][N];

    // 检查是否提供了正确数量的参数
    if (argc != 2 || strlen(argv[1]) != N*N) {
        wprintf(L"错误:程序需要一个正好包含 81 位数字的参数。\n");
        return 1;
    }

    // 将输入字符解析为网格
    for (int i = 0; i < N*N; i++) {
        if (argv[1][i] >= '0' && argv[1][i] <= '9') {
            grid[i/N][i%N] = argv[1][i] - '0';
        } else {
            wprintf(L"错误:参数应仅包含数字。\n");
            return 1;
        }
    }

    // 在求解之前打印网格
    wprintf(L"未解决的数独:\n");
    printGrid(grid);

    // 如果成功,打印已解决的数独题
    if (solveSudoku(grid) == 1) {
        wprintf(L"已解决数独:\n");
        printGrid(grid);
    } else {
        wprintf(L"对于提供的数独,没有解决方案。\n");
    }

    return 0;
}

使用方法如下:
Sudoku.exe 090020051010050603050000400530900000020001005600075108100400067300010020000087000

posted @ 2024-01-19 10:29  烟熏牛肉干  阅读(74)  评论(0编辑  收藏  举报