mirror of
https://github.com/JeroenED/libpairtwo.git
synced 2024-11-25 15:57:41 +01:00
Jeroen De Meerleer
ad1f64914a
There is no such thing as american scoring. The only american thing in tournament chess is the american pairing system wihich uses some variables to calculate your opponent. One of these was called americanpoints in the original sources of pairtwo. This one was unfortunatly mistaken to really contain an american scoring
901 lines
30 KiB
PHP
901 lines
30 KiB
PHP
<?php
|
|
/**
|
|
* Reader Pairtwo6
|
|
*
|
|
* Reads out Pairtwo-6 files
|
|
*
|
|
* @author Jeroen De Meerleer <schaak@jeroened.be>
|
|
* @category Main
|
|
* @package Libpairtwo
|
|
* @copyright Copyright (c) 2018-2019 Jeroen De Meerleer <schaak@jeroened.be>
|
|
*/
|
|
|
|
|
|
namespace JeroenED\Libpairtwo\Readers;
|
|
|
|
use JeroenED\Libpairtwo\Enums\Color;
|
|
use JeroenED\Libpairtwo\Enums\Gender;
|
|
use JeroenED\Libpairtwo\Enums\Result;
|
|
use JeroenED\Libpairtwo\Enums\Tiebreak;
|
|
use JeroenED\Libpairtwo\Enums\Title;
|
|
use JeroenED\Libpairtwo\Enums\TournamentSystem;
|
|
use JeroenED\Libpairtwo\Exceptions\IncompatibleReaderException;
|
|
use JeroenED\Libpairtwo\Interfaces\ReaderInterface;
|
|
use JeroenED\Libpairtwo\Pairing;
|
|
use JeroenED\Libpairtwo\Player;
|
|
use JeroenED\Libpairtwo\Round;
|
|
use JeroenED\Libpairtwo\Tournament;
|
|
use DateTime;
|
|
|
|
/**
|
|
* Reader Pairtwo6
|
|
*
|
|
* Reads out Pairtwo-6 files
|
|
*
|
|
* @author Jeroen De Meerleer <schaak@jeroened.be>
|
|
* @category Main
|
|
* @package Libpairtwo
|
|
* @copyright Copyright (c) 2018-2019 Jeroen De Meerleer <schaak@jeroened.be>
|
|
*/
|
|
class Pairtwo6 implements ReaderInterface
|
|
{
|
|
private const PT_DAYFACTOR = 32;
|
|
private const PT_MONTHFACTOR = 16;
|
|
private const PT_YEARFACTOR = 512;
|
|
private const PT_PASTOFFSET = 117;
|
|
private const CompatibleVersions = ['6.', '5.'];
|
|
|
|
/** @var string */
|
|
private $Release;
|
|
|
|
/** @var Tournament */
|
|
private $Tournament;
|
|
|
|
/** @var bool|DateTime|int|string[] */
|
|
private $BinaryData;
|
|
|
|
/**
|
|
* Returns the version tag of Pairtwo which created the pairtwo file
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getRelease(): string
|
|
{
|
|
return $this->Release;
|
|
}
|
|
|
|
/**
|
|
* Sets the version tag of Pairtwo which created the pairtwo file
|
|
*
|
|
* @param string $Release
|
|
* @return Pairtwo6
|
|
*/
|
|
public function setRelease(string $Release): Pairtwo6
|
|
{
|
|
$this->Release = $Release;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns the tournament that was read out of the pairtwo file
|
|
*
|
|
* @return Tournament
|
|
*/
|
|
public function getTournament(): Tournament
|
|
{
|
|
return $this->Tournament;
|
|
}
|
|
|
|
/**
|
|
* Sets the tournament that was read out of the pairtwo file
|
|
*
|
|
* @param Tournament $Tournament
|
|
* @return Pairtwo6
|
|
*/
|
|
public function setTournament(Tournament $Tournament): Pairtwo6
|
|
{
|
|
$this->Tournament = $Tournament;
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns binary data that was read out the pairtwo file but was not needed immediately
|
|
*
|
|
* @param string $Key
|
|
* @return bool|DateTime|int|string|null
|
|
*/
|
|
public function getBinaryData(string $Key)
|
|
{
|
|
if (isset($this->BinaryData[$Key])) {
|
|
return $this->BinaryData[$Key];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets binary data that is read out the pairtwo file but is not needed immediately
|
|
*
|
|
* @param string $Key
|
|
* @param bool|int|DateTime|string $Value
|
|
* @return Pairtwo6
|
|
*/
|
|
public function setBinaryData(string $Key, $Value): Pairtwo6
|
|
{
|
|
$this->BinaryData[$Key] = $Value;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Reads out $swsfile and returns a Pairtwo6 class object
|
|
*
|
|
* @param string $filename
|
|
* @return Pairtwo6
|
|
* @throws IncompatibleReaderException
|
|
*/
|
|
public function read(string $filename): ReaderInterface
|
|
{
|
|
$swshandle = fopen($filename, 'rb');
|
|
$swscontents = fread($swshandle, filesize($filename));
|
|
fclose($swshandle);
|
|
|
|
$offset = 0;
|
|
|
|
|
|
$length = 4;
|
|
$this->setRelease($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
if (array_search(substr($this->getRelease(), 0, 2), self::CompatibleVersions) === false) {
|
|
throw new IncompatibleReaderException("This file was not created with Pairtwo 5 or higher");
|
|
}
|
|
|
|
$this->setTournament(new Tournament());
|
|
$this->getTournament()->setPriorityElo('Nation');
|
|
$this->getTournament()->setPriorityId('Nation');
|
|
// UserCountry
|
|
$length = 4;
|
|
$this->setBinaryData("UserCountry", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// SavedOffset
|
|
$length = 4;
|
|
$this->setBinaryData("SavedOffset", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// NewPlayer
|
|
$length = 4;
|
|
$this->setBinaryData("NewPlayer", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// AmericanHandicap
|
|
$length = 4;
|
|
$this->setBinaryData("AmericanHandicap", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// LowOrder
|
|
$length = 4;
|
|
$this->setBinaryData("LowOrder", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// PairingMethod
|
|
$length = 4;
|
|
$this->setBinaryData("PairingMethod", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// AmericanPresence
|
|
$length = 4;
|
|
$this->setBinaryData("AmericanPresence", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// CheckSameClub
|
|
$length = 4;
|
|
$this->setBinaryData("CheckSameClub", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// NoColorCheck
|
|
$length = 4;
|
|
$this->setBinaryData("NoColorCheck", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// SeparateCategories
|
|
$length = 4;
|
|
$this->setBinaryData("SeparateCategories", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// EloUsed
|
|
$length = 4;
|
|
$this->setBinaryData("EloUsed", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// AlternateColors
|
|
$length = 4;
|
|
$this->setBinaryData("AlternateColors", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// MaxMeetings
|
|
$length = 4;
|
|
$this->setBinaryData("MaxMeetings", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// MaxDistance
|
|
$length = 4;
|
|
$this->setBinaryData("MaxDistance", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// MinimizeKeizer
|
|
$length = 4;
|
|
$this->setBinaryData("MinimizeKeizer", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// MinRoundsMeetings
|
|
$length = 4;
|
|
$this->setBinaryData("MinRoundsMeetings", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// MaxRoundsAbsent
|
|
$length = 4;
|
|
$this->setBinaryData("MaxRoundsAbsent", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// SpecialPoints
|
|
$length = 4 * 6;
|
|
$this->setBinaryData("SpecialPoints", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// NewNamePos
|
|
$length = 4;
|
|
$this->setBinaryData("NewNamePos", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// CurrentRound
|
|
$length = 4;
|
|
$this->setBinaryData("CurrentRound", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// CreatedRounds
|
|
$length = 4;
|
|
$this->setBinaryData("CreatedRounds", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// CreatedPlayers
|
|
$length = 4;
|
|
$this->setBinaryData("CreatedPlayers", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// MaxSelection
|
|
$length = 4;
|
|
$this->setBinaryData("MaxSelection", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// NumberOfRounds
|
|
$length = 4;
|
|
$this->setBinaryData("NumberOfRounds", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// NumberOfPairings
|
|
$length = 4;
|
|
$this->setBinaryData("NumberOfPairings", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// CreatedPairings
|
|
$length = 4;
|
|
$this->setBinaryData("CreatedPairings", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// PairingElems
|
|
$length = 4;
|
|
$this->setBinaryData("PairingElems", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// RandomSeed
|
|
$length = 4;
|
|
$this->setBinaryData("RandomSeed", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// TieOrder
|
|
for ($i = 0; $i < 5; $i++) {
|
|
$length = 4;
|
|
switch ($this->readData('Int', substr($swscontents, $offset, $length))) {
|
|
case 1:
|
|
$tiebreak = Tiebreak::Buchholz;
|
|
break;
|
|
case 2:
|
|
$tiebreak = Tiebreak::BuchholzMed;
|
|
break;
|
|
case 3:
|
|
$tiebreak = Tiebreak::BuchholzCut;
|
|
break;
|
|
case 4:
|
|
$tiebreak = Tiebreak::Sonneborn;
|
|
break;
|
|
case 5:
|
|
$tiebreak = Tiebreak::Kashdan;
|
|
break;
|
|
case 6:
|
|
$tiebreak = Tiebreak::Cumulative;
|
|
break;
|
|
case 7:
|
|
$tiebreak = Tiebreak::Between;
|
|
break;
|
|
case 8:
|
|
$tiebreak = Tiebreak::Koya;
|
|
break;
|
|
case 9:
|
|
$tiebreak = Tiebreak::Baumbach;
|
|
break;
|
|
case 10:
|
|
$tiebreak = Tiebreak::Performance;
|
|
break;
|
|
case 11:
|
|
$tiebreak = Tiebreak::Aro;
|
|
break;
|
|
case 12:
|
|
$tiebreak = Tiebreak::AroCut;
|
|
break;
|
|
case 13:
|
|
$tiebreak = Tiebreak::BlackPlayed;
|
|
break;
|
|
case 14:
|
|
$tiebreak = Tiebreak::Testmatch;
|
|
break;
|
|
case 15:
|
|
$tiebreak = Tiebreak::Drawing;
|
|
break;
|
|
case 0:
|
|
default:
|
|
$tiebreak = Tiebreak::None;
|
|
break;
|
|
}
|
|
$this->getTournament()->addTieBreak(new Tiebreak($tiebreak));
|
|
$offset += $length;
|
|
}
|
|
|
|
// Categorie
|
|
$length = 4 * 10;
|
|
$this->setBinaryData("Categorie", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// ExtraPoints
|
|
$length = 4 * 20;
|
|
$this->setBinaryData("ExtraPoints", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// SelectP
|
|
$length = 4 * 20;
|
|
$this->setBinaryData("SelectP", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Players
|
|
for ($i = 0; $i < $this->getBinaryData("NewPlayer"); $i++) {
|
|
$player = new Player();
|
|
|
|
// Rank (Unused value)
|
|
$length = 4;
|
|
$player->setBinaryData("Rank", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setBinaryData("NamePos", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setId('Fide', $this->readData('Int', substr($swscontents, $offset, $length) . ""));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setBinaryData("ExtraPts", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setElo('Nation', $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->SetDateOfBirth($this->readData('Date', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setId('Nation', $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setBinaryData("Points", $this->readData('Int', substr($swscontents, $offset, $length)) / 2);
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setId('Club', $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setBinaryData("ScoreBuchholz", $this->readData('Int', substr($swscontents, $offset, $length)) / 2);
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setBinaryData("ScoreAmerican", $this->readData('Int', substr($swscontents, $offset, $length)) / 2);
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setBinaryData("HelpValue", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 4;
|
|
$player->setElo('Fide', $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("NameLength", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 3;
|
|
$player->setNation($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setCategory($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
switch ($this->readData('Int', substr($swscontents, $offset, $length))) {
|
|
case 1:
|
|
$title = Title::ELO;
|
|
break;
|
|
case 2:
|
|
$title = Title::NM;
|
|
break;
|
|
case 3:
|
|
$title = Title::WCM;
|
|
break;
|
|
case 4:
|
|
$title = Title::WFM;
|
|
break;
|
|
case 5:
|
|
$title = Title::CM;
|
|
break;
|
|
case 6:
|
|
$title = Title::WIM;
|
|
break;
|
|
case 7:
|
|
$title = Title::FM;
|
|
break;
|
|
case 8:
|
|
$title = Title::WGM;
|
|
break;
|
|
case 9:
|
|
$title = Title::HM;
|
|
break;
|
|
case 10:
|
|
$title = Title::IM;
|
|
break;
|
|
case 11:
|
|
$title = Title::HG;
|
|
break;
|
|
case 12:
|
|
$title = Title::GM;
|
|
break;
|
|
case 0:
|
|
default:
|
|
$title = Title::NONE;
|
|
break;
|
|
}
|
|
$player->setTitle(new Title($title));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
switch ($this->readData('Int', substr($swscontents, $offset, $length))) {
|
|
case 1:
|
|
$gender = Gender::Male;
|
|
break;
|
|
case 2:
|
|
$gender = Gender::Female;
|
|
break;
|
|
default:
|
|
$gender = Gender::Neutral;
|
|
break;
|
|
}
|
|
$player->setGender(new Gender($gender));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData('NumberOfTies', $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData('Absent', $this->readData('Bool', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("ColorDiff", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("ColorPref", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("Paired", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("Float", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("FloatPrev", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("FloatBefore", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
$player->setBinaryData("TieMatch", $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
$this->getTournament()->addPlayer($player);
|
|
}
|
|
// PlayerNames
|
|
$length = (Integer)$this->getBinaryData("NewNamePos") + 0;
|
|
$this->setBinaryData("PlayerNames", substr($swscontents, $offset, $length));
|
|
$offset += $length;
|
|
|
|
for ($i = 0; $i < $this->getBinaryData("NewPlayer"); $i++) {
|
|
$player = $this->getTournament()->getPlayerById($i);
|
|
$namelength = $player->getBinaryData("NameLength");
|
|
$nameoffset = $player->getBinaryData("NamePos");
|
|
$player->setName($this->readData("String", substr($this->getBinaryData("PlayerNames"), $nameoffset, $namelength)));
|
|
|
|
$this->getTournament()->updatePlayer($i, $player);
|
|
}
|
|
|
|
// TournamentName
|
|
$length = 80;
|
|
$this->getTournament()->setName($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// TournamentOrganiser
|
|
$length = 50;
|
|
$this->getTournament()->setOrganiser($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// TournamentTempo
|
|
$length = 50;
|
|
$this->getTournament()->setTempo($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// TournamentCountry
|
|
$length = 32;
|
|
$this->getTournament()->setOrganiserCountry($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Arbiters
|
|
$length = 128;
|
|
$this->getTournament()->setArbiter($this->readData('String', substr($swscontents, $offset, $length)), 0);
|
|
$offset += $length;
|
|
|
|
// Rounds
|
|
$length = 4;
|
|
$this->getTournament()->setNoOfRounds($this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Participants
|
|
$length = 4;
|
|
$this->setBinaryData('Participants', $this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Fidehomol
|
|
$length = 4;
|
|
$this->getTournament()->setFideHomol($this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// StartDate
|
|
$length = 4;
|
|
$this->getTournament()->setStartDate($this->readData('Date', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// EndDate
|
|
$length = 4;
|
|
$this->getTournament()->setEndDate($this->readData('Date', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Place
|
|
$length = 36;
|
|
$this->getTournament()->setOrganiserPlace($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// First period
|
|
$length = 32;
|
|
$this->getTournament()->setFirstPeriod($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Second period
|
|
$length = 32;
|
|
$this->getTournament()->setSecondPeriod($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Unrated Elo
|
|
$length = 4;
|
|
$this->getTournament()->setNonRatedElo($this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Type
|
|
$length = 4;
|
|
switch ($this->readData('Int', substr($swscontents, $offset, $length))) {
|
|
case 2:
|
|
$system = TournamentSystem::Closed;
|
|
break;
|
|
case 4:
|
|
$system = TournamentSystem::American;
|
|
break;
|
|
case 6:
|
|
$system = TournamentSystem::Keizer;
|
|
break;
|
|
case 0:
|
|
default:
|
|
$system = TournamentSystem::Swiss;
|
|
break;
|
|
}
|
|
$this->getTournament()->setSystem(new TournamentSystem($system));
|
|
$offset += $length;
|
|
|
|
// Federation
|
|
$length = 12;
|
|
$this->getTournament()->setFederation($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Soustype
|
|
/*
|
|
* 32 Bits:
|
|
* 1 bit = Libre?
|
|
* 6 bits = First round sent to FIDE
|
|
* 6 bits = First round sent to FRBE-KBSB
|
|
* 6 bits = Last round sent to FIDE
|
|
* 6 bits = Last round sent to FRBE-KBSB
|
|
* 6 bits = Number of the First board
|
|
* 1 bit = Double round robin
|
|
*/
|
|
$length = 4;
|
|
$this->setBinaryData('SousType', $this->readData('Hex', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Organising club no
|
|
$length = 4;
|
|
$this->getTournament()->setOrganiserClubNo($this->readData('String', substr($swscontents, $offset, $length), 0));
|
|
$offset += $length;
|
|
|
|
// Organising club
|
|
$length = 8;
|
|
$this->getTournament()->setOrganiserClub($this->readData('String', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Tournament year
|
|
$length = 4;
|
|
$this->getTournament()->setYear($this->readData('Int', substr($swscontents, $offset, $length)));
|
|
$offset += $length;
|
|
|
|
// Round dates
|
|
for ($i = 0; $i < $this->getTournament()->getNoOfRounds(); $i++) {
|
|
$length = 4;
|
|
$round = new Round();
|
|
$round->setRoundNo($i);
|
|
$round->setDate($this->readData('Date', substr($swscontents, $offset, $length)));
|
|
$this->getTournament()->addRound($round);
|
|
$offset += $length;
|
|
}
|
|
|
|
if ($this->getBinaryData("CurrentRound") > 0) {
|
|
for ($i = 0; $i < $this->getBinaryData("NewPlayer"); $i++) {
|
|
for ($x = 0; $x < $this->getBinaryData("CreatedRounds"); $x++) {
|
|
$pairing = new Pairing();
|
|
|
|
$pairing->setPlayer($this->getTournament()->getPlayerById($i));
|
|
|
|
$length = 4;
|
|
$opponent = $this->readData('Int', substr($swscontents, $offset, $length));
|
|
if ($opponent != 4294967295) {
|
|
$pairing->setOpponent($this->getTournament()->getPlayerById($opponent));
|
|
}
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
|
|
switch ($this->readData('Int', substr($swscontents, $offset, $length))) {
|
|
case 255:
|
|
case 253:
|
|
$color = Color::Black;
|
|
break;
|
|
case 1:
|
|
case 3:
|
|
$color = Color::White;
|
|
break;
|
|
case 0:
|
|
default:
|
|
$color = Color::None;
|
|
break;
|
|
}
|
|
$pairing->setColor(new Color($color));
|
|
$offset += $length;
|
|
|
|
$length = 1;
|
|
switch ($this->readData('Int', substr($swscontents, $offset, $length))) {
|
|
case 1:
|
|
$result = Result::Lost;
|
|
break;
|
|
case 2:
|
|
$result = Result::Absent;
|
|
break;
|
|
case 3:
|
|
$result = Result::Adjourned;
|
|
break;
|
|
case 4:
|
|
$result = Result::Bye;
|
|
break;
|
|
case 6:
|
|
$result = Result::Draw;
|
|
break;
|
|
case 8:
|
|
$result = Result::DrawAdjourned;
|
|
break;
|
|
case 11:
|
|
$result = Result::Won;
|
|
break;
|
|
case 12:
|
|
$result = Result::WonForfait;
|
|
break;
|
|
case 13:
|
|
$result = Result::WonAdjourned;
|
|
break;
|
|
case 14:
|
|
$result = Result::WonBye;
|
|
break;
|
|
case 0:
|
|
default:
|
|
$result = Result::None;
|
|
break;
|
|
}
|
|
$pairing->setResult(new Result($result));
|
|
$offset += $length;
|
|
|
|
$pairing->setRound($x);
|
|
$offset += 2;
|
|
|
|
$pairing->setBoard(-1);
|
|
if ($x < $this->getBinaryData("CurrentRound")) {
|
|
$this->getTournament()->addPairing($pairing);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->addTiebreaks();
|
|
|
|
$this->getTournament()->pairingsToRounds();
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Converts $data to $type and defaults to $default if given
|
|
*
|
|
* Possible types for $type are:
|
|
* * String (UTF-8 String representation of $data. Default: empty string '')
|
|
* * Hex (Capitalized Hex Value of $data. Default: 00)
|
|
* * Int (Unsigned Integer value of $data Default: 0)
|
|
* * Bool (Boolean representation of $data. Default: false)
|
|
* * Date (Date representation of $data. Default: 1902/01/01)
|
|
*
|
|
* @param string $type
|
|
* @param string $data
|
|
* @param mixed $default
|
|
* @return bool|DateTime|int|string
|
|
*/
|
|
private function readData(string $type, string $data, $default = null)
|
|
{
|
|
switch ($type) {
|
|
case 'String':
|
|
$data = trim($data);
|
|
if ($data == '') {
|
|
return (is_null($default)) ? '' : $default;
|
|
}
|
|
return iconv('windows-1252', 'utf-8', $data);
|
|
break;
|
|
case 'Hex':
|
|
case 'Int':
|
|
case 'Bool':
|
|
case 'Date':
|
|
$hex = implode(unpack("H*", $data));
|
|
$hex = array_reverse(str_split($hex, 2));
|
|
|
|
foreach ($hex as $key => $item) {
|
|
if ($item == "00") {
|
|
$hex[$key] = "";
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
$hex = implode($hex);
|
|
$hex = ($hex == "") ? "00" : $hex;
|
|
if ($type == 'Hex') {
|
|
if ($hex == '00') {
|
|
return (is_null($default)) ? '00' : $default;
|
|
}
|
|
return $hex;
|
|
} elseif ($type == 'Int') {
|
|
if ($hex == '00') {
|
|
return (is_null($default)) ? 0 : $default;
|
|
}
|
|
return hexdec($hex);
|
|
} elseif ($type == 'Date') {
|
|
if ($hex == '00') {
|
|
return (is_null($default)) ? $this->convertUIntToTimestamp(0) : $default;
|
|
}
|
|
return $this->convertUIntToTimestamp(hexdec($hex));
|
|
} elseif ($type == 'Bool') {
|
|
return ($hex == "01") ? true : false;
|
|
}
|
|
break;
|
|
default:
|
|
throw new \InvalidArgumentException("Datatype not known");
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Converts integer value to a date representation
|
|
*
|
|
* @param int $date
|
|
* @return bool|DateTime
|
|
*/
|
|
private function convertUIntToTimestamp(int $date)
|
|
{
|
|
$curyear = date('Y');
|
|
$yearoffset = $curyear - self::PT_PASTOFFSET;
|
|
|
|
// Day
|
|
$day = $date % self::PT_DAYFACTOR;
|
|
if ($day < 1) {
|
|
$day = 1;
|
|
}
|
|
|
|
// Month
|
|
$month = ($date / self::PT_DAYFACTOR) % self::PT_MONTHFACTOR;
|
|
if ($month < 1) {
|
|
$month = 1;
|
|
}
|
|
|
|
// Year
|
|
$year = ($date / self::PT_YEARFACTOR) + $yearoffset;
|
|
|
|
$concat = $month . '/' . $day . '/' . intval($year);
|
|
$format = 'm/d/Y';
|
|
|
|
|
|
return DateTime::createFromFormat($format, $concat);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return $this
|
|
*/
|
|
private function addTiebreaks(): Pairtwo6
|
|
{
|
|
switch ($this->getTournament()->getSystem()) {
|
|
case TournamentSystem::Keizer:
|
|
$firstElement = new Tiebreak(Tiebreak::Keizer);
|
|
break;
|
|
case TournamentSystem::American:
|
|
case TournamentSystem::Closed:
|
|
case TournamentSystem::Swiss:
|
|
$firstElement = new Tiebreak(Tiebreak::Points);
|
|
break;
|
|
}
|
|
$tiebreaks = $this->getTournament()->getTiebreaks();
|
|
array_unshift($tiebreaks, $firstElement);
|
|
$this->getTournament()->setTiebreaks($tiebreaks);
|
|
return $this;
|
|
}
|
|
}
|