Closes 8 and resolved conflict
Conflicts: phpunit.xml
This commit is contained in:
@@ -73,3 +73,35 @@ cd core
|
||||
composer install
|
||||
./t
|
||||
```
|
||||
|
||||
## Contributing
|
||||
Some notes:
|
||||
* Pull requests cannot be accepted that break the continuous integration checks we have in place (like tests, for example).
|
||||
* Our git workflow requires squashing your commits into something that resembles a reasonable story, rebasing them onto master, and pushing instead of merging. We want our commit history to be as clean as possible.
|
||||
|
||||
Workflow should be something like:
|
||||
```bash
|
||||
# Start this flow from master:
|
||||
git checkout master
|
||||
|
||||
# Create a new feature branch, tracking origin/master.
|
||||
git checkout -b feature/my-feature-branch -t origin/master
|
||||
|
||||
# Make some awesome commits and put up a pull request! Don't forget to push your branch to remote before creating the PR. Try something like hub (https://hub.github.com/) if you want to create PRs from the command line.
|
||||
...
|
||||
|
||||
# If necessary, squash your commits to ensure a clean commit history.
|
||||
git rebase -i
|
||||
|
||||
# Edit the last commit message, saying you want to close the PR by adding "closes #[PR number]" to the message.
|
||||
git commit --amend
|
||||
|
||||
# Rebase to ensure you have the latest changes.
|
||||
git pull --rebase
|
||||
|
||||
# Push to remote.
|
||||
git push origin feature/my-feature-branch:master
|
||||
|
||||
# Delete your feature branch.
|
||||
git branch -D feature/my-feature-branch
|
||||
```
|
||||
|
||||
@@ -5,4 +5,12 @@
|
||||
<var name="DB_PASSWD" value="" />
|
||||
<var name="DB_NAME" value="daenerys" />
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Models">
|
||||
<directory>tests/Models</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Other">
|
||||
<file>tests/TimeKeeperTest.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core;
|
||||
|
||||
class DiceBag {
|
||||
public function chance(float $p): bool {
|
||||
$r = $this->uniform(0., 1.);
|
||||
return $r < $p;
|
||||
}
|
||||
|
||||
public function uniform(float $min, float $max): float {
|
||||
return (mt_rand(0, 100) / 100.0) * ($max - $min) + $min;
|
||||
}
|
||||
|
||||
public function normal(float $min, float $max): float {
|
||||
if ($min > $max) {
|
||||
$tmp = $max;
|
||||
$max = $min;
|
||||
$min = $tmp;
|
||||
} else if ($min == $max) {
|
||||
return $min;
|
||||
}
|
||||
|
||||
$mean = ($max - $min) / 2;
|
||||
$r = 0;
|
||||
do {
|
||||
$u1 = mt_rand() / mt_getrandmax();
|
||||
$u2 = mt_rand() / mt_getrandmax();
|
||||
$r = sqrt(-2 * log($u1)) * cos(2 * pi() * $u2) + $mean;
|
||||
} while ($r < $min || $r > $max);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core;
|
||||
|
||||
class TimeKeeper {
|
||||
private $adjustedEpoch;
|
||||
private $theBeginning;
|
||||
|
||||
private $secondsPerMinute = 60;
|
||||
private $secondsPerHour = 60 * 60;
|
||||
private $secondsPerDay = 60 * 60 * 24;
|
||||
private $secondsPerGameYear;
|
||||
private $secondsPerGameDay;
|
||||
private $secondsPerGameHour;
|
||||
private $secondsPerGameMinute;
|
||||
private $secondsPerGameSecond;
|
||||
|
||||
public function __construct(\DateTime $gameEpoch, int $gameOffsetSeconds, int $gameDaysPerDay) {
|
||||
$gameEpochCopy = clone($gameEpoch);
|
||||
$this->adjustedEpoch = $gameEpochCopy->add(
|
||||
$this->interval(0, 0, 0, 0, $gameOffsetSeconds)
|
||||
);
|
||||
$this->theBeginning = new \DateTime("0000-01-01 UTC");
|
||||
|
||||
$this->secondsPerGameDay = (float) $this->secondsPerDay / $gameDaysPerDay;
|
||||
$this->secondsPerGameYear = $this->secondsPerGameDay * 365;
|
||||
$this->secondsPerGameHour = $this->secondsPerGameDay / 24;
|
||||
$this->secondsPerGameMinute = $this->secondsPerGameHour / 60;
|
||||
$this->secondsPerGameSecond = $this->secondsPerGameMinute / 60;
|
||||
}
|
||||
|
||||
public function isNewDay(DateTime $lastInteractionTime): bool {
|
||||
if ($lastInteractionTime == null) {
|
||||
return true;
|
||||
}
|
||||
$t1 = $this->gameTime();
|
||||
$t2 = $this->convertToGameTime($lastInteractionTime);
|
||||
$d1 = $t1->format("Y-m-d");
|
||||
$d2 = $t2->format("Y-m-d");
|
||||
|
||||
return $d1 != $d2;
|
||||
}
|
||||
|
||||
public function gameTime(): \DateTime {
|
||||
return $this->convertToGameTime(new \DateTime());
|
||||
}
|
||||
|
||||
public function convertFromGameTime(
|
||||
\DateTime $time
|
||||
): \DateTime {
|
||||
// Game dates are in the distant past, better not use getTimestamp().
|
||||
$i = $this->theBeginning->diff($time);
|
||||
|
||||
$seconds = 0;
|
||||
$seconds += $i->days * $this->secondsPerGameDay;
|
||||
$seconds += $i->h * $this->secondsPerGameHour;
|
||||
$seconds += $i->i * $this->secondsPerGameMinute;
|
||||
$seconds += $i->s * $this->secondsPerGameSecond;
|
||||
|
||||
$ret = clone($this->adjustedEpoch);
|
||||
return $ret->add($this->interval(0, 0, 0, 0, (int) $seconds));
|
||||
}
|
||||
|
||||
public function convertToGameTime(
|
||||
\DateTime $time
|
||||
): \DateTime {
|
||||
$timeUnix = $time->getTimestamp();
|
||||
$epochUnix = $this->adjustedEpoch->getTimestamp();
|
||||
|
||||
$interval = $timeUnix - $epochUnix;
|
||||
|
||||
$years = (int) ($interval / $this->secondsPerGameYear);
|
||||
$interval -= $years * $this->secondsPerGameYear;
|
||||
|
||||
$days = (int) ($interval / $this->secondsPerGameDay);
|
||||
$interval -= $days * $this->secondsPerGameDay;
|
||||
|
||||
$hours = (int) ($interval / $this->secondsPerGameHour);
|
||||
$interval -= $hours * $this->secondsPerGameHour;
|
||||
|
||||
$minutes = (int) ($interval / $this->secondsPerGameMinute);
|
||||
$interval -= $minutes * $this->secondsPerGameMinute;
|
||||
|
||||
$seconds = (int) ($interval / $this->secondsPerGameSecond);
|
||||
$interval -= $seconds * $this->secondsPerGameSecond;
|
||||
|
||||
$ret = clone($this->theBeginning);
|
||||
return $ret->add(
|
||||
$this->interval($years, $days, $hours, $minutes, $seconds)
|
||||
);
|
||||
}
|
||||
|
||||
private function interval(
|
||||
int $years,
|
||||
int $days,
|
||||
int $hours,
|
||||
int $minutes,
|
||||
int $seconds
|
||||
): \DateInterval {
|
||||
return new \DateInterval(
|
||||
'P'.$years.'Y'.$days.'DT'.$hours.'H'.$minutes.'M'.$seconds.'S'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tests;
|
||||
|
||||
use LotGD\Core\DiceBag;
|
||||
|
||||
/**
|
||||
* @backupGlobals disabled
|
||||
* @backupStaticAttributes disabled
|
||||
*/
|
||||
class DiceBagTests extends \PHPUnit_Framework_TestCase {
|
||||
public function testUniform() {
|
||||
$db = new DiceBag();
|
||||
$value = $db->uniform(0., 1.);
|
||||
$this->assertGreaterThan(0, $value);
|
||||
$this->assertLessThan(1, $value);
|
||||
}
|
||||
|
||||
public function testNormal() {
|
||||
$db = new DiceBag();
|
||||
$value = $db->normal(0., 1.);
|
||||
$this->assertGreaterThan(0, $value);
|
||||
$this->assertLessThan(1, $value);
|
||||
|
||||
$value = $db->normal(1., 0.);
|
||||
$this->assertGreaterThan(0, $value);
|
||||
$this->assertLessThan(1, $value);
|
||||
|
||||
$this->assertEquals(0, $db->normal(0., 0.));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LotGD\Core\Tests;
|
||||
|
||||
use LotGD\Core\TimeKeeper;
|
||||
|
||||
/**
|
||||
* @backupGlobals disabled
|
||||
* @backupStaticAttributes disabled
|
||||
*/
|
||||
class TimeKeeperTests extends \PHPUnit_Framework_TestCase {
|
||||
private $gameEpoch;
|
||||
private $gameOffsetSeconds;
|
||||
private $gameDaysPerDay;
|
||||
|
||||
public function setUp() {
|
||||
$this->gameEpoch = new \DateTime('2015-07-27 00:00:00 PDT');;
|
||||
$this->gameOffsetSeconds = 0;
|
||||
$this->gameDaysPerDay = 2;
|
||||
}
|
||||
|
||||
public function testConvertToBasicConversion() {
|
||||
$this->gameDaysPerDay = 1;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$date = new \DateTime('2015-07-27 23:59:59 PDT');
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-01 23:59:59', $converted->format('Y-m-d H:i:s'));
|
||||
|
||||
$date = new \DateTime('2015-07-27 12:00:00 PDT');
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-01 12:00:00', $converted->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testConvertToRespectsGameDaysPerDayUpperBound() {
|
||||
$date = new \DateTime('2015-07-27 05:59:59 PDT');
|
||||
|
||||
$this->gameDaysPerDay = 4;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-01', $converted->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testConvertToRespectsGameDaysPerDayNextDay() {
|
||||
$date = new \DateTime('2015-07-27 06:00:00 PDT');
|
||||
|
||||
$this->gameDaysPerDay = 4;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-02', $converted->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testConvertToRespectsGameDaysPerDayNextDayUpperBound() {
|
||||
$date = new \DateTime('2015-07-27 11:59:59 PDT');
|
||||
|
||||
$this->gameDaysPerDay = 4;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-02', $converted->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testDetectsNewDay() {
|
||||
}
|
||||
|
||||
public function testConvertToRespectsGameOffset() {
|
||||
$date = new \DateTime('2015-07-27 01:01:15 PDT');
|
||||
|
||||
$this->gameOffsetSeconds = 60*60;
|
||||
$this->gameDaysPerDay = 1;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-01 00:01:15', $converted->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testConvertToRespectsGameOffsetUpperBound() {
|
||||
$date = new \DateTime('2015-07-28 00:59:59 PDT');
|
||||
|
||||
$this->gameOffsetSeconds = 60*60;
|
||||
$this->gameDaysPerDay = 1;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-01 23:59:59', $converted->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testConvertToRespectsGameOffsetNextDay() {
|
||||
$date = new \DateTime('2015-07-28 01:00:00 PDT');
|
||||
|
||||
$this->gameOffsetSeconds = 60*60;
|
||||
$this->gameDaysPerDay = 1;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-02', $converted->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testConvertToRespectsGameOffsetNextDayUpperBound() {
|
||||
$date = new \DateTime('2015-07-29 00:59:59 PDT');
|
||||
|
||||
$this->gameOffsetSeconds = 60*60;
|
||||
$this->gameDaysPerDay = 1;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertToGameTime($date);
|
||||
$this->assertEquals('0000-01-02', $converted->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testConvertFromBasicConversion() {
|
||||
$date = new \DateTime('0000-01-02 00:00:00 UTC');
|
||||
|
||||
$this->gameDaysPerDay = 1;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertFromGameTime($date);
|
||||
$this->assertEquals("2015-07-28", $converted->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testConvertFromRespectsGameOffsetNextDay() {
|
||||
$epoch = new \DateTime('2015-07-27 00:00:00 PDT');
|
||||
$date = new \DateTime('0000-01-02 23:59:59 UTC');
|
||||
|
||||
$this->gameEpoch = $epoch;
|
||||
$this->gameOffsetSeconds = 60*60;
|
||||
$this->gameDaysPerDay = 1;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertFromGameTime($date);
|
||||
$this->assertEquals("2015-07-29 00:59:59", $converted->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testConvertFromRespectsGameDaysPerDayNextDay() {
|
||||
$epoch = new \DateTime('2015-07-27 00:00:00 PDT');
|
||||
$date = new \DateTime('0000-01-02 23:59:59 UTC');
|
||||
|
||||
$this->gameEpoch = $epoch;
|
||||
$this->gameDaysPerDay = 4;
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
|
||||
$converted = $keeper->convertFromGameTime($date);
|
||||
$this->assertEquals("2015-07-27 11:59:59", $converted->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testGameTimeSanity() {
|
||||
$keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay);
|
||||
$this->assertNotNull($keeper->gameTime());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user