一、Plist文件结构设计

由于要预先生成数独题目的文件,我自然而然想到用plist存取。

我用Xcode建了几个plist文件来熟悉这种文件使用的结构后设计了如下结构:

为区分难度(后来了解到挖空数与难度其实不一定相对应),我笼统的以挖空数分类,每一个分类下存储这一挖空数对应的数独题目与解。

具体来说,root使用Dictionary类型,下面的关键字以“D”开头,后面为挖空的数目,每个“DXX”为Array类型,内容为不同的数独题目与解,每个数独题是Dictionary类型,关键字“p”代表题目,“s”表示这个题目的多种解。题目与答案都是String,“0”代表这是一个空,否则代表一个数字

如图“D51”表示挖空51个,“Item0”为挖空51个下的第一个数独题,p为数独题目,s下为多个解。

二、设计生成数度题目与解法的算法(C++)

作为一个懂得合理偷懒的人(其实是个算法渣),我参考了这篇文章:

http://www.cnblogs.com/gkfeng/archive/2012/09/15/2686452.html

该算法貌似是DFS+剪枝的思想,还能生成多解,于是我拿来改了改,使之直接生成plist文件。注意plist文件一点要符合apple的格式,一旦不符合就不能读取。

第267行 while (blanks<61) {    “<61”代表挖空挖到60

   1:  #include <fstream>
   2:  #include <unistd.h>
   3:  #include "stdio.h"
   4:  #include "stdlib.h"
   5:  #include "time.h"
   6:  //#include "fstream.h"
   7:  #include <iostream>
   8:  #include <sstream>
   9:  #include <string>
  10:  using namespace std;
  11:  ostringstream oss;
  12:  ostringstream coutt;
  13:  class CSudoku
  14:  {
  15:      int map[9][9],lastmap[9][9];
  16:      int smod;
  17:      int solves;
  18:      int check(int,int,int*);
  19:      void dfs();
  20:  public:
  21:      enum{ANY=0,ALL=1};
  22:      CSudoku(int n=40);// 随机生成数独,n越大越难
  23:      CSudoku(int *data);// 人工指定数独
  24:      virtual ~CSudoku();
  25:      void display();// 显示数独
  26:      void Sdisplay();// 显示数独
  27:      int resolve(int mod=ALL);// 解数独
  28:  };
  29:   long sand=0;
  30:   
  31:   
  32:  CSudoku::CSudoku(int n)
  33:  {
  34:      int i,j;
  35:      sand++;
  36:      srand(time(&sand));
  37:      do
  38:      {
  39:          for(i=0;i<9;++i)
  40:          {
  41:              for(j=0;j<9;++j)
  42:                  map[i][j]=0;
  43:              j=rand()%9;
  44:              map[i][j]=i+1;
  45:          }
  46:      }
  47:      while(!resolve(ANY));
  48:      
  49:      // 挖窟窿
  50:      for(int k=0;k<n;)
  51:      {
  52:          i=rand()%81;
  53:          j=i%9;
  54:          i=i/9;
  55:          if(map[i][j]>0)
  56:          {
  57:              map[i][j]=0;
  58:              ++k;
  59:          }
  60:          
  61:      }
  62:      //printf("(randomized sudoku created with %d blanks.)\n",blanks);
  63:  }
  64:  CSudoku::CSudoku(int *data)
  65:  {
  66:      int *pm=(int*)map;
  67:      for(int i=0;i<81;++i)
  68:          pm[i]=data[i];
  69:  }
  70:  CSudoku::~CSudoku()
  71:  {
  72:      return;
  73:  }
  74:  void CSudoku::display()
  75:  {
  76:      ostringstream osst;
  77:      osst.str("");
  78:      osst<<"<string>";
  79:      for(int i=0;i<9;++i)
  80:      {
  81:          for(int j=0;j<9;++j)
  82:          {
  83:  //            if(map[i][j]>0)
  84:  //                printf("< %d >  ",map[i][j]);
  85:  //            else
  86:  //                printf("[   ]  ");
  87:              
  88:              osst<<map[i][j];
  89:          }
  90:  //        printf("\n");
  91:      }
  92:      osst<<"</string>\n";
  93:      oss<<osst.str();
  94:  }
  95:  int same = 1;
  96:  void CSudoku::Sdisplay()
  97:  {
  98:      ostringstream osst;
  99:      osst.str("");
 100:      osst<<"<string>";
 101:      for(int i=0;i<9;++i)
 102:      {
 103:          for(int j=0;j<9;++j)
 104:          {
 105:              if (map[i][j]!=lastmap[i][j]) {
 106:                  same = 0;
 107:  //                oss<<"err!!!-------------------------------"<<same;
 108:  //                return;
 109:              }
 110:          }
 111:      }
 112:      if (same) {
 113:          return;
 114:      }
 115:      for(int i=0;i<9;++i)
 116:      {
 117:          for(int j=0;j<9;++j)
 118:          {
 119:              //            if(map[i][j]>0)
 120:              //                printf("< %d >  ",map[i][j]);
 121:              //            else
 122:              //                printf("[   ]  ");
 123:              lastmap[i][j] = map[i][j];
 124:              osst<<map[i][j];
 125:   
 126:          }
 127:          //        printf("\n");
 128:      }
 129:      osst<<"</string>\n";
 130:      oss<<osst.str();
 131:  }
 132:  int CSudoku::resolve(int mod)
 133:  {
 134:      smod=mod;
 135:      if(mod==ALL)
 136:      {
 137:          solves=0;
 138:          dfs();
 139:          return solves;
 140:      }
 141:      else if(mod==ANY)
 142:      {
 143:          try
 144:          {
 145:              dfs();
 146:              return 0;
 147:          }
 148:          catch(int)
 149:          {
 150:              return 1;
 151:          }
 152:      }
 153:      return 0;
 154:  }
 155:  int CSudoku::check(int y,int x,int *mark)
 156:  {
 157:      int i,j,is,js,count=0;
 158:      for(i=1;i<=9;++i)
 159:          mark[i]=0;
 160:      for(i=0;i<9;++i)
 161:          mark[map[y][i]]=1;
 162:      for(i=0;i<9;++i)
 163:          mark[map[i][x]]=1;
 164:      is=y/3*3;
 165:      js=x/3*3;
 166:      for(i=0;i<3;++i)
 167:      {
 168:          for(j=0;j<3;++j)
 169:              mark[map[is+i][js+j]]=1;
 170:      }
 171:      for(i=1;i<=9;++i)
 172:          if(mark[i]==0)
 173:              count++;
 174:      return count;
 175:  }
 176:  int toomanys = 0; int blanks = 40;
 177:  void CSudoku::dfs()
 178:  {
 179:      int i,j,im=-1,jm,min=10;
 180:      int mark[10];
 181:      for(i=0;i<9;++i)
 182:      {
 183:          for(j=0;j<9;++j)
 184:          {
 185:              if(map[i][j])
 186:                  continue;
 187:              int c=check(i,j,mark);
 188:              if(c==0)
 189:                  return;
 190:              if(c<min)
 191:              {
 192:                  im=i;
 193:                  jm=j;
 194:                  min=c;
 195:              }
 196:          }
 197:      }
 198:      if(im==-1)
 199:      {
 200:          if(smod==ALL)
 201:          {
 202:              ++solves;
 203:  //            printf("No. %d:\n",++solves);
 204:              if (solves>(2)) {
 205:                  toomanys = 1;
 206:                  return;
 207:              }
 208:              Sdisplay();
 209:              return;
 210:          }
 211:          else if(smod==ANY)
 212:          {
 213:              throw(1);
 214:          }
 215:      }
 216:      check(im,jm,mark);
 217:      for(i=1;i<=9;++i)
 218:      {
 219:          if(mark[i]==0)
 220:          {
 221:              map[im][jm]=i;
 222:              dfs();
 223:          }
 224:      }
 225:      map[im][jm]=0;
 226:  }
 227:   
 228:  int main()
 229:  {
 230:      int data1[]=
 231:      {4,9,0,0,0,6,0,2,7,
 232:          5,0,0,0,1,0,0,0,4,
 233:          6,0,0,0,0,8,0,0,3,
 234:          1,0,4,0,0,0,0,0,0,
 235:          0,6,0,0,0,0,0,5,0,
 236:          0,0,0,0,0,0,2,0,8,
 237:          7,0,0,2,0,0,0,0,5,
 238:          8,0,0,0,9,0,0,0,1,
 239:          3,4,0,5,0,0,0,6,2
 240:      };
 241:      int data2[]=
 242:      {7,4,0,0,8,0,0,1,6,
 243:          9,0,0,0,3,5,0,0,4,
 244:          0,0,0,7,0,0,0,0,0,
 245:          0,7,0,0,0,9,5,0,0,
 246:          6,1,0,0,5,0,0,8,7,
 247:          0,0,2,6,0,0,0,4,0,
 248:          0,0,0,0,0,4,0,0,0,
 249:          3,0,0,5,6,0,0,0,2,
 250:          5,6,0,0,1,0,0,3,9
 251:      };
 252:  //    cout<<"begin";
 253:  //    std::ofstream logFile("out.plist");
 254:  //    std::streambuf *outbuf = std::cout.rdbuf(logFile.rdbuf());
 255:      //<dict>
 256:      //<key>p</key>
 257:      //<string></string>
 258:      //<key>s</key>
 259:      //<array>
 260:      //<string>12</string>
 261:      //<string>32</string>
 262:      //</array>
 263:      //</dict>
 264:      cout<<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>";
 265:      int num = 0;
 266:  //    int normalEnd = 1;
 267:      while (blanks<60) {
 268:  //        <key>D20</key>
 269:  //        <array>
 270:         coutt<<"<key>D"<<blanks<<"</key>"<<endl<<"<array>"<<endl;
 271:  //        result =
 272:          int inNum = 0;
 273:        
 274:          for (int ii = 0; ii<100; ++ii) {
 275:  //            cout<<num<<"d"<<blanks<<endl;
 276:  //           normalEnd = 1;
 277:              same = 1;toomanys = 0;
 278:              oss<<"<dict>"<<endl<<"<key>p</key>"<<endl;
 279:              //    cin>>blanks;
 280:              
 281:              CSudoku s(blanks);
 282:              s.display();
 283:              //    cout<<"开始解数独:"<<endl;
 284:              oss<<"<key>s</key>"<<endl<<"<array>"<<endl;
 285:              //
 286:              s.resolve();
 287:              oss<<"</array>"<<endl<<"</dict>"<<endl;
 288:  //            sleep(1);
 289:  //            usleep(15000);
 290:              if (same){//||toomanys) {
 291:  //                cout<<"err!!!!====------";
 292:                  oss.str("");
 293:  //                normalEnd = 0;
 294:                  continue;
 295:              }else{
 296:                  coutt<<oss.str();
 297:                  oss.str("");
 298:                  ++num;++inNum;
 299:  //                normalEnd = 1;
 300:              }
 301:              if (inNum>20) {
 302:                  break;
 303:              }
 304:          }
 305:          
 306:          
 307:          
 308:  //        </array>
 309:  //        if (normalEnd == 1) {
 310:              coutt<<"</array>"<<endl;
 311:          if (inNum ) {
 312:              cout<<coutt.str();
 313:          }
 314:          coutt.str("");
 315:  //            cout<<oss.str();
 316:              oss.str("");
 317:  //        }
 318:          
 319:   
 320:          blanks+=1;
 321:  //        ++num;
 322:          
 323:          
 324:  //        if (num>5000) {
 325:  //            break;
 326:  //        }
 327:          
 328:          
 329:          
 330:      }
 331:     
 332:      
 333:      
 334:      cout<<"</dict>\n</plist>\n";
 335:  //      std::cout.rdbuf(outbuf);
 336:      
 337:  //    cout<<"done";
 338:      return 0;
 339:  }

三、将输出转向到文件

这个程序默认是输出到屏幕上,我想直接输出成文件。首先要定位到xcode项目中的可执行文件,如图,右键Show In Finder,找到所在的目录。

接着打开Terminal,cd到那个目录,输入“./sudokuG > sudokuR.plist”

终端会在该目录下生成一个新的 sudokuR.plist文件。拷贝到桌面,以供后续使用。

注:如果等待时间太长请减小267行的那个条件。Terminal执行过程中按Ctrl+C可以中途终止。

iOS开发 Swift开发数独游戏(二)数独题目的生成的更多相关文章

  1. iOS开发 Swift开发数独游戏(一)

    一.前言 我姥姥是一名退休数学老师,一直很喜欢玩数独游戏.我以前答应过她要给她写一个数独游戏.本来计划是写一个Android应用的,但恰好我学了好长时间iOS开发一直没做什么"大项目&quo ...

  2. iOS开发 Swift开发数独游戏(四) 游戏界面的界面与逻辑

    一.游戏界面涉及到的功能点 1)数独格子的建模 (1)绘制数独格子要考虑到标记功能 所以要在每个格子内预先塞入9个标记数字,仅数独格子算下来就有9*9*9=729个格子且存在大量嵌套(这导致我在操作S ...

  3. iOS开发 Swift开发数独游戏(三) 选关界面

    一.选关界面涉及到的功能点 1)需要UITableView以及相应数据代理.协议的实现 2)读取plist文件并转化成模型 3)在单元格点击后进入数独游戏,涉及到把数据经segue在UIViewCon ...

  4. iOS开发 Swift开发数独游戏(五)显示游戏答案

          要点是设置好Tag就好,通过代码找到并初始化即可. 1: // 2: // ShowAnswerController.swift 3: // sudoku-v02 4: // 5: // ...

  5. IOS系列swift语言之课时二

    今天我们要讲的就是函数[对于函数,在最后面还有几道题,喜欢的博友可以看了自己做一下,和我交流一下] 当然这与我们的c语言还是有一定的共同之处的,对于有一些c语言或者是java基础的童鞋,我觉得是很容易 ...

  6. iOS中 Swift初级入门学习(二)

    // Copyright (c) 2015年 韩俊强. All rights reserved. // import Foundation /* // 控制语句 // for - in // 遍历字符 ...

  7. iOS、swift、React Native学习常用的社区、论坛

    <!----iOS> <!----Swift>*IOS开发常用社区:http://code4app.com/ *IOS开发常用社区:http://www.cocoachina. ...

  8. 使用Xamarin开发移动应用示例——数独游戏(二)创建游戏界面

    在本系列第一部分,我们创建了程序框架,现在我们创建游戏的界面,项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 首先在View ...

  9. 使用Xamarin开发移动应用示例——数独游戏(一)项目的创建与调试

    最近项目中需要移动客户端,由于团队基本上使用.Net产品线,所以决定使用Xmarin进行开发,这样技术路线统一,便于后期维护.官网上是这样介绍的" Xamarin 允许你使用 .NET 代码 ...

随机推荐

  1. 孤荷凌寒自学python第四十天python 的线程锁RLock

     孤荷凌寒自学python第四十天python的线程锁RLock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 因为研究同时在多线程中读写同一个文本文件引发冲突,所以使用Lock锁尝试同步, ...

  2. leetcode_day02

    任务二:删除排序数组中的重复项 原文链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 最开始的解决思路: ...

  3. 训练caffe:registry.count(type) == 0 (1 vs. 0) Solver type Nesterov already registered

    命令:./continue-train.sh 内容:../../caffe-master/build/tools/caffe train -gpu=$1 -solver=solver.prototxt ...

  4. go语言的学习网站

    1)http://www.runoob.com/go/go-data-types.html 2)https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/ ...

  5. 在 MongoDB 上模拟事务操作来实现支付

    我们的产品叫「学海密探」,属于在线教育行业,产品需要有支付功能,然而支付最蛋疼是什么?有人会说是支付宝和微信等支付接口的接入开发!没错,但支付接口的开发算是比较简单的了,我觉得凡是跟钱有关系的操作最重 ...

  6. CentOS修改IP地址

    一.CentOS 修改IP地址修改对应网卡的IP地址的配置文件 # vi /etc/sysconfig/network-scripts/ifcfg-eth0   电信 # vi /etc/syscon ...

  7. MySQL事物相关学习

    总结下最近对MySQL数据库的认识 Q:在手动开启事物后,commit失败是否需要显示的rollback? A:在网上查了不少资料,没有查到明确的答案.问了身边的朋友,朋友也不太了解,不过均表示显示的 ...

  8. 第十章 用户数据报协议和IP分片

    用户数据报协议和IP分片 UDP是一种保留消息边界的简单的面向数据报的传输层协议.它仅提供差错检测.只是检测,而不是纠正,它只是把应用程序传给IP层的数据发送出去,但是并不会保证数据能够完好无损的到达 ...

  9. 【POJ 2728 Desert King】

    Time Limit: 3000MSMemory Limit: 65536K Total Submissions: 27109Accepted: 7527 Description David the ...

  10. atan 和 atan2

     转自http://blog.csdn.net/chinabinlang/article/details/6802686 atan函数与atan2函数的一点区别 . atan 和 atan2 都是求反 ...