数独游戏的AI解法

因为解的过程没有全局状态这种概念,所以不方便使用著名的H>D模板来解。其实因为格子的数量很少,只要做简章的优化就完全不存在问题。即使用穷举法,也能很快算出答案。(某人:不要小看穷举法!!!>_<++)

下次准备考虑生成游戏的算法,难度应该较高。

console工程的代码

// sudoku.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include "conio.h"

/* 为了代码好看^^ */
#define SUCCESS  1
#define FAILED  0

/* 地图类型9*9的char,每个char从0-9,0表示待填 */
typedef char MAPTYPE[9][9];
/*  行数据,同时用作“可能性”数据。如LINETYPE a; 当a[0]为真时表示
   当前位置可填1,a[1]为真时表示可填2,以此类推 */
typedef char LINETYPE[9];

/* 测试用地图文本,摘自http://www.game616.com/ */
const char *_map1 = {
 "980000005"
 "107050000"
 "000076809"
 "000840000"
 "078500200"
 "250000008"
 "000000052"
 "035001070"
 "709030000"
};

/* 从地图文本读取生成地图。地图文本是连续的81个asc数字字符串 */
void parse_map(MAPTYPE dest, const char* src)
{
 const char *p = src;
 for ( int j = 0; j < 9; j++ )
  for ( int i = 0; i < 9; i++ )
  {
   if (*p == ' ') dest[i][j] = 0;
   else dest[i][j] = (*p) - '0';
   p++;
  }
}

/* 打印地图 */
void dump_map(MAPTYPE dest)
{
 for ( int j = 0; j < 9; j++ )
 {
  for ( int i = 0; i < 9; i++ )
  {
   printf("%d ", dest[i][j]);
  }
  printf("/n");
 }
 printf("/n");
}

int fill_line(MAPTYPE dest, int line, MAPTYPE result);

/* 填下一个格子。本行的可能性已在调用前算好,要考虑的是列的可能性和九宫格的可能性 */
/* nums_possible : array (0-8) means possible of number (1-9) */
int fill_pos(MAPTYPE dest, LINETYPE nums_possible, int line, int pos, MAPTYPE result)
{
 if ( pos >= 9 ) return SUCCESS;
 if ( dest[pos][line] != 0 ) return fill_pos(dest, nums_possible, line, pos + 1, result);
 for ( int i = 0; i < 9; i++ )
 {
  if ( !nums_possible[i] ) continue;
  /* 检查本列是否重复 */
  int vetical_failed = 0;
  for ( int j = 0; j < 9; j++ )
   if ( dest[pos][j] == i + 1 )
   {
    vetical_failed = 1;
    break;
   }
  if ( vetical_failed ) continue;
  /* 检查九宫格是否重复 */
  int nine_failed = 0;
  int m = pos / 3;
  int n = line / 3;
  m *= 3;
  n *= 3;
  for ( int y = n; y < n + 3; y++ )
  {
   for ( int x = m; x < m + 3; x++ )
   {
    if ( dest[x][y] == i + 1 )
    {
     nine_failed = 1;
     break;
    }
   }
   if ( nine_failed ) break;
  }
  if ( nine_failed ) continue;
  /* all ok, try next position */
  dest[pos][line] = i + 1;
  nums_possible[i] = 0;
  if ( fill_pos(dest, nums_possible, line, pos + 1, result) )
  {
   /* 本行已全部OK,尝试下一行 */
   if ( fill_line(dest, line + 1, result) ) return SUCCESS;
   /* 下一行失败,重新尝试本位置的剩余可能性 */
  }
  nums_possible[i] = 1;
  dest[pos][line] = 0;
 }
 return FAILED;
}

/* 填下一行 */
int fill_line(MAPTYPE dest, int line, MAPTYPE result)
{
 if ( line >= 9 )
 {
  /* copy map */
  memcpy(result, dest, sizeof(MAPTYPE));
  return SUCCESS;
 }
 LINETYPE nums;
 LINETYPE saveline;
 /* calc possibility(for the current line) */
 for ( int i = 0; i < 9; i++ ) nums[i] = 1; /* all can be */
 for ( int i = 0; i < 9; i++ )
 {
  char n = dest[i][line];
  /* save line */
  saveline[i] = dest[i][line];
  if ( n != 0 ) nums[n - 1] = 0; /* appears */
 }
 if ( !fill_pos(dest, nums, line, 0, result) )
 {
  /* restore line */
  for ( int i = 0; i < 9; i++ ) dest[i][line] = saveline[i];
  return FAILED;
 }
 return SUCCESS;
}

int _tmain(int argc, _TCHAR* argv[])
{
 MAPTYPE dest, result;
 parse_map(dest, _map1);
 if ( fill_line(dest, 0, result) ) dump_map(result);
 getch();
 return 0;
}

 

你可能感兴趣的:(游戏,算法,优化,测试)