/*************************************************************************** * Copyright (C) 2002-2003 Andi Peredri * * andi@ukr.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include "checkers.h" #include "pdn.h" #define PLAYER true #define COMPUTER false void Pdn::clear() { pdnDate=pdnSite=pdnType=pdnEvent=pdnRound=pdnWhite=pdnBlack=pdnResult=""; for(int i=0; i<32; i++) board[i]=FREE; } QString Pdn::get(Tag tag) const { switch(tag) { case Date: return pdnDate; case Site: return pdnSite; case Type: return pdnType; case Event: return pdnEvent; case Round: return pdnRound; case White: return pdnWhite; case Black: return pdnBlack; default: return pdnResult; } } void Pdn::set(Tag tag, const QString& string) { switch(tag) { case Date: pdnDate=string; break; case Site: pdnSite=string; break; case Type: pdnType=string; break; case Event: pdnEvent=string;break; case Round: pdnRound=string;break; case White: pdnWhite=string;break; case Black: pdnBlack=string;break; default: pdnResult=string; } } bool Pdn::open(const QString& filename) { database.clear(); QFile file(filename); if(!file.open(IO_ReadOnly)) return false; QTextStream stream(&file); QString str1,str2,str3; while(!stream.eof()) { str1=stream.readLine(); str2=str1.stripWhiteSpace(); str3.append(str2); str3.append("\n"); if(str2.endsWith("1-0") || str2.endsWith("*") || str2.endsWith("0-1") || str2.endsWith("1/2-1/2")) { database.append(str3); str3=""; } } file.close(); return true; } bool Pdn::save(const QString& filename, int game) { QString string1; QString string2; QString notation; if(pdnType.toInt() == ENGLISH) notation=QString(ENOTATION); else notation=QString(RNOTATION); for(int i=0; i<32; i++) { int index=i*2; if(white==COMPUTER) index=62-index; QString pos; switch(board[i]) { case KING1: pos.append('K'); case MAN1: pos.append(notation.mid(index,2).stripWhiteSpace()); if(string1.length()) string1.append(','); string1.append(pos); break; case KING2: pos.append('K'); case MAN2: pos.append(notation.mid(index,2).stripWhiteSpace()); if(string2.length()) string2.append(','); string2.append(pos); default: break; } } QString fen; if(white==PLAYER) fen.append("W:W"+string1+":B"+string2+"."); else fen.append("B:W"+string2+":B"+string1+"."); QString pdngame("\n"); if(pdnEvent.length()) pdngame.append("[Event \""+pdnEvent+"\"]\n"); if(pdnSite.length()) pdngame.append("[Site \"" +pdnSite +"\"]\n"); if(pdnDate.length()) pdngame.append("[Date \"" +pdnDate +"\"]\n"); if(pdnRound.length()) pdngame.append("[Round \""+pdnRound+"\"]\n"); if(pdnWhite.length()) pdngame.append("[White \""+pdnWhite+"\"]\n"); if(pdnBlack.length()) pdngame.append("[Black \""+pdnBlack+"\"]\n"); pdngame.append("[Result \""+pdnResult+"\"]\n"); pdngame.append("[GameType \""+pdnType+"\"]\n"); pdngame.append("[SetUp \"1\"]\n"); pdngame.append("[FEN \""+fen+"\"]\n"); pdngame.append("\n"+pdnResult+"\n"); open(filename); if(game==-1) database.append(pdngame); else database[game]=pdngame; QFile file(filename); if(!file.open( IO_WriteOnly )) return false; QTextStream stream(&file); stream << database.join(""); file.close(); return true; } bool Pdn::parse(int game) { clear(); if(game>=count()) return false; QString fen; QString pdngame=database[game]; // PDN game int num=pdngame.contains('\n'); // Number of lines for(int i=0; i<=num; i++) { QString line=pdngame.section('\n',i,i); if(line.startsWith("[")) { line.remove(0,1); line=line.stripWhiteSpace(); if(line.startsWith("GameType")) pdnType=line.section('"',1,1); else if(line.startsWith("FEN")) fen=line.section('"',1,1); else if(line.startsWith("Date")) pdnDate=line.section('"',1,1); else if(line.startsWith("Site")) pdnSite=line.section('"',1,1); else if(line.startsWith("Event")) pdnEvent=line.section('"',1,1); else if(line.startsWith("Round")) pdnRound=line.section('"',1,1); else if(line.startsWith("White")) pdnWhite=line.section('"',1,1); else if(line.startsWith("Black")) pdnBlack=line.section('"',1,1); else if(line.startsWith("Result")) pdnResult=line.section('"',1,1); else ; // Skip other unsupported tags } } // Translation of the GameType tag switch(pdnType.toInt()) { case ENGLISH: break; case RUSSIAN: break; default: return false; } // Parsing of the Forsyth-Edwards Notation (FEN) tag if(fen.isNull()) { white=PLAYER; for(int i=0; i<12; i++) board[i]=MAN2; for(int i=20; i<32; i++) board[i]=MAN1; return true; } fen=fen.simplifyWhiteSpace(); for(int i=fen.find(" "); i!=-1; i=fen.find(" ")) fen=fen.remove(i,1); if(fen.startsWith("W:W")) white=PLAYER; else if(fen.startsWith("B:W")) white=COMPUTER; else return false; QString string=fen.mid(3).section(":B",0,0); if(!parse(string, white)) return false; string=fen.section(":B",1,1); if(string.endsWith(".")) string.truncate(string.length()-1); if(!parse(string, !white)) return false; return true; } bool Pdn::parse(const QString& string, bool side) { QString pos; QString notation; if(pdnType.toInt() == ENGLISH) notation=QString(ENOTATION); else notation=QString(RNOTATION); for(int i=0; pos=string.section(',',i,i); i++) { bool king=false; if(pos.startsWith("K")) { pos=pos.remove(0,1); king=true; } if(pos.length()==1) pos.append(' '); if(pos.length()!=2) return false; int index=notation.find(pos); if(index%2) index=notation.find(pos,index+1); if(index == -1) return false; if(white==COMPUTER) index=62-index; if(side==PLAYER) board[index/2]=(king ? KING1 : MAN1); else board[index/2]=(king ? KING2 : MAN2); } return true; }