mirror of
https://github.com/furyfire/trueskill.git
synced 2025-06-27 15:21:31 +00:00
Compare commits
8 Commits
55656b7889
...
master
Author | SHA1 | Date | |
---|---|---|---|
1d06fa0b0a | |||
a097fa7f71 | |||
ad9d7f94de | |||
1725979b1c | |||
ac7e3f5c2d | |||
adc587ac0d | |||
d729caac1f | |||
bd9fccb87b |
@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phive xmlns="https://phar.io/phive">
|
||||
<phar name="phpmd" version="^2.15.0" installed="2.15.0" location="./tools/phpmd" copy="false"/>
|
||||
<phar name="overtrue/phplint" version="^9.6.2" installed="9.6.2" location="./tools/phplint" copy="false"/>
|
||||
<phar name="phpstan" version="^2.1.12" installed="2.1.12" location="./tools/phpstan" copy="false"/>
|
||||
<phar name="psalm" version="^7.0.0-beta6" installed="7.0.0-beta6" location="./tools/psalm" copy="false"/>
|
||||
<phar name="phpcs" version="^3.12.2" installed="3.12.2" location="./tools/phpcs" copy="false"/>
|
||||
<phar name="phpcbf" version="^3.12.2" installed="3.12.2" location="./tools/phpcbf" copy="false"/>
|
||||
<phar name="phpdocumentor" version="^3.7.1" installed="3.7.1" location="./tools/phpdocumentor" copy="false"/>
|
||||
<phar name="phpstan" version="^2.1.12" installed="2.1.17" location="./tools/phpstan" copy="false"/>
|
||||
<phar name="psalm" version="^7.0.0-beta6" installed="7.0.0-beta9" location="./tools/psalm" copy="false"/>
|
||||
<phar name="phpcs" version="^3.12.2" installed="3.13.2" location="./tools/phpcs" copy="false"/>
|
||||
<phar name="phpcbf" version="^3.12.2" installed="3.13.2" location="./tools/phpcbf" copy="false"/>
|
||||
<phar name="phpdocumentor" version="^3.7.1" installed="3.8.0" location="./tools/phpdocumentor" copy="false"/>
|
||||
<phar name="phpbench" version="^1.4.1" installed="1.4.1" location="./tools/phpbench" copy="false"/>
|
||||
<phar name="infection" version="^0.29.14" installed="0.29.14" location="./tools/infection" copy="false"/>
|
||||
<phar name="phpunit" version="^12.1.3" installed="12.2.3" location="./tools/phpunit" copy="false"/>
|
||||
</phive>
|
||||
|
32
.phpcs.xml
32
.phpcs.xml
@ -6,6 +6,11 @@
|
||||
<file>tests/</file>
|
||||
<file>benchmark/</file>
|
||||
|
||||
<arg name="basepath" value="."/>
|
||||
<arg name="colors"/>
|
||||
<arg name="parallel" value="8"/>
|
||||
<arg name="report" value="emacs"/>
|
||||
<arg value="p"/>
|
||||
|
||||
<rule ref="PSR1">
|
||||
<exclude name="Generic.Files.LineLength"/>
|
||||
@ -18,23 +23,19 @@
|
||||
<exclude name="Generic.Files.LowercasedFilename.NotFound"/>
|
||||
<exclude name="Generic.PHP.ClosingPHPTag.NotFound"/>
|
||||
<exclude name="Generic.Files.EndFileNoNewline.Found"/>
|
||||
<exclude name="Generic.Files.EndFileNoNewline.Found"/>
|
||||
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found"/>
|
||||
<exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine"/>
|
||||
<exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine"/>
|
||||
<exclude name="Generic.PHP.LowerCaseConstant.Found"/>
|
||||
<exclude name="Generic.Formatting.SpaceAfterCast"/>
|
||||
<exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning"/>
|
||||
<exclude name="Generic.Commenting.DocComment.MissingShort"/>
|
||||
<exclude name="Generic.NamingConventions.AbstractClassNamePrefix.Missing"/>
|
||||
<exclude name="Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed"/>
|
||||
<exclude name="Generic.NamingConventions.InterfaceNameSuffix.Missing"/>
|
||||
<exclude name="Generic.Commenting.Todo.TaskFound"/>
|
||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUse"/>
|
||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed"/>
|
||||
<exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed"/>
|
||||
<exclude name="Generic.Formatting.SpaceBeforeCast.NoSpace"/>
|
||||
<exclude name="Generic.CodeAnalysis.UselessOverridingMethod.Found"/>
|
||||
|
||||
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace"/>
|
||||
</rule>
|
||||
|
||||
@ -50,4 +51,25 @@
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.Formatting.SpaceAfterCast">
|
||||
<properties>
|
||||
<property name="spacing" value="0"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- Do not allow unreachable code. -->
|
||||
<rule ref="Squiz.PHP.NonExecutableCode"/>
|
||||
|
||||
<!-- Do not allow ambiguous conditions. -->
|
||||
<rule ref="Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence"/>
|
||||
|
||||
<!-- The testing bootstrap file uses string concats to stop IDEs seeing the class aliases -->
|
||||
<rule ref="Generic.Strings.UnnecessaryStringConcat" />
|
||||
|
||||
<!-- This test file specifically *needs* Windows line endings for testing purposes. -->
|
||||
<rule ref="Generic.Files.LineEndings.InvalidEOLChar" />
|
||||
|
||||
<!-- Avoid false positive with this sniff detecting itself -->
|
||||
<rule ref="Generic.Commenting.Todo"/>
|
||||
</ruleset>
|
12
.phplint.yml
12
.phplint.yml
@ -1,12 +0,0 @@
|
||||
path:
|
||||
- src/
|
||||
- tests/
|
||||
- benchmark/
|
||||
jobs: 10
|
||||
extensions:
|
||||
- php
|
||||
exclude:
|
||||
- vendor
|
||||
warning: true
|
||||
memory-limit: -1
|
||||
log-junit: "output/lint.xml"
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"php.version": "8.4"
|
||||
}
|
4317
CodeStandard.md
Normal file
4317
CodeStandard.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,13 @@
|
||||
{
|
||||
"name": "dnw/php-trueskill",
|
||||
"description": "Trueskill implementation by Moserware updated for PHP 8.4",
|
||||
"keywords": ["trueskill", "matchmaking", "ranking", "skill", "elo"],
|
||||
"keywords": [
|
||||
"trueskill",
|
||||
"matchmaking",
|
||||
"ranking",
|
||||
"skill",
|
||||
"elo"
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.4"
|
||||
},
|
||||
@ -22,34 +28,35 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit",
|
||||
"document": "tools/phpDocumentor",
|
||||
"benchmark": "tools/phpbench run --report=default --output=build-artifact",
|
||||
"metrics": "vendor/bin/phpmetrics --config=phpmetrics.yml",
|
||||
"test": "tools/phpunit",
|
||||
"document": "tools/phpdocumentor",
|
||||
"benchmark": "tools/phpbench run --report=default --output=build-artifact",
|
||||
"metrics": "phpmetrics --config=phpmetrics.yml",
|
||||
"lint": [
|
||||
"tools/phplint",
|
||||
"tools/phpcs",
|
||||
"tools/phpcbf src/ tests/ benchmark/ examples/",
|
||||
"tools/phpmd src/,tests/,benchmark/,examples/ text phpmd.ruleset.xml"
|
||||
"tools/phpcbf",
|
||||
"tools/phpcs",
|
||||
"tools/phpmd src/,tests/,benchmark/,examples/ text phpmd.ruleset.xml"
|
||||
],
|
||||
"analyze": [
|
||||
"@analyze-phpstan",
|
||||
"@analyze-psalm",
|
||||
"@analyze-rector"
|
||||
"@analyze-phpstan",
|
||||
"@analyze-psalm",
|
||||
"@analyze-rector"
|
||||
],
|
||||
"analyze-phpstan":"tools/phpstan analyze --error-format=raw",
|
||||
"analyze-psalm": "tools/psalm --no-cache --show-info=true",
|
||||
"analyze-rector": "vendor/bin/rector --dry-run",
|
||||
"analyze-phpstan": "tools/phpstan analyze --error-format=raw",
|
||||
"analyze-psalm": "tools/psalm --show-info=true",
|
||||
"analyze-rector": "rector --dry-run",
|
||||
"html": [
|
||||
"pandoc -s README.md -o output/README.html",
|
||||
"pandoc -s docs/index.rst -o output/index.html"
|
||||
"pandoc -s docs/index.rst -o output/index.html",
|
||||
"tools/phpcs --generator=MarkDown | pandoc -o output/CodeStandard.html --metadata title=\"Code Standard\""
|
||||
],
|
||||
"all": [
|
||||
"@test",
|
||||
"@lint",
|
||||
"@analyze",
|
||||
"@document",
|
||||
"@metrics",
|
||||
"@html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
104
composer.lock
generated
104
composer.lock
generated
@ -160,16 +160,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.4.0",
|
||||
"version": "v5.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "447a020a1f875a434d62f2a401f53b82a396e494"
|
||||
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
|
||||
"reference": "447a020a1f875a434d62f2a401f53b82a396e494",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
|
||||
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -212,26 +212,26 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
|
||||
},
|
||||
"time": "2024-12-30T11:07:19+00:00"
|
||||
"time": "2025-05-31T08:24:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "openmetrics-php/exposition-text",
|
||||
"version": "v0.4.1",
|
||||
"version": "v0.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openmetrics-php/exposition-text.git",
|
||||
"reference": "fcfca38f693e168f4520bbd359d91528bbb9a8e8"
|
||||
"reference": "4f65004f93e53eac4b9668879b92d3c200a851ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/openmetrics-php/exposition-text/zipball/fcfca38f693e168f4520bbd359d91528bbb9a8e8",
|
||||
"reference": "fcfca38f693e168f4520bbd359d91528bbb9a8e8",
|
||||
"url": "https://api.github.com/repos/openmetrics-php/exposition-text/zipball/4f65004f93e53eac4b9668879b92d3c200a851ba",
|
||||
"reference": "4f65004f93e53eac4b9668879b92d3c200a851ba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
"php": "^7.2 || ^8.0 || ^8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-xdebug": "*"
|
||||
@ -255,9 +255,9 @@
|
||||
"description": "Implementation of the text exposition format of OpenMetrics",
|
||||
"support": {
|
||||
"issues": "https://github.com/openmetrics-php/exposition-text/issues",
|
||||
"source": "https://github.com/openmetrics-php/exposition-text/tree/v0.4.1"
|
||||
"source": "https://github.com/openmetrics-php/exposition-text/tree/v0.4.2"
|
||||
},
|
||||
"time": "2024-07-16T12:47:30+00:00"
|
||||
"time": "2025-06-04T14:59:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -456,16 +456,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.12.25",
|
||||
"version": "1.12.27",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "e310849a19e02b8bfcbb63147f495d8f872dd96f"
|
||||
"reference": "3a6e423c076ab39dfedc307e2ac627ef579db162"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e310849a19e02b8bfcbb63147f495d8f872dd96f",
|
||||
"reference": "e310849a19e02b8bfcbb63147f495d8f872dd96f",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3a6e423c076ab39dfedc307e2ac627ef579db162",
|
||||
"reference": "3a6e423c076ab39dfedc307e2ac627ef579db162",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -510,20 +510,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-27T12:20:45+00:00"
|
||||
"time": "2025-05-21T20:51:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "11.0.9",
|
||||
"version": "11.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7"
|
||||
"reference": "1a800a7446add2d79cc6b3c01c45381810367d76"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7",
|
||||
"reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76",
|
||||
"reference": "1a800a7446add2d79cc6b3c01c45381810367d76",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -580,15 +580,27 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-25T13:26:39+00:00"
|
||||
"time": "2025-06-18T08:56:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -837,16 +849,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "11.5.18",
|
||||
"version": "11.5.24",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "fc3e887c7f3f9917e1bf61e523413d753db00a17"
|
||||
"reference": "6b07ab1047155cf38f82dd691787a277782271dd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc3e887c7f3f9917e1bf61e523413d753db00a17",
|
||||
"reference": "fc3e887c7f3f9917e1bf61e523413d753db00a17",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6b07ab1047155cf38f82dd691787a277782271dd",
|
||||
"reference": "6b07ab1047155cf38f82dd691787a277782271dd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -856,11 +868,11 @@
|
||||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"myclabs/deep-copy": "^1.13.0",
|
||||
"myclabs/deep-copy": "^1.13.1",
|
||||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=8.2",
|
||||
"phpunit/php-code-coverage": "^11.0.9",
|
||||
"phpunit/php-code-coverage": "^11.0.10",
|
||||
"phpunit/php-file-iterator": "^5.1.0",
|
||||
"phpunit/php-invoker": "^5.0.1",
|
||||
"phpunit/php-text-template": "^4.0.1",
|
||||
@ -869,7 +881,7 @@
|
||||
"sebastian/code-unit": "^3.0.3",
|
||||
"sebastian/comparator": "^6.3.1",
|
||||
"sebastian/diff": "^6.0.2",
|
||||
"sebastian/environment": "^7.2.0",
|
||||
"sebastian/environment": "^7.2.1",
|
||||
"sebastian/exporter": "^6.3.0",
|
||||
"sebastian/global-state": "^7.0.2",
|
||||
"sebastian/object-enumerator": "^6.0.1",
|
||||
@ -918,7 +930,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.18"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.24"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -942,7 +954,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-22T06:09:49+00:00"
|
||||
"time": "2025-06-20T11:31:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rector/rector",
|
||||
@ -1380,23 +1392,23 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5"
|
||||
"reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5",
|
||||
"reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4",
|
||||
"reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^11.0"
|
||||
"phpunit/phpunit": "^11.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-posix": "*"
|
||||
@ -1432,15 +1444,27 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
||||
"security": "https://github.com/sebastianbergmann/environment/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/7.2.0"
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/7.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-03T04:54:44+00:00"
|
||||
"time": "2025-05-21T11:55:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
|
@ -33,6 +33,7 @@ Links
|
||||
* `Test report <test/index.html>`_
|
||||
* `Mutation testing <mutation/infection.html>`_
|
||||
* `Code metrics <metrics/index.html>`_
|
||||
* `Code Standard <CodeStandard.html>`_
|
||||
|
||||
|
||||
Standard Tools
|
||||
|
@ -16,5 +16,5 @@
|
||||
</source>
|
||||
</api>
|
||||
</version>
|
||||
<!--setting name="graphs.enabled" value="true"/-->
|
||||
<setting name="graphs.enabled" value="true"/>
|
||||
</phpdocumentor>
|
@ -24,7 +24,7 @@ abstract class FactorGraphLayer
|
||||
*/
|
||||
private array $inputVariablesGroups = [];
|
||||
|
||||
protected function __construct(private readonly TrueSkillFactorGraph $parentFactorGraph)
|
||||
public function __construct(private readonly TrueSkillFactorGraph $parentFactorGraph)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,12 @@ namespace DNW\Skills;
|
||||
final class HashMap
|
||||
{
|
||||
/**
|
||||
* @var mixed[] $hashToValue
|
||||
* @var mixed[] $hashToValue Store the hash to value mapping.
|
||||
*/
|
||||
private array $hashToValue = [];
|
||||
|
||||
/**
|
||||
* @var mixed[] $hashToKey
|
||||
* @var mixed[] $hashToKey Store the hash to original key mapping.
|
||||
*/
|
||||
private array $hashToKey = [];
|
||||
|
||||
|
@ -27,7 +27,7 @@ final class BasicMath
|
||||
/**
|
||||
* Sums the items in $itemsToSum
|
||||
*
|
||||
* @param mixed[] $itemsToSum The items to sum,
|
||||
* @param mixed[] $itemsToSum The items to sum.
|
||||
* @param \Closure $callback The function to apply to each array element before summing.
|
||||
*
|
||||
* @return float The sum.
|
||||
|
@ -34,8 +34,9 @@ final class GaussianDistribution
|
||||
*/
|
||||
private const float M_LOG_SQRT_2_PI = 0.9189385332046727417803297364056176398613974736377834128171515404;
|
||||
|
||||
// precision and precisionMean are used because they make multiplying and dividing simpler
|
||||
// (see the accompanying math paper for more details)
|
||||
/**
|
||||
* Precision and precisionMean are used because they make multiplying and dividing simpler.
|
||||
*/
|
||||
private float $precision = 1.0;
|
||||
|
||||
private float $precisionMean = 0.0;
|
||||
|
@ -79,7 +79,7 @@ class Matrix
|
||||
}
|
||||
}
|
||||
|
||||
public function getValue(int $row, int $col): float|int
|
||||
public function getValue(int $row, int $col): float
|
||||
{
|
||||
$this->checkRowCol($row, $col);
|
||||
return $this->matrixRowData[$row][$col];
|
||||
@ -130,10 +130,10 @@ class Matrix
|
||||
// | a b |
|
||||
// | c d |
|
||||
// The determinant is ad - bc
|
||||
$a = (float)$this->getValue(0, 0);
|
||||
$b = (float)$this->getValue(0, 1);
|
||||
$c = (float)$this->getValue(1, 0);
|
||||
$d = (float)$this->getValue(1, 1);
|
||||
$a = $this->getValue(0, 0);
|
||||
$b = $this->getValue(0, 1);
|
||||
$c = $this->getValue(1, 0);
|
||||
$d = $this->getValue(1, 1);
|
||||
|
||||
return $a * $d - $b * $c;
|
||||
}
|
||||
@ -148,7 +148,7 @@ class Matrix
|
||||
|
||||
// I expand along the first row
|
||||
for ($currentColumn = 0; $currentColumn < $this->columnCount; ++$currentColumn) {
|
||||
$firstRowColValue = (float)$this->getValue(0, $currentColumn);
|
||||
$firstRowColValue = $this->getValue(0, $currentColumn);
|
||||
$cofactor = $this->getCofactor(0, $currentColumn);
|
||||
$itemToAdd = $firstRowColValue * $cofactor;
|
||||
$result += $itemToAdd;
|
||||
@ -201,7 +201,7 @@ class Matrix
|
||||
public function getInverse(): Matrix|SquareMatrix
|
||||
{
|
||||
if (($this->rowCount == 1) && ($this->columnCount == 1)) {
|
||||
return new SquareMatrix(1.0 / (float)$this->getValue(0, 0));
|
||||
return new SquareMatrix(1.0 / $this->getValue(0, 0));
|
||||
}
|
||||
|
||||
// Take the simple approach:
|
||||
@ -212,7 +212,7 @@ class Matrix
|
||||
return self::scalarMultiply($determinantInverse, $adjugate);
|
||||
}
|
||||
|
||||
public static function scalarMultiply(float|int $scalarValue, Matrix $matrix): Matrix
|
||||
public static function scalarMultiply(float $scalarValue, Matrix $matrix): Matrix
|
||||
{
|
||||
$rows = $matrix->getRowCount();
|
||||
$columns = $matrix->getColumnCount();
|
||||
@ -240,9 +240,9 @@ class Matrix
|
||||
for ($currentRow = 0; $currentRow < $left->getRowCount(); ++$currentRow) {
|
||||
for ($currentColumn = 0; $currentColumn < $right->getColumnCount(); ++$currentColumn) {
|
||||
$resultMatrix[$currentRow][$currentColumn] =
|
||||
(float)$left->getValue($currentRow, $currentColumn)
|
||||
$left->getValue($currentRow, $currentColumn)
|
||||
+
|
||||
(float)$right->getValue($currentRow, $currentColumn);
|
||||
$right->getValue($currentRow, $currentColumn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,11 +265,11 @@ class Matrix
|
||||
|
||||
for ($currentRow = 0; $currentRow < $resultRows; ++$currentRow) {
|
||||
for ($currentColumn = 0; $currentColumn < $resultColumns; ++$currentColumn) {
|
||||
$productValue = 0;
|
||||
$productValue = 0.0;
|
||||
|
||||
for ($vectorIndex = 0; $vectorIndex < $left->getColumnCount(); ++$vectorIndex) {
|
||||
$leftValue = (float)$left->getValue($currentRow, $vectorIndex);
|
||||
$rightValue = (float)$right->getValue($vectorIndex, $currentColumn);
|
||||
$leftValue = $left->getValue($currentRow, $vectorIndex);
|
||||
$rightValue = $right->getValue($vectorIndex, $currentColumn);
|
||||
$vectorIndexProduct = $leftValue * $rightValue;
|
||||
$productValue += $vectorIndexProduct;
|
||||
}
|
||||
@ -339,8 +339,8 @@ class Matrix
|
||||
for ($currentColumn = 0; $currentColumn < $this->columnCount; ++$currentColumn) {
|
||||
$delta =
|
||||
abs(
|
||||
(float)$this->getValue($currentRow, $currentColumn) -
|
||||
(float)$otherMatrix->getValue($currentRow, $currentColumn)
|
||||
$this->getValue($currentRow, $currentColumn) -
|
||||
$otherMatrix->getValue($currentRow, $currentColumn)
|
||||
);
|
||||
|
||||
if ($delta > self::ERROR_TOLERANCE) {
|
||||
|
@ -13,14 +13,20 @@ final readonly class Player implements ISupportPartialPlay, ISupportPartialUpdat
|
||||
|
||||
private const float DEFAULT_PARTIAL_UPDATE_PERCENTAGE = 1.0;
|
||||
|
||||
/**
|
||||
* @var float The weight percentage to give this player when calculating a new rank.
|
||||
*/
|
||||
private float $PartialPlayPct;
|
||||
|
||||
/**
|
||||
* @var float Indicated how much of a skill update a player should receive where 0 represents no update and 1.0 represents 100% of the update.
|
||||
*/
|
||||
private float $PartialUpdatePct;
|
||||
|
||||
/**
|
||||
* Constructs a player.
|
||||
*
|
||||
* @param string|int $Id The identifier for the player, such as a name.
|
||||
* @param string|int $Id The identifier for the player, such as a name.
|
||||
* @param float $partialPlayPct The weight percentage to give this player when calculating a new rank.
|
||||
* @param float $partialUpdatePct Indicated how much of a skill update a player should receive where 0 represents no update and 1.0 represents 100% of the update.
|
||||
*/
|
||||
|
@ -6,6 +6,9 @@ namespace DNW\Skills;
|
||||
|
||||
class RatingContainer
|
||||
{
|
||||
/**
|
||||
* Link Player to a Rating using a hash map.
|
||||
*/
|
||||
private readonly HashMap $playerToRating;
|
||||
|
||||
public function __construct()
|
||||
|
@ -192,7 +192,7 @@ final class FactorGraphTrueSkillCalculator extends SkillCalculator
|
||||
$nextTeam = $teamAssignmentsList[$i + 1];
|
||||
foreach ($nextTeam->getAllPlayers() as $nextTeamPlayer) {
|
||||
// Add a -1 * playing time to represent the difference
|
||||
$playerAssignments[$currentColumn][] = -1 * PartialPlay::getPartialPlayPercentage($nextTeamPlayer);
|
||||
$playerAssignments[$currentColumn][] = -1.0 * PartialPlay::getPartialPlayPercentage($nextTeamPlayer);
|
||||
--$rowsRemaining;
|
||||
}
|
||||
|
||||
|
@ -72,12 +72,12 @@ final class GaussianWeightedSumFactor extends GaussianFactor
|
||||
|
||||
$weightsLength = $variableWeightsLength + 1;
|
||||
for ($weightsIndex = 1; $weightsIndex < $weightsLength; ++$weightsIndex) {
|
||||
$currentWeights = \array_fill(0, $variableWeightsLength, 0);
|
||||
$currentWeights = \array_fill(0, $variableWeightsLength, 0.0);
|
||||
|
||||
$variableIndices = \array_fill(0, $variableWeightsLength + 1, 0);
|
||||
$variableIndices = \array_fill(0, $variableWeightsLength + 1, 0.0);
|
||||
$variableIndices[0] = $weightsIndex;
|
||||
|
||||
$currentWeightsSquared = \array_fill(0, $variableWeightsLength, 0);
|
||||
$currentWeightsSquared = \array_fill(0, $variableWeightsLength, 0.0);
|
||||
|
||||
// keep a single variable to keep track of where we are in the array.
|
||||
// This is helpful since we skip over one of the spots
|
||||
@ -90,9 +90,9 @@ final class GaussianWeightedSumFactor extends GaussianFactor
|
||||
|
||||
$currentWeight = (-$variableWeights[$currentWeightSourceIndex] / $variableWeights[$weightsIndex - 1]);
|
||||
|
||||
if ($variableWeights[$weightsIndex - 1] == 0) {
|
||||
if ($variableWeights[$weightsIndex - 1] == 0.0) {
|
||||
// HACK: Getting around division by zero
|
||||
$currentWeight = 0;
|
||||
$currentWeight = 0.0;
|
||||
}
|
||||
|
||||
$currentWeights[$currentDestinationWeightIndex] = $currentWeight;
|
||||
@ -112,7 +112,7 @@ final class GaussianWeightedSumFactor extends GaussianFactor
|
||||
|
||||
$currentWeights[$currentDestinationWeightIndex] = $finalWeight;
|
||||
$currentWeightsSquared[$currentDestinationWeightIndex] = BasicMath::square($finalWeight);
|
||||
$variableIndices[count($variableWeights)] = 0;
|
||||
$variableIndices[count($variableWeights)] = 0.0;
|
||||
$this->varIndexOrdersForWeights[] = $variableIndices;
|
||||
|
||||
$this->weights[$weightsIndex] = $currentWeights;
|
||||
|
@ -29,11 +29,7 @@ final class TeamPerformancesToTeamPerformanceDifferencesLayer extends TrueSkillF
|
||||
}
|
||||
}
|
||||
|
||||
private function createTeamPerformanceToDifferenceFactor(
|
||||
Variable $strongerTeam,
|
||||
Variable $weakerTeam,
|
||||
Variable $output
|
||||
): GaussianWeightedSumFactor
|
||||
private function createTeamPerformanceToDifferenceFactor(Variable $strongerTeam, Variable $weakerTeam, Variable $output): GaussianWeightedSumFactor
|
||||
{
|
||||
$teams = [$strongerTeam, $weakerTeam];
|
||||
$weights = [1.0, -1.0];
|
||||
|
@ -9,8 +9,4 @@ use DNW\Skills\TrueSkill\TrueSkillFactorGraph;
|
||||
|
||||
abstract class TrueSkillFactorGraphLayer extends FactorGraphLayer
|
||||
{
|
||||
public function __construct(TrueSkillFactorGraph $parentGraph)
|
||||
{
|
||||
parent::__construct($parentGraph);
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ final class TrueSkillFactorGraph extends FactorGraph
|
||||
private readonly PlayerPriorValuesToSkillsLayer $priorLayer;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param GameInfo $gameInfo Parameters for the game.
|
||||
* @param Team[] $teams A mapping of team players and their ratings.
|
||||
* @param int[] $teamRanks The ranks of the teams where 1 is first place. For a tie, repeat the number (e.g. 1, 2, 2).
|
||||
|
@ -32,11 +32,7 @@ final class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
#[\Override]
|
||||
public function calculateNewRatings(
|
||||
GameInfo $gameInfo,
|
||||
array $teams,
|
||||
array $teamRanks
|
||||
): RatingContainer
|
||||
public function calculateNewRatings(GameInfo $gameInfo, array $teams, array $teamRanks): RatingContainer
|
||||
{
|
||||
// Basic argument checking
|
||||
$this->validateTeamCountAndPlayersCountPerTeam($teams);
|
||||
@ -118,11 +114,11 @@ final class TwoPlayerTrueSkillCalculator extends SkillCalculator
|
||||
// non-draw case
|
||||
$v = TruncatedGaussianCorrectionFunctions::vExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||
$w = TruncatedGaussianCorrectionFunctions::wExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||
$rankMultiplier = $comparison->value;
|
||||
$rankMultiplier = (float)$comparison->value;
|
||||
} else {
|
||||
$v = TruncatedGaussianCorrectionFunctions::vWithinMarginScaled($meanDelta, $drawMargin, $c);
|
||||
$w = TruncatedGaussianCorrectionFunctions::wWithinMarginScaled($meanDelta, $drawMargin, $c);
|
||||
$rankMultiplier = 1;
|
||||
$rankMultiplier = 1.0;
|
||||
}
|
||||
|
||||
$meanMultiplier = (BasicMath::square($selfRating->getStandardDeviation()) + BasicMath::square($gameInfo->getDynamicsFactor())) / $c;
|
||||
|
@ -64,13 +64,7 @@ final class TwoTeamTrueSkillCalculator extends SkillCalculator
|
||||
return $results;
|
||||
}
|
||||
|
||||
private static function updatePlayerRatings(
|
||||
GameInfo $gameInfo,
|
||||
RatingContainer $newPlayerRatings,
|
||||
Team $selfTeam,
|
||||
Team $otherTeam,
|
||||
PairwiseComparison $selfToOtherTeamComparison
|
||||
): void
|
||||
private static function updatePlayerRatings(GameInfo $gameInfo, RatingContainer $newPlayerRatings, Team $selfTeam, Team $otherTeam, PairwiseComparison $selfToOtherTeamComparison): void
|
||||
{
|
||||
$drawMargin = DrawMargin::getDrawMarginFromDrawProbability(
|
||||
$gameInfo->getDrawProbability(),
|
||||
@ -94,7 +88,7 @@ final class TwoTeamTrueSkillCalculator extends SkillCalculator
|
||||
+
|
||||
BasicMath::sum($otherTeam->getAllRatings(), $varianceGetter)
|
||||
+
|
||||
$totalPlayers * $betaSquared
|
||||
(float)$totalPlayers * $betaSquared
|
||||
);
|
||||
|
||||
$winningMean = $selfMeanSum;
|
||||
@ -117,7 +111,7 @@ final class TwoTeamTrueSkillCalculator extends SkillCalculator
|
||||
// non-draw case
|
||||
$v = TruncatedGaussianCorrectionFunctions::vExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||
$w = TruncatedGaussianCorrectionFunctions::wExceedsMarginScaled($meanDelta, $drawMargin, $c);
|
||||
$rankMultiplier = $selfToOtherTeamComparison->value;
|
||||
$rankMultiplier = (float)$selfToOtherTeamComparison->value;
|
||||
} else {
|
||||
// assume draw
|
||||
$v = TruncatedGaussianCorrectionFunctions::vWithinMarginScaled($meanDelta, $drawMargin, $c);
|
||||
|
@ -10,15 +10,8 @@ use DNW\Skills\Player;
|
||||
use DNW\Skills\Team;
|
||||
use DNW\Skills\TrueSkill\FactorGraphTrueSkillCalculator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||
use PHPUnit\Framework\Attributes\UsesClass;
|
||||
|
||||
#[CoversClass(FactorGraphTrueSkillCalculator::class)]
|
||||
#[UsesClass(\DNW\Skills\Numerics\Range::class)]
|
||||
#[UsesClass(\DNW\Skills\PlayersRange::class)]
|
||||
#[UsesClass(\DNW\Skills\SkillCalculator::class)]
|
||||
#[UsesClass(\DNW\Skills\TeamsRange::class)]
|
||||
final class FactorGraphTrueSkillCalculatorTest extends TestCase
|
||||
{
|
||||
#[CoversNothing]
|
||||
@ -75,6 +68,7 @@ final class FactorGraphTrueSkillCalculatorTest extends TestCase
|
||||
TrueSkillCalculatorTests::testPartialPlayScenarios($this, $calculator);
|
||||
}
|
||||
|
||||
#[CoversNothing]
|
||||
public function testMethodisSupported(): void
|
||||
{
|
||||
$calculator = new FactorGraphTrueSkillCalculator();
|
||||
|
@ -811,15 +811,15 @@ final class TrueSkillCalculatorTests
|
||||
|
||||
private static function sixteenTeamsOfOneNotDrawn(TestCase $testClass, SkillCalculator $calculator): void
|
||||
{
|
||||
$player1 = new Player(1);
|
||||
$player2 = new Player(2);
|
||||
$player3 = new Player(3);
|
||||
$player4 = new Player(4);
|
||||
$player5 = new Player(5);
|
||||
$player6 = new Player(6);
|
||||
$player7 = new Player(7);
|
||||
$player8 = new Player(8);
|
||||
$player9 = new Player(9);
|
||||
$player1 = new Player(1);
|
||||
$player2 = new Player(2);
|
||||
$player3 = new Player(3);
|
||||
$player4 = new Player(4);
|
||||
$player5 = new Player(5);
|
||||
$player6 = new Player(6);
|
||||
$player7 = new Player(7);
|
||||
$player8 = new Player(8);
|
||||
$player9 = new Player(9);
|
||||
$player10 = new Player(10);
|
||||
$player11 = new Player(11);
|
||||
$player12 = new Player(12);
|
||||
@ -830,15 +830,15 @@ final class TrueSkillCalculatorTests
|
||||
|
||||
$gameInfo = new GameInfo();
|
||||
|
||||
$team1 = new Team($player1, $gameInfo->getDefaultRating());
|
||||
$team2 = new Team($player2, $gameInfo->getDefaultRating());
|
||||
$team3 = new Team($player3, $gameInfo->getDefaultRating());
|
||||
$team4 = new Team($player4, $gameInfo->getDefaultRating());
|
||||
$team5 = new Team($player5, $gameInfo->getDefaultRating());
|
||||
$team6 = new Team($player6, $gameInfo->getDefaultRating());
|
||||
$team7 = new Team($player7, $gameInfo->getDefaultRating());
|
||||
$team8 = new Team($player8, $gameInfo->getDefaultRating());
|
||||
$team9 = new Team($player9, $gameInfo->getDefaultRating());
|
||||
$team1 = new Team($player1, $gameInfo->getDefaultRating());
|
||||
$team2 = new Team($player2, $gameInfo->getDefaultRating());
|
||||
$team3 = new Team($player3, $gameInfo->getDefaultRating());
|
||||
$team4 = new Team($player4, $gameInfo->getDefaultRating());
|
||||
$team5 = new Team($player5, $gameInfo->getDefaultRating());
|
||||
$team6 = new Team($player6, $gameInfo->getDefaultRating());
|
||||
$team7 = new Team($player7, $gameInfo->getDefaultRating());
|
||||
$team8 = new Team($player8, $gameInfo->getDefaultRating());
|
||||
$team9 = new Team($player9, $gameInfo->getDefaultRating());
|
||||
$team10 = new Team($player10, $gameInfo->getDefaultRating());
|
||||
$team11 = new Team($player11, $gameInfo->getDefaultRating());
|
||||
$team12 = new Team($player12, $gameInfo->getDefaultRating());
|
||||
|
@ -6,10 +6,8 @@ namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\TrueSkill\TwoPlayerTrueSkillCalculator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||
|
||||
#[CoversClass(TwoPlayerTrueSkillCalculator::class)]
|
||||
final class TwoPlayerTrueSkillCalculatorTest extends TestCase
|
||||
{
|
||||
#[CoversNothing]
|
||||
|
@ -6,10 +6,8 @@ namespace DNW\Skills\Tests\TrueSkill;
|
||||
|
||||
use DNW\Skills\TrueSkill\TwoTeamTrueSkillCalculator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||
|
||||
#[CoversClass(TwoTeamTrueSkillCalculator::class)]
|
||||
final class TwoTeamTrueSkillCalculatorTest extends TestCase
|
||||
{
|
||||
#[CoversNothing]
|
||||
|
Reference in New Issue
Block a user