iOS开发 Swift开发数独游戏(二)数独题目的生成
一、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开发数独游戏(二)数独题目的生成的更多相关文章
- iOS开发 Swift开发数独游戏(一)
一.前言 我姥姥是一名退休数学老师,一直很喜欢玩数独游戏.我以前答应过她要给她写一个数独游戏.本来计划是写一个Android应用的,但恰好我学了好长时间iOS开发一直没做什么"大项目&quo ...
- iOS开发 Swift开发数独游戏(四) 游戏界面的界面与逻辑
一.游戏界面涉及到的功能点 1)数独格子的建模 (1)绘制数独格子要考虑到标记功能 所以要在每个格子内预先塞入9个标记数字,仅数独格子算下来就有9*9*9=729个格子且存在大量嵌套(这导致我在操作S ...
- iOS开发 Swift开发数独游戏(三) 选关界面
一.选关界面涉及到的功能点 1)需要UITableView以及相应数据代理.协议的实现 2)读取plist文件并转化成模型 3)在单元格点击后进入数独游戏,涉及到把数据经segue在UIViewCon ...
- iOS开发 Swift开发数独游戏(五)显示游戏答案
要点是设置好Tag就好,通过代码找到并初始化即可. 1: // 2: // ShowAnswerController.swift 3: // sudoku-v02 4: // 5: // ...
- IOS系列swift语言之课时二
今天我们要讲的就是函数[对于函数,在最后面还有几道题,喜欢的博友可以看了自己做一下,和我交流一下] 当然这与我们的c语言还是有一定的共同之处的,对于有一些c语言或者是java基础的童鞋,我觉得是很容易 ...
- iOS中 Swift初级入门学习(二)
// Copyright (c) 2015年 韩俊强. All rights reserved. // import Foundation /* // 控制语句 // for - in // 遍历字符 ...
- iOS、swift、React Native学习常用的社区、论坛
<!----iOS> <!----Swift>*IOS开发常用社区:http://code4app.com/ *IOS开发常用社区:http://www.cocoachina. ...
- 使用Xamarin开发移动应用示例——数独游戏(二)创建游戏界面
在本系列第一部分,我们创建了程序框架,现在我们创建游戏的界面,项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 首先在View ...
- 使用Xamarin开发移动应用示例——数独游戏(一)项目的创建与调试
最近项目中需要移动客户端,由于团队基本上使用.Net产品线,所以决定使用Xmarin进行开发,这样技术路线统一,便于后期维护.官网上是这样介绍的" Xamarin 允许你使用 .NET 代码 ...
随机推荐
- 孤荷凌寒自学python第四十天python 的线程锁RLock
孤荷凌寒自学python第四十天python的线程锁RLock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 因为研究同时在多线程中读写同一个文本文件引发冲突,所以使用Lock锁尝试同步, ...
- leetcode_day02
任务二:删除排序数组中的重复项 原文链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 最开始的解决思路: ...
- 训练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 ...
- go语言的学习网站
1)http://www.runoob.com/go/go-data-types.html 2)https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/ ...
- 在 MongoDB 上模拟事务操作来实现支付
我们的产品叫「学海密探」,属于在线教育行业,产品需要有支付功能,然而支付最蛋疼是什么?有人会说是支付宝和微信等支付接口的接入开发!没错,但支付接口的开发算是比较简单的了,我觉得凡是跟钱有关系的操作最重 ...
- CentOS修改IP地址
一.CentOS 修改IP地址修改对应网卡的IP地址的配置文件 # vi /etc/sysconfig/network-scripts/ifcfg-eth0 电信 # vi /etc/syscon ...
- MySQL事物相关学习
总结下最近对MySQL数据库的认识 Q:在手动开启事物后,commit失败是否需要显示的rollback? A:在网上查了不少资料,没有查到明确的答案.问了身边的朋友,朋友也不太了解,不过均表示显示的 ...
- 第十章 用户数据报协议和IP分片
用户数据报协议和IP分片 UDP是一种保留消息边界的简单的面向数据报的传输层协议.它仅提供差错检测.只是检测,而不是纠正,它只是把应用程序传给IP层的数据发送出去,但是并不会保证数据能够完好无损的到达 ...
- 【POJ 2728 Desert King】
Time Limit: 3000MSMemory Limit: 65536K Total Submissions: 27109Accepted: 7527 Description David the ...
- atan 和 atan2
转自http://blog.csdn.net/chinabinlang/article/details/6802686 atan函数与atan2函数的一点区别 . atan 和 atan2 都是求反 ...