/*************************************************************************** pgn.cpp - description ------------------- begin : Mon Jul 30 2001 copyright : (C) 2003 by Troy Corbin Jr. email : tcorbin@users.sourceforge.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. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include "pgn.moc" #include "tabmanager.h" #include "tab_pgnview.h" pgn::pgn( resource *Rsrc, match_param *param ) { Resource = Rsrc; Param = param; pgnView = NULL; if( Param != NULL ) { connect( Param, TQ_SIGNAL( valuesChanged() ), this, TQ_SLOT( parseMatchParam() ) ); } } pgn::~pgn() { if( Param ) delete Param; if( pgnView ) { if( Resource->tabManager->isTab( pgnView ) ) { Resource->tabManager->removeTab( pgnView ); } } } /////////////////////////////////////// // // pgn::parseMatchParam // /////////////////////////////////////// void pgn::parseMatchParam( void ) { if( Param == NULL ) return; TAG_White = Param->name( WHITE ); TAG_Black = Param->name( BLACK ); switch( Param->type( BLACK ) ) { case PLAYERLOCAL: TAG_BlackType = "human"; break; case PLAYERPC: TAG_BlackType = "program"; break; case PLAYERTCP: TAG_BlackType = "unknown"; TAG_Mode = "ICS"; break; case PLAYEREMAIL: TAG_BlackType = "unknown"; TAG_Mode = "EM"; break; default: TAG_BlackType = "unknown"; break; } switch( Param->type( WHITE ) ) { case PLAYERLOCAL: TAG_WhiteType = "human"; break; case PLAYERPC: TAG_WhiteType = "program"; break; case PLAYERTCP: TAG_WhiteType = "unknown"; TAG_Mode = "ICS"; break; case PLAYEREMAIL: TAG_WhiteType = "unknown"; TAG_Mode = "EM"; break; default: TAG_WhiteType = "unknown"; break; } } /////////////////////////////////////// // // pgn::notation // /////////////////////////////////////// TQStringList* pgn::notation( const int format ) { TQStringList *list; TQString notation; MoveList::Iterator IT; Annotation *annon; int tmp(0), Line(0); bool showLineNumber( false ); list = new TQStringList; switch( format ) { case 0: /* CAN Raw move data ( ie. for UCI engines ) */ for( IT = Moves.begin(); IT != Moves.end(); ++IT ) { list->append( TQString( (*IT).CAN ) ); } break; case 1: /* SAN For display to the user */ for( IT = Moves.begin(); IT != Moves.end(); ++IT ) { Line = ( tmp + 2 ) >> 1; if( ( tmp % 2 ) == 0 ) { notation = TQString( "%1. %2" ).arg( Line ).arg( (*IT).SAN ); } else { notation = TQString( "%1... %2" ).arg( Line ).arg( (*IT).SAN ); } list->append( notation ); tmp++; } break; case 2: /* SAN For PGN */ for( IT = Moves.begin(); IT != Moves.end(); ++IT ) { Line = ( tmp + 2 ) >> 1; if( ( tmp % 2 ) == 0 ) { notation = TQString( "%1. %2" ).arg( Line ).arg( (*IT).SAN ); } else { if( showLineNumber ) { notation = TQString( "%1... %2" ).arg( Line ).arg( (*IT).SAN ); } else { notation = TQString( (*IT).SAN ); } } showLineNumber = false; /* Insert NAGs */ if( (*IT).NAG != 0 ) { notation += TQString( " $%1" ).arg( TQString::number( (*IT).NAG ) ); } /* Insert RAVs */ annon = RAV.find( tmp ); if( annon != NULL ) { notation += TQString( " (%1)" ).arg( annon->text ); showLineNumber = true; } /* Insert Annotations */ annon = annotations.find( tmp ); if( annon != NULL ) { notation += TQString( " {%1}" ).arg( annon->text ); showLineNumber = true; } list->append( notation ); tmp++; } break; default: break; } return list; } /////////////////////////////////////// // // pgn::caption // /////////////////////////////////////// TQString pgn::caption( void ) { TQString caption; caption = i18n( "%1 vs. %2").arg( TAG_White ).arg( TAG_Black ); return caption; } /////////////////////////////////////// // // pgn::clear // /////////////////////////////////////// void pgn::clear( void ) { Moves.clear(); RAV.clear(); annotations.clear(); Positions.clear(); currentIndex = 0; whiteTCP.clear(); blackTCP.clear(); whiteTime = 300; blackTime = 300; CurrentURL = ""; Move_Data.clear(); clearTags(); } /////////////////////////////////////// // // pgn::clearTags // /////////////////////////////////////// void pgn::clearTags( void ) { TAG_Site = ""; TAG_Date = ""; TAG_Round = ""; TAG_Result = ""; TAG_White = ""; TAG_WhiteTitle = ""; TAG_WhiteElo = ""; TAG_WhiteUSCF = ""; TAG_WhiteNA = ""; TAG_WhiteType = ""; TAG_Black = ""; TAG_BlackTitle = ""; TAG_BlackElo = ""; TAG_BlackUSCF = ""; TAG_BlackNA = ""; TAG_BlackType = ""; TAG_Time = ""; TAG_UTCTime = ""; TAG_UTCDate = ""; TAG_Event = ""; TAG_EventDate = ""; TAG_EventSponsor = ""; TAG_Section = ""; TAG_Stage = ""; TAG_Board = ""; TAG_Opening = ""; TAG_Variation = ""; TAG_SubVariation = ""; TAG_ECO = ""; TAG_NIC = ""; TAG_TimeControl = ""; TAG_Termination = ""; TAG_SetUp = ""; TAG_FEN = ""; TAG_Annotator = ""; TAG_Mode = ""; TAG_PlyCount = ""; } /////////////////////////////////////// // // pgn::init // /////////////////////////////////////// void pgn::init( void ) { TQString temp; struct utsname unamePtr; TQDateTime qdt; clear(); parseMatchParam(); uname( &unamePtr ); /* Build Date */ qdt = TQDateTime::currentDateTime(); TAG_Date = TQString("%1.%2.%3").arg(qdt.date().year(),4).arg(qdt.date().month(),2).arg(qdt.date().day(),2); TAG_Date = TAG_Date.replace( TQRegExp("\\s"), TQString("0") ); TAG_Time = qdt.time().toString(); TAG_Site = unamePtr.nodename; TAG_Event = "Knights Computer Chess Game"; TAG_Round = "-"; TAG_Result = "*"; } /////////////////////////////////////// // // pgn::scan // /////////////////////////////////////// int pgn::scan( void ) { int Section(0); TQChar c; clearTags(); File_Position = File.at(); /* Toplevel parsing loop */ while( 1 ) { /* Is this the end of the .pgn file? */ if( Input.atEnd() ) { close(); return 100; // 100% Complete } currentLine = Input.readLine(); if( currentLine.isEmpty() ) { if( Section == 1 ) return (int)( ( (float)File.at() / (float)File.size() ) * 100.0 ); } c = getch(); while( c != TQChar::null ) { switch( c ) { /* Tag Pair */ case '[': parseTag(); break; case '%': /* Fall through */ case ';': c = TQChar::null; continue; break; default: Section = 1; c = TQChar::null; continue; break; } c = getch(); } } /* We should NEVER reach this point */ close(); return -1; } /////////////////////////////////////// // // pgn::load // /////////////////////////////////////// bool pgn::load( const int pos ) { TQString Token, Value; TQChar c; File.at(pos); clear(); /* Toplevel parsing loop */ while( 1 ) { if( Input.atEnd() ) break; currentLine = Input.readLine(); if( currentLine.isEmpty() ) { /* Finished with TAGs... now grab the move data for display */ File_Position = File.at(); while( 1 ) { currentLine = Input.readLine(); if( ( currentLine.at(0) == '[' ) || Input.atEnd() ) break; Move_Data << currentLine; } /* Allocate the Tab_PGNView */ pgnView = new tab_pgnView( this, Resource ); connect( pgnView, TQ_SIGNAL( destroyed() ), this, TQ_SLOT( childViewDestroyed() ) ); Resource->tabManager->addTab( pgnView, i18n( "%1 vs. %2" ).arg( TAG_White ).arg( TAG_Black ) ); pgnView->init(); File.at( File_Position ); currentLine = ""; return TRUE; } c = getch(); while( c != TQChar::null ) { Token = ""; Value = ""; switch( c ) { /* Special break... look for the Knights tag */ case '%': Value = getword(); if( Value == "KNIGHTS_CMD" ) parseKnightsData(); /* Fall through */ case ';': c = TQChar::null; continue; break; /* Tag Pair */ case '[': parseTag(); break; default: c = TQChar::null; break; } c = getch(); } } close(); return TRUE; } /////////////////////////////////////// // // pgn::loadNext // /////////////////////////////////////// bool pgn::loadNext( void ) { TQChar c; TQString Value; ChessMove Move; bool postMove( FALSE ); /* Toplevel parsing loop */ while( 1 ) { if( currentLine.isEmpty() ) { if( Input.atEnd() ) break; currentLine = Input.readLine(); } c = getch(); while( c != TQChar::null ) { Value = ""; switch( c ) { /* Special break... look for the Knights tag */ case '%': Value = getword(); if( Value == "KNIGHTS_CMD" ) parseKnightsData(); /* Fall through */ case ';': c = TQChar::null; continue; /* Tag Pair...next game, so we're done. */ case '[': return FALSE; /* Numeric Annotation Glyph */ case '$': c = getch(); while( ( c.unicode() >= '0' ) && ( c.unicode() <= '9' ) ) { Value += c; c = getch(); } Moves[ Moves.count() - 1 ].NAG = Value.toInt(); break; /* Recursive Annotation Variations */ case '(': parseRAV(); break; /* Textual Annotation */ case '{': parseAnnotation(); break; /* Reserved for future expansion by the PGN */ case '<': while( c != '>' ) c = getch(); break; /* Everything from '0' to '*' is null to us and falls through */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ' ': case '/': case '-': case '.': case '*': break; default: if( postMove ) { currentLine.prepend( c ); return TRUE; } /* Catch Standard Algebraic Notation */ while( ( c != TQChar::null ) && ( c != ' ' ) && ( c != ';' ) && ( c != '%' ) ) { Value += c; c = getch(); } strcpy( Move.SAN, Value.latin1() ); emit processMove( Move ); postMove = TRUE; } c = getch(); } } return FALSE; } /////////////////////////////////////// // // pgn::save // /////////////////////////////////////// bool pgn::save( TQString URL ) { TQFile Save( URL ); TQTextStream *Output; TQString Token, Value; close(); CurrentURL = URL; if( Resource->OPTION_Reuse_PGN && ( URL == Resource->PGN_Filename ) ) { Save.open( IO_WriteOnly | IO_Append ); } else { Save.open( IO_WriteOnly ); } Output = new TQTextStream( &Save ); (*Output) << "[Event \"" << TAG_Event << "\"]\n"; (*Output) << "[Site \"" << TAG_Site << "\"]\n"; (*Output) << "[Date \"" << TAG_Date << "\"]\n"; (*Output) << "[Round \"" << TAG_Round << "\"]\n"; (*Output) << "[White \"" << TAG_White << "\"]\n"; (*Output) << "[Black \"" << TAG_Black << "\"]\n"; (*Output) << "[Result \"" << TAG_Result << "\"]\n"; if( !TAG_TimeControl.isEmpty() ) (*Output) << "[TimeControl \"" << TAG_TimeControl << "\"]\n"; if( !TAG_WhiteTitle.isEmpty() ) (*Output) << "[WhiteTitle \"" << TAG_WhiteTitle << "\"]\n"; if( !TAG_WhiteElo.isEmpty() ) (*Output) << "[WhiteElo \"" << TAG_WhiteElo << "\"]\n"; if( !TAG_WhiteUSCF.isEmpty() ) (*Output) << "[WhiteUSCF \"" << TAG_WhiteUSCF << "\"]\n"; if( !TAG_WhiteNA.isEmpty() ) (*Output) << "[WhiteNA \"" << TAG_WhiteNA << "\"]\n"; if( !TAG_WhiteType.isEmpty() ) (*Output) << "[WhiteType \"" << TAG_WhiteType << "\"]\n"; if( !TAG_BlackTitle.isEmpty() ) (*Output) << "[BlackTitle \"" << TAG_BlackTitle << "\"]\n"; if( !TAG_BlackElo.isEmpty() ) (*Output) << "[BlackElo \"" << TAG_BlackElo << "\"]\n"; if( !TAG_BlackUSCF.isEmpty() ) (*Output) << "[BlackUSCF \"" << TAG_BlackUSCF << "\"]\n"; if( !TAG_BlackNA.isEmpty() ) (*Output) << "[BlackNA \"" << TAG_BlackNA << "\"]\n"; if( !TAG_BlackType.isEmpty() ) (*Output) << "[BlackType \"" << TAG_BlackType << "\"]\n"; if( !TAG_Time.isEmpty() ) (*Output) << "[Time \"" << TAG_Time << "\"]\n"; if( !TAG_UTCTime.isEmpty() ) (*Output) << "[UTCTime \"" << TAG_UTCTime << "\"]\n"; if( !TAG_UTCDate.isEmpty() ) (*Output) << "[UTCDate \"" << TAG_UTCDate << "\"]\n"; if( !TAG_EventDate.isEmpty() ) (*Output) << "[EventDate \"" << TAG_EventDate << "\"]\n"; if( !TAG_EventSponsor.isEmpty() ) (*Output) << "[EventSponsor \"" << TAG_EventSponsor << "\"]\n"; if( !TAG_Section.isEmpty() ) (*Output) << "[Section \"" << TAG_Section << "\"]\n"; if( !TAG_Stage.isEmpty() ) (*Output) << "[Stage \"" << TAG_Stage << "\"]\n"; if( !TAG_Board.isEmpty() ) (*Output) << "[Board \"" << TAG_Board << "\"]\n"; if( !TAG_Opening.isEmpty() ) (*Output) << "[Opening \"" << TAG_Opening << "\"]\n"; if( !TAG_Variation.isEmpty() ) (*Output) << "[Variation \"" << TAG_Variation << "\"]\n"; if( !TAG_SubVariation.isEmpty() ) (*Output) << "[SubVariation \"" << TAG_SubVariation << "\"]\n"; if( !TAG_ECO.isEmpty() ) (*Output) << "[ECO \"" << TAG_ECO << "\"]\n"; if( !TAG_NIC.isEmpty() ) (*Output) << "[NIC \"" << TAG_NIC << "\"]\n"; if( !TAG_Termination.isEmpty() ) (*Output) << "[Termination \"" << TAG_Termination << "\"]\n"; if( !TAG_SetUp.isEmpty() ) (*Output) << "[SetUp \"" << TAG_SetUp << "\"]\n"; if( !TAG_FEN.isEmpty() ) (*Output) << "[FEN \"" << TAG_FEN << "\"]\n"; if( !TAG_Annotator.isEmpty() ) (*Output) << "[Annotator \"" << TAG_Annotator << "\"]\n"; if( !TAG_Mode.isEmpty() ) (*Output) << "[Mode \"" << TAG_Mode << "\"]\n"; TAG_PlyCount = TQString().setNum( Moves.count() ); (*Output) << "[PlyCount \"" << TAG_PlyCount << "\"]\n"; /* Save internal data if this game is unfinished */ if( TAG_Result == "*" ) { (*Output) << "% KNIGHTS_CMD WhiteType "; switch( Param->type(WHITE) ) { case PLAYERPC: (*Output) << "PC\n"; break; case PLAYERTCP: (*Output) << "TCP\n"; break; case PLAYEREMAIL: (*Output) << "Email\n"; break; case PLAYERLOCAL: default: (*Output) << "Local\n"; break; } (*Output) << "% KNIGHTS_CMD BlackType "; switch( Param->type(BLACK) ) { case PLAYERPC: (*Output) << "PC\n"; break; case PLAYERTCP: (*Output) << "TCP\n"; break; case PLAYEREMAIL: (*Output) << "Email\n"; break; case PLAYERLOCAL: default: (*Output) << "Local\n"; break; } (*Output) << "% KNIGHTS_CMD WhiteTime " << whiteTime << "\n"; (*Output) << "% KNIGHTS_CMD BlackTime " << blackTime << "\n"; (*Output) << "% KNIGHTS_CMD DONE\n"; } /* End of internal data save */ (*Output) << "\n"; TQStringList *list = notation(2); TQString SAN = list->join( " " ); delete list; kdWarning() << SAN.right( 20 ) << endl; unsigned int pos = 80; unsigned int lastPos = 0; while( pos < SAN.length() ) { while( SAN.at( pos ) != ' ' ) pos--; SAN = SAN.replace( pos, 1, TQString("\n") ); lastPos = pos; pos = lastPos + 80; } kdWarning() << SAN.right( 20 ) << endl; (*Output) << SAN << " " << TAG_Result << "\n\n"; Save.close(); return TRUE; } /////////////////////////////////////// // // pgn::getch // /////////////////////////////////////// TQChar pgn::getch( void ) { TQChar c; c = currentLine.at(0); currentLine.remove( 0, 1 ); return c; } /////////////////////////////////////// // // pgn::getword // /////////////////////////////////////// TQString pgn::getword( void ) { TQChar c; TQString word; do { c = getch(); } while( c == ' ' ); while( ( c != ' ' ) && ( c != TQChar::null ) ) { word += c; c = getch(); } return word; } /////////////////////////////////////// // // pgn::open // /////////////////////////////////////// bool pgn::open( const TQString &URL ) { close(); if( !TDEIO::NetAccess::download( URL, tempFile ) ) return FALSE; File.setName( tempFile ); if( !File.open( IO_ReadOnly ) ) { close(); return FALSE; } Input.setDevice( &File ); CurrentURL = URL; File.at(0); return TRUE; } /////////////////////////////////////// // // pgn::close // /////////////////////////////////////// void pgn::close( void ) { if( !File.isOpen() ) { File.close(); } if( !tempFile.isEmpty() ) { TDEIO::NetAccess::removeTempFile( tempFile ); tempFile = ""; } } /////////////////////////////////////// // // pgn::parseTag // /////////////////////////////////////// void pgn::parseTag( void ) { TQChar c; TQString Token; TQString Value; c = getch(); while( c == ' ' ) c = getch(); while( c != '\"' ) { if( c == ' ' ) { c = getch(); continue; } Token += c; c = getch(); } c = getch(); while( c != '\"' ) { Value += c; c = getch(); } c = getch(); while( c != ']' ) c = getch(); /* Now Apply the Token/Value that we got */ if( Token == "Site" ) TAG_Site = Value; else if( Token == "Date" ) TAG_Date = Value; else if( Token == "Round" ) TAG_Round = Value; else if( Token == "Result" ) TAG_Result = Value; else if( Token == "White" ) TAG_White = Value; else if( Token == "WhiteTitle" ) TAG_WhiteTitle = Value; else if( Token == "WhiteElo" ) TAG_WhiteElo = Value; else if( Token == "WhiteUSCF" ) TAG_WhiteUSCF = Value; else if( Token == "WhiteNA" ) TAG_WhiteNA = Value; else if( Token == "WhiteType" ) TAG_WhiteType = Value; else if( Token == "Black" ) TAG_Black = Value; else if( Token == "BlackTitle" ) TAG_BlackTitle = Value; else if( Token == "BlackElo" ) TAG_BlackElo = Value; else if( Token == "BlackUSCF" ) TAG_BlackUSCF = Value; else if( Token == "BlackNA" ) TAG_BlackNA = Value; else if( Token == "BlackType" ) TAG_BlackType = Value; else if( Token == "Time" ) TAG_Time = Value; else if( Token == "UTCTime" ) TAG_UTCTime = Value; else if( Token == "UTCDate" ) TAG_UTCDate = Value; else if( Token == "Event" ) TAG_Event = Value; else if( Token == "EventDate" ) TAG_EventDate = Value; else if( Token == "EventSponsor") TAG_EventSponsor = Value; else if( Token == "Section" ) TAG_Section = Value; else if( Token == "Stage" ) TAG_Stage = Value; else if( Token == "Board" ) TAG_Board = Value; else if( Token == "Opening" ) TAG_Opening = Value; else if( Token == "Variation" ) TAG_Variation = Value; else if( Token == "SubVariation" ) TAG_SubVariation = Value; else if( Token == "ECO" ) TAG_ECO = Value; else if( Token == "NIC" ) TAG_NIC = Value; else if( Token == "TimeControl" ) TAG_TimeControl = Value; else if( Token == "Termination" ) TAG_Termination = Value; else if( Token == "SetUp" ) TAG_SetUp = Value; else if( Token == "FEN" ) TAG_FEN = Value; else if( Token == "Annotator" ) TAG_Annotator = Value; else if( Token == "Mode" ) TAG_Mode = Value; else if( Token == "PlyCount" ) TAG_PlyCount = Value; } /////////////////////////////////////// // // pgn::Parse_Annotation // /////////////////////////////////////// void pgn::parseAnnotation( const int fromRAVnum ) { Annotation *annon = new Annotation; TQChar c; c = getch(); while( c != '}' ) { if( c == TQChar::null ) { if( Input.eof() ) break; currentLine = Input.readLine(); c = ' '; } annon->text += c; c = getch(); } annon->RAV = fromRAVnum; annotations.add( Moves.count() - 1, annon ); // kdWarning() << "# " << annon.pos << " : " << annon.text << endl; } /////////////////////////////////////// // // pgn::Parse_RAV // /////////////////////////////////////// void pgn::parseRAV( void ) { int RAVLevel(1); Annotation *annon = new Annotation; TQChar c; while( RAVLevel ) { c = getch(); if( c == TQChar::null ) { if( Input.eof() ) break; currentLine = Input.readLine(); c = ' '; } if( c == ')' ) { RAVLevel--; if( !RAVLevel ) break; } if( c == '(' ) { RAVLevel++; } annon->text += c; } RAV.add( Moves.count() - 1, annon ); // kdWarning() << "# " << annon.pos << " : " << annon.text << endl; } /////////////////////////////////////// // // pgn::parseKnightsData // /////////////////////////////////////// void pgn::parseKnightsData( void ) { TQString Key; TQString Value; Key = getword(); if( Key == "DONE" ) { emit processSpecial(); return; } if( Key == "WhiteType" ) { Value = getword(); if( Value == "Local" ) Param->setType(WHITE, PLAYERLOCAL); if( Value == "PC" ) Param->setType(WHITE, PLAYERPC); if( Value == "TCP" ) Param->setType(WHITE, PLAYERTCP); if( Value == "Email" ) Param->setType(WHITE, PLAYEREMAIL); return; } if( Key == "BlackType" ) { Value = getword(); if( Value == "Local" ) Param->setType(BLACK, PLAYERLOCAL); if( Value == "PC" ) Param->setType(BLACK, PLAYERPC); if( Value == "TCP" ) Param->setType(BLACK, PLAYERTCP); if( Value == "Email" ) Param->setType(BLACK, PLAYEREMAIL); return; } if( Key == "WhiteTime" ) { Value = getword(); whiteTime = Value.toInt(); return; } if( Key == "BlackTime" ) { Value = getword(); blackTime = Value.toInt(); return; } } /////////////////////////////////////// // // pgn::print // /////////////////////////////////////// void pgn::print( void ) { if( !pgnView ) { /* Allocate the Tab_PGNView */ pgnView = new tab_pgnView( this, Resource ); Resource->tabManager->addTab( pgnView, i18n( "%1 vs. %2" ).arg( TAG_White ).arg( TAG_Black ) ); connect( pgnView, TQ_SIGNAL( destroyed() ), this, TQ_SLOT( childViewDestroyed() ) ); pgnView->init(); } pgnView->print(); } /////////////////////////////////////// // // pgn::childViewDestroyed // /////////////////////////////////////// void pgn::childViewDestroyed( void ) { pgnView = NULL; } /////////////////////////////////////// // // pgn::getNAG // /////////////////////////////////////// TQString pgn::getNAG( int num ) { TQString Line; switch( num ) { case 1: Line = i18n( "Good move" ); break; case 2: Line = i18n( "Poor move" ); break; case 3: Line = i18n( "Very good move" ); break; case 4: Line = i18n( "Very poor move" ); break; case 5: Line = i18n( "Speculative move" ); break; case 6: Line = i18n( "Questionable move" ); break; case 7: Line = i18n( "Forced move" ); break; case 8: Line = i18n( "Singular move" ); break; case 9: Line = i18n( "Worst move" ); break; case 10: Line = i18n( "Drawish position" ); break; case 11: Line = i18n( "Equal chances, quiet position" ); break; case 12: Line = i18n( "Equal chances, active position" ); break; case 13: Line = i18n( "Unclear position" ); break; case 14: Line = i18n( "White has a slight advantage" ); break; case 15: Line = i18n( "Black has a slight advantage" ); break; case 16: Line = i18n( "White has a moderate advantage" ); break; case 17: Line = i18n( "Black has a moderate advantage" ); break; case 18: Line = i18n( "White has a decisive advantage" ); break; case 19: Line = i18n( "Black has a decisive advantage" ); break; case 20: Line = i18n( "White has a crushing advantage ( Black should resign )" ); break; case 21: Line = i18n( "Black has a crushing advantage ( White should resign )" ); break; case 22: Line = i18n( "White is in zugzwang" ); break; case 23: Line = i18n( "Black is in zugzwang" ); break; case 24: Line = i18n( "White has a slight space advantage" ); break; case 25: Line = i18n( "Black has a slight space advantage" ); break; case 26: Line = i18n( "White has a moderate space advantage" ); break; case 27: Line = i18n( "Black has a moderate space advantage" ); break; case 28: Line = i18n( "White has a decisive space advantage" ); break; case 29: Line = i18n( "Black has a decisive space advantage" ); break; case 30: Line = i18n( "White has a slight time ( development ) advantage" ); break; case 31: Line = i18n( "Black has a slight time ( development ) advantage" ); break; case 32: Line = i18n( "White has a moderate time ( development ) advantage" ); break; case 33: Line = i18n( "Black has a moderate time ( development ) advantage" ); break; case 34: Line = i18n( "White has a decisive time ( development ) advantage" ); break; case 35: Line = i18n( "Black has a decisive time ( development ) advantage" ); break; case 36: Line = i18n( "White has the initiative" ); break; case 37: Line = i18n( "Black has the initiative" ); break; case 38: Line = i18n( "White has a lasting initiative" ); break; case 39: Line = i18n( "Black has a lasting initiative" ); break; case 40: Line = i18n( "White has the attack" ); break; case 41: Line = i18n( "Black has the attack" ); break; case 42: Line = i18n( "White has insufficient compensation for material deficit" ); break; case 43: Line = i18n( "Black has insufficient compensation for material deficit" ); break; case 44: Line = i18n( "White has sufficient compensation for material deficit" ); break; case 45: Line = i18n( "Black has sufficient compensation for material deficit" ); break; case 46: Line = i18n( "White has more than adequate compensation for material deficit" ); break; case 47: Line = i18n( "Black has more than adequate compensation for material deficit" ); break; case 48: Line = i18n( "White has a slight center control advantage" ); break; case 49: Line = i18n( "Black has a slight center control advantage" ); break; case 50: Line = i18n( "White has a moderate center control advantage" ); break; case 51: Line = i18n( "Black has a moderate center control advantage" ); break; case 52: Line = i18n( "White has a decisive center control advantage" ); break; case 53: Line = i18n( "Black has a decisive center control advantage" ); break; case 54: Line = i18n( "White has a slight kingside control advantage" ); break; case 55: Line = i18n( "Black has a slight kingside control advantage" ); break; case 56: Line = i18n( "White has a moderate kingside control advantage" ); break; case 57: Line = i18n( "Black has a moderate kingside control advantage" ); break; case 58: Line = i18n( "White has a decisive kingside control advantage" ); break; case 59: Line = i18n( "Black has a decisive kingside control advantage" ); break; case 60: Line = i18n( "White has a slight queenside control advantage" ); break; case 61: Line = i18n( "Black has a slight queenside control advantage" ); break; case 62: Line = i18n( "White has a moderate queenside control advantage" ); break; case 63: Line = i18n( "Black has a moderate queenside control advantage" ); break; case 64: Line = i18n( "White has a decisive queenside control advantage" ); break; case 65: Line = i18n( "Black has a decisive queenside control advantage" ); break; case 66: Line = i18n( "White has a vulnerable first rank" ); break; case 67: Line = i18n( "Black has a vulnerable first rank" ); break; case 68: Line = i18n( "White has a well protected first rank" ); break; case 69: Line = i18n( "Black has a well protected first rank" ); break; case 70: Line = i18n( "White has a poorly protected king" ); break; case 71: Line = i18n( "Black has a poorly protected king" ); break; case 72: Line = i18n( "White has a well protected king" ); break; case 73: Line = i18n( "Black has a well protected king" ); break; case 74: Line = i18n( "White has a poorly placed king" ); break; case 75: Line = i18n( "Black has a poorly placed king" ); break; case 76: Line = i18n( "White has a well placed king" ); break; case 77: Line = i18n( "Black has a well placed king" ); break; case 78: Line = i18n( "White has a very weak pawn structure" ); break; case 79: Line = i18n( "Black has a very weak pawn structure" ); break; case 80: Line = i18n( "White has a moderately weak pawn structure" ); break; case 81: Line = i18n( "Black has a moderately weak pawn structure" ); break; case 82: Line = i18n( "White has a moderately strong pawn structure" ); break; case 83: Line = i18n( "Black has a moderately strong pawn structure" ); break; case 84: Line = i18n( "White has a very strong pawn structure" ); break; case 85: Line = i18n( "Black has a very strong pawn structure" ); break; case 86: Line = i18n( "White has poor knight placement" ); break; case 87: Line = i18n( "Black has poor knight placement" ); break; case 88: Line = i18n( "White has good knight placement" ); break; case 89: Line = i18n( "Black has good knight placement" ); break; case 90: Line = i18n( "White has poor bishop placement" ); break; case 91: Line = i18n( "Black has poor bishop placement" ); break; case 92: Line = i18n( "White has good bishop placement" ); break; case 93: Line = i18n( "Black has good bishop placement" ); break; case 94: Line = i18n( "White has poor rook placement" ); break; case 95: Line = i18n( "Black has poor rook placement" ); break; case 96: Line = i18n( "White has good rook placement" ); break; case 97: Line = i18n( "Black has good rook placement" ); break; case 98: Line = i18n( "White has poor queen placement" ); break; case 99: Line = i18n( "Black has poor queen placement" ); break; case 100: Line = i18n( "White has good queen placement" ); break; case 101: Line = i18n( "Black has good queen placement" ); break; case 102: Line = i18n( "White has poor piece coordination" ); break; case 103: Line = i18n( "Black has poor piece coordination" ); break; case 104: Line = i18n( "White has good piece coordination" ); break; case 105: Line = i18n( "Black has good piece coordination" ); break; case 106: Line = i18n( "White has played the opening very poorly" ); break; case 107: Line = i18n( "Black has played the opening very poorly" ); break; case 108: Line = i18n( "White has played the opening poorly" ); break; case 109: Line = i18n( "Black has played the opening poorly" ); break; case 110: Line = i18n( "White has played the opening well" ); break; case 111: Line = i18n( "Black has played the opening well" ); break; case 112: Line = i18n( "White has played the opening very well" ); break; case 113: Line = i18n( "Black has played the opening very well" ); break; case 114: Line = i18n( "White has played the middlegame very poorly" ); break; case 115: Line = i18n( "Black has played the middlegame very poorly" ); break; case 116: Line = i18n( "White has played the middlegame poorly" ); break; case 117: Line = i18n( "Black has played the middlegame poorly" ); break; case 118: Line = i18n( "White has played the middlegame well" ); break; case 119: Line = i18n( "Black has played the middlegame well" ); break; case 120: Line = i18n( "White has played the middlegame very well" ); break; case 121: Line = i18n( "Black has played the middlegame very well" ); break; case 122: Line = i18n( "White has played the ending very poorly" ); break; case 123: Line = i18n( "Black has played the ending very poorly" ); break; case 124: Line = i18n( "White has played the ending poorly" ); break; case 125: Line = i18n( "Black has played the ending poorly" ); break; case 126: Line = i18n( "White has played the ending well" ); break; case 127: Line = i18n( "Black has played the ending well" ); break; case 128: Line = i18n( "White has played the ending very well" ); break; case 129: Line = i18n( "Black has played the ending very well" ); break; case 130: Line = i18n( "White has slight counterplay" ); break; case 131: Line = i18n( "Black has slight counterplay" ); break; case 132: Line = i18n( "White has moderate counterplay" ); break; case 133: Line = i18n( "Black has moderate counterplay" ); break; case 134: Line = i18n( "White has decisive counterplay" ); break; case 135: Line = i18n( "Black has decisive counterplay" ); break; case 136: Line = i18n( "White has moderate time control pressure" ); break; case 137: Line = i18n( "Black has moderate time control pressure" ); break; case 138: Line = i18n( "White has severe time control pressure" ); break; case 139: Line = i18n( "Black has severe time control pressure" ); case 140: Line = i18n( "With the idea..." ); break; case 141: Line = i18n( "Aimed against..." ); break; case 142: Line = i18n( "Better Move" ); break; case 143: Line = i18n( "Worse Move" ); break; case 144: Line = i18n( "Equivalent move" ); break; case 145: Line = i18n( "Editor's Remark" ); break; case 146: Line = i18n( "Novelty" ); break; case 147: Line = i18n( "Weak point" ); break; case 148: Line = i18n( "Endgame" ); break; case 149: Line = i18n( "Line" ); break; case 150: Line = i18n( "Diagonal" ); break; case 151: Line = i18n( "White has a pair of Bishops" ); break; case 152: Line = i18n( "Black has a pair of Bishops" ); break; case 153: Line = i18n( "Bishops of opposite color" ); break; case 154: Line = i18n( "Bishops of same color" ); break; case 190: Line = i18n( "Etc." ); break; case 191: Line = i18n( "Doubled pawns" ); break; case 192: Line = i18n( "Isolated pawn" ); break; case 193: Line = i18n( "Connected pawns" ); break; case 194: Line = i18n( "Hanging pawns" ); break; case 195: Line = i18n( "Backwards pawn" ); break; default: Line = ""; break; } return Line; }