Overview

Namespaces

  • pgn
    • exceptions
    • tags
  • utils

Classes

  • pgn\Game
  • pgn\PGN
  • pgn\tags\Annotator
  • pgn\tags\Black
  • pgn\tags\BlackElo
  • pgn\tags\BlackNA
  • pgn\tags\BlackTitle
  • pgn\tags\BlackType
  • pgn\tags\BlackUSCF
  • pgn\tags\Board
  • pgn\tags\Date
  • pgn\tags\ECO
  • pgn\tags\Event
  • pgn\tags\EventCountry
  • pgn\tags\EventDate
  • pgn\tags\EventRounds
  • pgn\tags\EventSponsor
  • pgn\tags\EventType
  • pgn\tags\FEN
  • pgn\tags\Mode
  • pgn\tags\NIC
  • pgn\tags\Opening
  • pgn\tags\PlyCount
  • pgn\tags\Result
  • pgn\tags\Round
  • pgn\tags\Section
  • pgn\tags\SetUp
  • pgn\tags\Site
  • pgn\tags\Source
  • pgn\tags\SourceDate
  • pgn\tags\Stage
  • pgn\tags\SubVariation
  • pgn\tags\Tag
  • pgn\tags\Termination
  • pgn\tags\Time
  • pgn\tags\TimeControl
  • pgn\tags\UknownTag
  • pgn\tags\UTCDate
  • pgn\tags\UTCTime
  • pgn\tags\Variation
  • pgn\tags\White
  • pgn\tags\WhiteElo
  • pgn\tags\WhiteNA
  • pgn\tags\WhiteTitle
  • pgn\tags\WhiteType
  • pgn\tags\WhiteUSCF
  • utils\Parser
  • utils\String

Exceptions

  • pgn\exceptions\InvalidClassNameException
  • pgn\exceptions\InvalidDataException
  • pgn\exceptions\InvalidGameFormatException
  • pgn\exceptions\InvalidGamePathException
  • pgn\exceptions\PGNException
  • utils\ParserException
  • Overview
  • Namespace
  • Class
  1: <?php
  2: /* 
  3:  * Copyright (c) 2016 Geraldo B. Landre
  4:  * 
  5:  * See the file LICENSE for copying permission.
  6:  */
  7: namespace pgn;
  8: 
  9: use pgn\tags\Tag;
 10: use pgn\exceptions\InvalidGameFormatException;
 11: 
 12: /**
 13:  * Description of Game:
 14:  * A PGN Game is composed by a set of tags (at least STR) and a movetext section:
 15:  * The movetext section is composed of chess moves, move number indications, 
 16:  * optional annotations, and a single concluding game termination marker. 
 17:  *  
 18:  * @todo Because illegal moves are not real chess moves, they are not permitted in PGN 
 19:  * movetext.  They may appear in commentary, however.  One would hope that illegal 
 20:  * moves are relatively rare in games worthy of recording.
 21:  * 
 22:  * Game Termination Markers:
 23:  *  
 24:  * Each movetext section has exactly one game termination marker; the marker 
 25:  * always occurs as the last element in the movetext.  The game termination marker 
 26:  * is a symbol that is one of the following four values: "1-0" (White wins), "0-1" 
 27:  * (Black wins), "1/2-1/2" (drawn game), and "*" (game in progress, result 
 28:  * unknown, or game abandoned).  Note that the digit zero is used in the above; 
 29:  * not the upper case letter "O".  The game termination marker appearing in the 
 30:  * movetext of a game must match the value of the game's Result tag pair.  (While 
 31:  * the marker appears as a string in the Result tag, it appears as a symbol 
 32:  * without quotes in the movetext.)
 33:  * @see pgn_standard.txt
 34:  * @author Geraldo
 35:  */
 36: class Game {
 37: 
 38:     /**
 39:      *
 40:      * @var Tag [] array of tags
 41:      */
 42:     private $tags;
 43: 
 44:     /**
 45:      *
 46:      * @var string 
 47:      */
 48:     private $moveText;
 49: 
 50:     /**
 51:      *
 52:      * @var string [] array
 53:      */
 54:     private $parseErrors;
 55: 
 56:     /**
 57:      * Creates an empty Game
 58:      */
 59:     public function __construct() {
 60:         $this->moveText = "";
 61:         $this->tags = array();
 62:         $this->parseErrors = array();
 63:     }
 64: 
 65:     /**
 66:      * Returns a string representation of the Game object
 67:      * @return string a string representation of the PGN object
 68:      */
 69:     public function __toString() {
 70:         return $this->toString();
 71:     }
 72:     
 73:     /**
 74:      * Returns a string representation of the Game object
 75:      * @todo implement support of a properties file with the property defaultEndLine
 76:      * @param string $endl The end-line character (default: "\n").
 77:      * Example:
 78:      * <pre><code>
 79:      * <?php
 80:      * $object = new Game;
 81:      * $object->toString("<br />");
 82:      * </code></pre>
 83:      * @return string a string representation of the PGN object
 84:      */
 85:     public function toString($endLine = "\n") {
 86:         
 87:         if (empty($this->moveText) && count($this->tags) == 0) {
 88:             return "";
 89:         }
 90:         
 91:         $strTags = "";
 92:         foreach($this->tags as $tag) {
 93:             $strTags .= $tag . $endLine;
 94:         }
 95:         
 96:         return $strTags . $endLine . $endLine . $this->moveText;
 97:     }
 98:     
 99:     /**
100:      * Parses a string containing a game and fills movetext and tags attributes.
101:      * The tag attribute is filled as an associative array (TagName => TagObject)
102:      * 
103:      * @assert(NULL) throws pgn\exceptions\InvalidGameFormatException
104:      * @assert(123) throws pgn\exceptions\InvalidGameFormatException
105:      * 
106:      * @param string $unparsedGame string containing one PGN Game
107:      * @throws InvalidGameFormatException throws an exception if the parameter
108:      *         is not a string or if it doesn't have the correct fields, i.e.
109:      *         the move text and the seven roster tags
110:      */
111:     public function parse($unparsedGame) {
112:         if (!is_string($unparsedGame)) {
113:             throw new InvalidGameFormatException("[" . __CLASS__ . "] invalid game format (it's not a valid string): " . $unparsedGame);
114:         }
115:         
116:         $parsing = explode("]", $unparsedGame);
117:         
118:         if(count($parsing) < 8) {
119:             throw new InvalidGameFormatException("[" . __CLASS__ . "] invalid game format (it doesn't have correct fields): " . $unparsedGame);
120:         }
121:         
122:         $uncheckedMoveText = array_pop($parsing);
123: 
124:         foreach ($parsing as $unparsedTag) {
125:             $tag = Tag::parse($unparsedTag . "]", $this->parseErrors);
126:             $this->addTag($tag);
127:         }
128:         
129:         if (!$this->checkSetUpAndFEN()) {
130:             throw new InvalidGameFormatException("[" . __CLASS__ . "] invalid game format (SetUp=1 without FEN): " . $unparsedGame);
131:         }
132:         
133:         if ($this->checkMoveText($uncheckedMoveText)) {
134:             $this->moveText = $uncheckedMoveText;
135:         } else {
136:             $this->parseErrors[] = "[" . __CLASS__ . "] MoveText: " . $uncheckedMoveText;
137:         }
138:     }
139:     
140:     /**
141:      * 
142:      * @param string $tagName
143:      * @return Tag
144:      */
145:     public function getTag($tagName) {
146:         if(array_key_exists($tagName, $this->tags)) {
147:             return $this->tags[$tagName];
148:         }
149:         return NULL;
150:     }
151:     
152:     /**
153:      * 
154:      * @param Tag $tag
155:      */
156:     public function addTag($tag) {
157:         if ($tag instanceof Tag) {
158:             $this->tags[$tag->getName()] = $tag;
159:         }
160:     }
161:     
162:     /**
163:      * @todo implement this method
164:      * @param string $uncheckedMoveText
165:      * @return boolean
166:      */
167:     protected function checkMoveText($uncheckedMoveText) {
168:         return true;
169:     }
170: 
171:     protected function checkSetUpAndFEN() {
172:         $setUp = $this->getTag("SetUp");
173:         $fen = $this->getTag("FEN");
174:         
175:         // the pair SetUp and FEN must exists together
176:         if($setUp === NULL) {
177:             return $fen === NULL;
178:         }
179:         else {
180:             return $fen !== NULL;
181:         }
182:     }
183: 
184: }
185: 
API documentation generated by ApiGen