中国象棋控件 2.0.14
载入中...
搜索中...
未找到
ChessGame.cpp
1// 作者:康林 <kl222@126.com>
2
3#include "ChessGame.h"
4#include <fstream>
5#include <time.h>
6#include <string.h>
7#include <memory>
8#include "Pgn.h"
9#include "Fen.h"
10
11#ifdef WIN32
12#include <WinSock2.h>
13#else
14#include <arpa/inet.h>
15#endif
16
17#include "Pgn.h"
18
19CChessGame::CChessGame()
20{
21 m_nIndex = -1;
22 m_bFuPang = false;
23 /*
24 m_StartGame.push_back({0, 0, CPiece::BChe});
25 m_StartGame.push_back({1, 0, CPiece::BMa});
26 m_StartGame.push_back({2, 0, CPiece::BXiang});
27 m_StartGame.push_back({3, 0, CPiece::BShi});
28 m_StartGame.push_back({4, 0, CPiece::BShuai});
29 m_StartGame.push_back({5, 0, CPiece::BShi});
30 m_StartGame.push_back({6, 0, CPiece::BXiang});
31 m_StartGame.push_back({7, 0, CPiece::BMa});
32 m_StartGame.push_back({8, 0, CPiece::BChe});
33
34 m_StartGame.push_back({1, 2, CPiece::BPao});
35 m_StartGame.push_back({7, 2, CPiece::BPao});
36
37 m_StartGame.push_back({0, 3, CPiece::BBing});
38 m_StartGame.push_back({2, 3, CPiece::BBing});
39 m_StartGame.push_back({4, 3, CPiece::BBing});
40 m_StartGame.push_back({6, 3, CPiece::BBing});
41 m_StartGame.push_back({8, 3, CPiece::BBing});
42
43 m_StartGame.push_back({0, 9, CPiece::RChe});
44 m_StartGame.push_back({1, 9, CPiece::RMa});
45 m_StartGame.push_back({2, 9, CPiece::RXiang});
46 m_StartGame.push_back({3, 9, CPiece::RShi});
47 m_StartGame.push_back({4, 9, CPiece::RShuai});
48 m_StartGame.push_back({5, 9, CPiece::RShi});
49 m_StartGame.push_back({6, 9, CPiece::RXiang});
50 m_StartGame.push_back({7, 9, CPiece::RMa});
51 m_StartGame.push_back({8, 9, CPiece::RChe});
52
53 m_StartGame.push_back({1, 7, CPiece::RPao});
54 m_StartGame.push_back({7, 7, CPiece::RPao});
55
56 m_StartGame.push_back({0, 6, CPiece::RBing});
57 m_StartGame.push_back({2, 6, CPiece::RBing});
58 m_StartGame.push_back({4, 6, CPiece::RBing});
59 m_StartGame.push_back({6, 6, CPiece::RBing});
60 m_StartGame.push_back({8, 6, CPiece::RBing});
61 //*/
62
63}
64
65CChessGame::~CChessGame()
66{}
67
68
83int CChessGame::QiZiBianMa(int *i, int *j, CPiece::ENUM_QiZi *qz, strCODE *pCode, ENUM_BianMa bianma)
84{
85 switch (bianma)
86 {
87 case BianMa:
88 pCode->step[0] = *i;
89 pCode->step[1] = *j;
90 pCode->step[2] = *qz;
91 break;
92 case JieMa:
93 *i = pCode->step[0];
94 *j = pCode->step[1];
95 *qz = static_cast<CPiece::ENUM_QiZi>(pCode->step[2]);
96 break;
97 }
98
99 return 0;
100}
101
116 const char* pDescript, time_t tm)
117{
118 strStep step;
119 QiZiBianMa(&i, &j, &qz, &step.code);
120 if (pDescript)
121 step.szDescript = pDescript;
122
123 step.tm = tm;
124
125 // 调整容器大小
126 if (m_nIndex + 1 < m_ChessGame.size())
127 {
128 m_ChessGame.resize(m_nIndex + 1);
129 }
130
131 m_ChessGame.push_back(step);//保存到棋局中
132 m_nIndex++;
133
134 return 0;
135}
136
146{
147 if (m_nIndex < 0)
148 return -1;
149 m_nIndex--;
150 m_ChessGame.erase(--m_ChessGame.end());
151 return 0;
152}
153
154
165{
166 if (m_nIndex < 0)
167 return -1;
168
169 QiZiBianMa(&i, &j, &qz, &m_ChessGame[m_nIndex].code, JieMa);
170 m_nIndex--;
171 return 0;
172}
173
186{
187 if (m_ChessGame.size() <= m_nIndex + 1)
188 return -1;
189
190 QiZiBianMa(&i, &j, &qz, &m_ChessGame[++m_nIndex].code, JieMa);
191
192 return 0;
193}
194
195int CChessGame::SaveChessGame(const char* szFile)
196{
197 if (!szFile) return -1;
198 strFile head;
199#ifdef WIN32
200#ifdef MINGW
201 strncpy_s(head.head.szAppName, MAX_STRING_BUFFER, APPNAME, MAX_STRING_BUFFER);
202 strncpy_s(head.head.szAuthor, MAX_STRING_BUFFER, AUTHOR, MAX_STRING_BUFFER);
203#else
204 strncpy_s(head.head.szAppName, APPNAME, MAX_STRING_BUFFER);
205 strncpy_s(head.head.szAuthor, AUTHOR, MAX_STRING_BUFFER);
206#endif
207#else
208 strncpy(head.head.szAppName, APPNAME, MAX_STRING_BUFFER);
209 strncpy(head.head.szAuthor, AUTHOR, MAX_STRING_BUFFER);
210#endif
211
212 head.head.dwVersion = 2;
213 head.iBuShu = htons(m_ChessGame.size());
214
215 head.timeStart = htonl(m_tmStart);
216 head.timeEnd = htonl(m_tmEnd);
217#ifdef WIN32
218#ifdef MINGW
219 strncpy_s(head.szRedName, MAX_STRING_BUFFER, m_szRedName.c_str(), MAX_STRING_BUFFER);
220 strncpy_s(head.szBlackName, MAX_STRING_BUFFER, m_szBlackName.c_str(), MAX_STRING_BUFFER);
221#else
222 strncpy_s(head.szRedName, m_szRedName.c_str(), MAX_STRING_BUFFER);
223 strncpy_s(head.szBlackName, m_szBlackName.c_str(), MAX_STRING_BUFFER);
224#endif
225#else
226 strncpy(head.szRedName, m_szRedName.c_str(), MAX_STRING_BUFFER);
227 strncpy(head.szBlackName, m_szBlackName.c_str(), MAX_STRING_BUFFER);
228#endif
229
230 std::ofstream out(szFile);
231 if (!out.is_open())
232 return -2;
233 out.write((char*)&head, sizeof(strFile));
234
235 // 保存标签
236 short nTag = htons(m_Tags.size());
237 out.write((char*)&nTag, sizeof (short));
238 for(const auto& item: m_Tags)
239 {
240 std::string key = item.first;
241 std::string val = item.second;
242 WriteStringToFile(out, key);
243 WriteStringToFile(out, val);
244 }
245
246 //保存开局
247 char nLen = 0; //开局最多30子
248 nLen = m_StartGame.size();
249 out.write(&nLen, sizeof (char));
250 if(nLen > 0)
251 {
252 std::vector<strStartGame>::iterator it;
253 for(it = m_StartGame.begin(); it != m_StartGame.end(); it++)
254 {
255 strCODE code;
256 QiZiBianMa(&it->i, &it->j, &it->qz, &code);
257 out.write(code.step, sizeof(strCODE));
258 }
259 }
260
261 //保存着法
262 std::vector<strStep>::iterator it;
263 for (it = m_ChessGame.begin(); it != m_ChessGame.end(); it++)
264 {
265 out.write(it->code.step, sizeof(strCODE));
266 long t = htonl(it->tm);
267 out.write((char*)&t, sizeof(long));
268 WriteStringToFile(out, it->szDescript);
269 }
270 out.close();
271 return 0;
272}
273
274int CChessGame::LoadChessGame(const char* szFile)
275{
276 int nRet = 0;
277 if (!szFile) return -1;
278
279 strFile head;
280 memset(&head, 0, sizeof(strFile));
281
282 std::ifstream in(szFile);
283 if (!in.is_open())
284 return -2;
285
286 in.read((char*)&head, sizeof(strFile));
287 m_szRedName = head.szRedName;
288 m_szBlackName = head.szBlackName;
289 m_tmStart = ntohl(head.timeStart);
290 m_tmEnd = ntohl(head.timeEnd);
291
292 do {
293 if (strcmp(head.head.szAppName, APPNAME))
294 {
295 nRet = -3;
296 break;
297 }
298 if (strcmp(head.head.szAuthor, AUTHOR))
299 {
300 nRet = -4;
301 break;
302 }
303 if (head.head.dwVersion != 2)
304 {
305 nRet = -5;
306 break;
307 }
308
309 //加载标签
310 short nTags = 0;
311 in.read((char*)&nTags, sizeof (short));
312 nTags = ntohs(nTags);
313 if(nTags) m_Tags.clear();
314 while(nTags-- > 0)
315 {
316 std::string key, val;
317 ReadStringFromFile(in, key);
318 ReadStringFromFile(in, val);
319 m_Tags[key] = val;
320 }
321
322 //加载开局
323 m_StartGame.clear();
324 char nLen = 0;
325 in.read(&nLen, sizeof (char));
326 if(nLen > 0)
327 {
328 while (nLen--) {
329 strCODE code;
330 in.read(code.step, sizeof(strCODE));
331 strStartGame g;
332 QiZiBianMa(&g.i, &g.j, &g.qz, &code, JieMa);
333 m_StartGame.push_back(g);
334 }
335 }
336
337 //加载着法
338 m_ChessGame.clear();
339 m_nIndex = ntohs(head.iBuShu);
340 while (m_nIndex--)
341 {
342 strStep step;
343 in.read((char*)&step.code, sizeof(strCODE));
344 long tm;
345 in.read((char*)&tm, sizeof(long));
346 step.tm = ntohl(tm);
347 ReadStringFromFile(in, step.szDescript);
348 m_ChessGame.push_back(step);
349 }
350 m_nIndex = -1;
351 } while (0);
352
353 in.close();
354 return nRet;
355}
356
357int CChessGame::SaveChessGamePgn(const char *pFileName, _SavePgnFormat f)
358{
359 int nRet = 0;
360 if (!pFileName) return -1;
361
362 CPGN pgn;
363 std::shared_ptr<CChessSteps> Steps;
364
365 //设置 Tag
366 if(!m_szRedName.empty())
367 pgn.SetRed(m_szRedName.c_str());
368 if(!m_szBlackName.empty())
369 pgn.SetBlack(m_szBlackName.c_str());
370
371 CPiece::ENUM_QiZi board[9][10];
372 if(m_StartGame.empty())
373 {
374 GetStartGameBoard(board);
375 }
376
377 std::string szFen;
378 CFen fen;
379 nRet = fen.FenFromBoard(szFen, board);
380 if(0 == nRet)
381 pgn.SetFen(szFen.c_str());
382
383 for(const auto& item: m_Tags)
384 {
385 std::string key = item.first;
386 std::string val = item.second;
387 pgn.SetTag(key, val);
388 }
389
390 switch (f) {
391 case ICCS:
392 pgn.SetFormat("ICCS");
393 Steps = std::shared_ptr<CChessStepsIccs>(new CChessStepsIccs());
394 break;
395 case WXF:
396 pgn.SetFormat("WXF");
397 break;
398 case Chinese:
399 pgn.SetFormat("Chinese");
400 Steps = std::shared_ptr<CChessStepsChinese>(new CChessStepsChinese());
401 break;
402 }
403
404 GetStartGameBoard(Steps->m_Board);
405 for(auto& item: m_ChessGame)
406 {
407 int i = 0, j = 0;
408 CPiece::ENUM_QiZi qz = CPiece::NoQiZi;
409 QiZiBianMa(&i, &j, &qz, &item.code, JieMa);
410 Steps->AddStep(i, j, qz, item.szDescript);
411 }
412
413 std::ofstream out(pFileName);
414 if (!out.is_open())
415 return -2;
416 pgn.SetSteps(Steps);
417 out << pgn.toString();
418 out.close();
419
420 return nRet;
421}
422
423int CChessGame::LoadChessGamePgn(const char *pFileName, _SavePgnFormat f)
424{
425 int nRet = 0;
426 if (!pFileName) return -1;
427
428 //TODO:
429 std::ifstream in(pFileName);
430 if (!in.is_open())
431 return -2;
432
433
434 in.close();
435 return nRet;
436}
437
438int CChessGame::WriteStringToFile(std::ofstream &o, std::string &s)
439{
440 short nLen = s.size();
441 short n = htons(nLen);
442 o.write((char*)&n, sizeof(short));
443 if (nLen > 0)
444 {
445 o.write(s.c_str(), nLen);
446 }
447 return 0;
448}
449
450int CChessGame::ReadStringFromFile(std::ifstream &i, std::string &s)
451{
452 short nLen = 0;
453 i.read((char*)&nLen, sizeof(short));
454 nLen = ntohs(nLen);
455 if (nLen > 0)
456 {
457 char* pBuf = new char[nLen + 1];
458 memset(pBuf, 0, nLen + 1);
459 i.read(pBuf, nLen);
460 s = pBuf;
461 delete[]pBuf;
462 }
463 return 0;
464}
465
466time_t CChessGame::GetStartTime()
467{
468 return m_tmStart;
469}
470
471int CChessGame::SetStartTime(const time_t& t)
472{
473 m_tmStart = t;
474 return 0;
475}
476
477time_t CChessGame::GetEndTime()
478{
479 return m_tmEnd;
480}
481
482int CChessGame::SetEndTime(const time_t& t)
483{
484 m_tmEnd = t;
485 return 0;
486}
487
488std::string CChessGame::GetRedName()
489{
490 return m_szRedName;
491}
492
493int CChessGame::SetRedName(const char* pszName)
494{
495 m_szRedName = pszName;
496 return 0;
497}
498
499std::string CChessGame::GetBlackName()
500{
501 return m_szBlackName;
502}
503
504int CChessGame::SetBlackName(const char* pszName)
505{
506 m_szBlackName = pszName;
507 return 0;
508}
509
510std::string CChessGame::GetTag(const std::string &szpTag)
511{
512 std::map<std::string, std::string>::iterator it;
513 it = m_Tags.find(szpTag);
514 if(m_Tags.end() != it)
515 return it->second;
516 return std::string();
517}
518
519int CChessGame::AddTag(const std::string &szTag, const std::string &szVal)
520{
521 m_Tags[szTag] = szVal;
522 return 0;
523}
524
525//检测布局是否合法, 使用标准棋盘布局,红下黑上
527{
528 int nRet = 0;
529
530 int nRChe = 0;
531 int nRMa = 0;
532 int nRXiang = 0;
533 int nRShi = 0;
534 int nRShuai = 0;
535 int nRPao = 0;
536 int nRBing = 0;
537
538 int nBChe = 0;
539 int nBMa = 0;
540 int nBXiang = 0;
541 int nBShi = 0;
542 int nBShuai = 0;
543 int nBPao = 0;
544 int nBBing = 0;
545
546 //检查各种棋子个数
547 for(int i = 0; i < 9; i++) {
548 for(int j = 0; j < 10; j++) {
549 switch(board[i][j])
550 {
551 case CPiece::RChe:
552 nRChe++;
553 break;
554 case CPiece::RMa:
555 nRMa++;
556 break;
557 case CPiece::RXiang:
558 nRXiang++;
559 if(!((2 == i && 9 == j) || (6 == i && 9 == j)
560 || (0 == i && 7 == j) || (8 == i && 7 == j)
561 || (2 == i && 5 == j) || (6 == i && 5 == j)
562 ))
563 return -1;
564 break;
565 case CPiece::RShi:
566 nRShi++;
567 if((i < 3) || (i > 5) || (j < 7))
568 return -2;
569 if((i == 3 || 5 == i) && j == 8)
570 return -3;
571 if(i == 4 && (j == 9 || j == 7))
572 return -4;
573 break;
574 case CPiece::RShuai:
575 nRShuai++;
576 if((i < 3) || (i > 5) || (j < 7))
577 return -5;
578 break;
579 case CPiece::RPao:
580 nRPao++;
581 break;
582 case CPiece::RBing:
583 nRBing++;
584 if(j > 6) return -6;
585 break;
586 case CPiece::BBing:
587 nBBing++;
588 if(j < 3) return -7;
589 break;
590 case CPiece::BPao:
591 nBPao++;
592 break;
593 case CPiece::BChe:
594 nBChe++;
595 break;
596 case CPiece::BMa:
597 nBMa++;
598 break;
599 case CPiece::BXiang:
600 nBXiang++;
601 if(!((2 == i && 0 == j) || (6 == i && 0 == j)
602 || (0 == i && 2 == j) || (8 == i && 2 == j)
603 || (2 == i && 4 == j) || (6 == i && 4 == j)
604 ))
605 return -8;
606 break;
607 case CPiece::BShi:
608 nBShi++;
609 if((i < 3) || (i > 5) || (j > 2))
610 return -9;
611 if((i == 3 || 5 == i) && j == 1)
612 return -10;
613 if(i == 4 && (j == 0 || j == 2))
614 return -11;
615 break;
616 case CPiece::BShuai:
617 nBShuai++;
618 if((i < 3) || (i > 5) || (j > 2))
619 return -12;
620 break;
621 default:
622 break;
623 }
624 }
625 }
626
627 if(nBChe > 2 || nRChe > 2
628 || nBMa > 2 || nRMa > 2
629 || nBXiang > 2 || nRXiang > 2
630 || nBShi > 2 || nBShi > 2
631 || nBShuai > 1 || nRShuai > 1
632 || nBPao > 2 || nRPao > 2
633 || nBBing > 5 || nRBing > 5)
634 return -13;
635
636 return nRet;
637}
638
640{
641 //初始化空棋局
642 int i, j;
643 for (i = 0; i < 9; i++)
644 for (j = 0; j < 10; j++)
645 {
646 board[i][j] = CPiece::NoQiZi;
647 }
648
649 if(m_StartGame.size())
650 {
651 std::vector<CChessGame::strStartGame>::iterator it;
652 for(it = m_StartGame.begin(); it != m_StartGame.end(); it++)
653 {
654 board[it->i][it->j] = it->qz;
655 }
656 return CheckGame(board);
657 }
658 else
659 {
660 board[0][0] = board[8][0] = CPiece::BChe;
661 board[1][0] = board[7][0] = CPiece::BMa;
662 board[2][0] = board[6][0] = CPiece::BXiang;
663 board[3][0] = board[5][0] = CPiece::BShi;
664 board[4][0] = CPiece::BShuai;
665 board[1][2] = board[7][2] = CPiece::BPao;
666 board[0][3] = board[2][3] = board[4][3] = board[6][3] = board[8][3] = CPiece::BBing;
667
668 board[0][9] = board[8][9] = CPiece::RChe;
669 board[1][9] = board[7][9] = CPiece::RMa;
670 board[2][9] = board[6][9] = CPiece::RXiang;
671 board[3][9] = board[5][9] = CPiece::RShi;
672 board[4][9] = CPiece::RShuai;
673 board[1][7] = board[7][7] = CPiece::RPao;
674 board[0][6] = board[2][6] = board[4][6] = board[6][6] = board[8][6] = CPiece::RBing;
675 }
676 return 0;
677}
int GetPreviouStep(int &i, int &j, CPiece::ENUM_QiZi &qz)
函数名:GetPreviouStep 功 能:上步棋 参 数:无 返回值:走棋步数 作 者:康 林 版 本:1.0.0.1 日 期:2004-10-5 时 间:10:19:51
int RevokeStep()
撤销一步
int SaveChessGame(const char *pFileName)
Saves the chess game
int SaveStep(int i, int j, CPiece::ENUM_QiZi qz, const char *pDescript=nullptr, time_t tm=time(nullptr))
保存一步
int GetNextStep(int &i, int &j, CPiece::ENUM_QiZi &qz)
Gets the next step
int GetStartGameBoard(CPiece::ENUM_QiZi board[][10])
得到开局棋盘布局
static int CheckGame(const CPiece::ENUM_QiZi board[][10])
棋盘开局 检测布局是否合法, 使用标准棋盘布局,红下黑上
The CChessStepsChinese class
ICCS是中国象棋互联网服务器(Internet Chinese Chess Server)的缩写。
Definition ChessSteps.h:57
福斯夫-爱德华兹记号法 (Forsyth-Edwards Notation)
Definition Fen.h:20
Class to hold all information for the Portable Game Notation (PGN) of a single game.
Definition Pgn.h:23
std::string toString() const
Gets the game as PGN string.
Definition Pgn.cpp:75
enum CPiece::_ENUM_QiZi ENUM_QiZi
棋子枚举值 四个位表示棋子,最左1位表示颜色