中国象棋控件 v2.0.13
载入中...
搜索中...
未找到
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
115int CChessGame::SaveStep(int i, int j, CPiece::ENUM_QiZi qz,
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
164int CChessGame::GetPreviouStep(int &i, int &j, CPiece::ENUM_QiZi &qz)
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
185int CChessGame::GetNextStep(int &i, int &j, CPiece::ENUM_QiZi &qz)
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//检测布局是否合法, 使用标准棋盘布局,红下黑上
526int CChessGame::CheckGame(const CPiece::ENUM_QiZi board[][10])
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 {
550 switch(board[i][j])
551 {
552 case CPiece::RChe:
553 nRChe++;
554 break;
555 case CPiece::RMa:
556 nRMa++;
557 break;
558 case CPiece::RXiang:
559 nRXiang++;
560 if(!((2 == i && 9 == j) || (6 == i && 9 == j)
561 || (0 == i && 7 == j) || (8 == i && 7 == j)
562 || (2 == i && 5 == j) || (6 == i && 5 == j)
563 ))
564 return -1;
565 break;
566 case CPiece::RShi:
567 nRShi++;
568 if(i < 3 || i > 5 || j < 7)
569 return -2;
570 if((i == 3 || 5 == i) && j == 8)
571 return -3;
572 if(i == 4 && (j == 9 || j == 7))
573 return -4;
574 break;
575 case CPiece::RShuai:
576 nRShuai++;
577 if(i < 3 || i > 5 || j < 7)
578 return -5;
579 break;
580 case CPiece::RPao:
581 nRPao++;
582 break;
583 case CPiece::RBing:
584 nRBing++;
585 if(j > 6) return -6;
586 break;
587 case CPiece::BBing:
588 nBBing++;
589 if(j < 3) return -7;
590 break;
591 case CPiece::BPao:
592 nBPao++;
593 break;
594 case CPiece::BChe:
595 nBChe++;
596 break;
597 case CPiece::BMa:
598 nBMa++;
599 break;
600 case CPiece::BXiang:
601 nBXiang++;
602 if(!((2 == i && 0 == j) || (6 == i && 0 == j)
603 || (0 == i && 2 == j) || (8 == i && 2 == j)
604 || (2 == i && 4 == j) || (6 == i && 4 == j)
605 ))
606 return -8;
607 break;
608 case CPiece::BShi:
609 nBShi++;
610 if(i < 3 || i > 5 || j > 2)
611 return -9;
612 if((i == 3 || 5 == i) && j == 1)
613 return -10;
614 if(i == 4 && (j == 0 || j == 2))
615 return -11;
616 break;
617 case CPiece::BShuai:
618 nBShuai++;
619 if(i < 3 || i > 5 || j > 2)
620 return -12;
621 break;
622 default:
623 break;
624 }
625 }
626 if(nBChe > 2 || nRChe > 2
627 || nBMa > 2 || nRMa > 2
628 || nBXiang > 2 || nRXiang > 2
629 || nBShi > 2 || nBShi > 2
630 || nBShuai > 1 || nRShuai > 1
631 || nBPao > 2 || nRPao > 2
632 || nBBing > 5 || nRBing > 5)
633 return -13;
634
635 return nRet;
636}
637
638int CChessGame::GetStartGameBoard(/*[out]*/CPiece::ENUM_QiZi board[][10])
639{
640 //初始化空棋局
641 int i, j;
642 for (i = 0; i < 9; i++)
643 for (j = 0; j < 10; j++)
644 {
645 board[i][j] = CPiece::NoQiZi;
646 }
647
648 if(m_StartGame.size())
649 {
650 std::vector<CChessGame::strStartGame>::iterator it;
651 for(it = m_StartGame.begin(); it != m_StartGame.end(); it++)
652 {
653 board[it->i][it->j] = it->qz;
654 }
655 return CheckGame(board);
656 }
657 else
658 {
659 board[0][0] = board[8][0] = CPiece::BChe;
660 board[1][0] = board[7][0] = CPiece::BMa;
661 board[2][0] = board[6][0] = CPiece::BXiang;
662 board[3][0] = board[5][0] = CPiece::BShi;
663 board[4][0] = CPiece::BShuai;
664 board[1][2] = board[7][2] = CPiece::BPao;
665 board[0][3] = board[2][3] = board[4][3] = board[6][3] = board[8][3] = CPiece::BBing;
666
667 board[0][9] = board[8][9] = CPiece::RChe;
668 board[1][9] = board[7][9] = CPiece::RMa;
669 board[2][9] = board[6][9] = CPiece::RXiang;
670 board[3][9] = board[5][9] = CPiece::RShi;
671 board[4][9] = CPiece::RShuai;
672 board[1][7] = board[7][7] = CPiece::RPao;
673 board[0][6] = board[2][6] = board[4][6] = board[6][6] = board[8][6] = CPiece::RBing;
674 }
675 return 0;
676}
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 CChessStepsIccs class
Definition ChessSteps.h:47
福斯夫-爱德华兹记号法 (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