diff --git a/exercises/practice/all-your-base/.docs/instructions.md b/exercises/practice/all-your-base/.docs/instructions.md index c39686f2..1b688b69 100644 --- a/exercises/practice/all-your-base/.docs/instructions.md +++ b/exercises/practice/all-your-base/.docs/instructions.md @@ -1,32 +1,28 @@ # Instructions -Convert a number, represented as a sequence of digits in one base, to any other base. +Convert a sequence of digits in one base, representing a number, into a sequence of digits in another base, representing the same number. -Implement general base conversion. Given a number in base **a**, -represented as a sequence of digits, convert it to base **b**. +~~~~exercism/note +Try to implement the conversion yourself. +Do not use something else to perform the conversion for you. +~~~~ -## Note +## About [Positional Notation][positional-notation] -- Try to implement the conversion yourself. - Do not use something else to perform the conversion for you. +In positional notation, a number in base **b** can be understood as a linear combination of powers of **b**. -## About [Positional Notation](https://en.wikipedia.org/wiki/Positional_notation) +The number 42, _in base 10_, means: -In positional notation, a number in base **b** can be understood as a linear -combination of powers of **b**. +`(4 × 10¹) + (2 × 10⁰)` -The number 42, *in base 10*, means: +The number 101010, _in base 2_, means: -(4 * 10^1) + (2 * 10^0) +`(1 × 2⁵) + (0 × 2⁴) + (1 × 2³) + (0 × 2²) + (1 × 2¹) + (0 × 2⁰)` -The number 101010, *in base 2*, means: +The number 1120, _in base 3_, means: -(1 * 2^5) + (0 * 2^4) + (1 * 2^3) + (0 * 2^2) + (1 * 2^1) + (0 * 2^0) +`(1 × 3³) + (1 × 3²) + (2 × 3¹) + (0 × 3⁰)` -The number 1120, *in base 3*, means: +_Yes. Those three numbers above are exactly the same. Congratulations!_ -(1 * 3^3) + (1 * 3^2) + (2 * 3^1) + (0 * 3^0) - -I think you got the idea! - -*Yes. Those three numbers above are exactly the same. Congratulations!* +[positional-notation]: https://en.wikipedia.org/wiki/Positional_notation diff --git a/exercises/practice/all-your-base/.docs/introduction.md b/exercises/practice/all-your-base/.docs/introduction.md new file mode 100644 index 00000000..68aaffbe --- /dev/null +++ b/exercises/practice/all-your-base/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +You've just been hired as professor of mathematics. +Your first week went well, but something is off in your second week. +The problem is that every answer given by your students is wrong! +Luckily, your math skills have allowed you to identify the problem: the student answers _are_ correct, but they're all in base 2 (binary)! +Amazingly, it turns out that each week, the students use a different base. +To help you quickly verify the student answers, you'll be building a tool to translate between bases. diff --git a/exercises/practice/all-your-base/.meta/example.php b/exercises/practice/all-your-base/.meta/example.php index 0a6616f5..d37ad035 100644 --- a/exercises/practice/all-your-base/.meta/example.php +++ b/exercises/practice/all-your-base/.meta/example.php @@ -1,33 +1,15 @@ . - * - * To disable strict typing, comment out the directive below. - */ - declare(strict_types=1); -function rebase(int $fromBase, array $digits, int $toBase) +function rebase(int $fromBase, array $digits, int $toBase): array { - if (empty($digits) || $digits[0] == 0 || $fromBase <= 1 || $toBase <= 1) { - return null; + if ($fromBase <= 1) { + throw new InvalidArgumentException('input base must be >= 2'); + } + + if ($toBase <= 1) { + throw new InvalidArgumentException('output base must be >= 2'); } $decTotal = 0; @@ -35,7 +17,7 @@ function rebase(int $fromBase, array $digits, int $toBase) for ($i = 0; $i < count($digits); $i++) { $decTotal += $ordered[$i] * pow($fromBase, $i); if ($ordered[$i] >= $fromBase || $ordered[$i] < 0) { - return null; + throw new InvalidArgumentException('all digits must satisfy 0 <= d < input base'); } } diff --git a/exercises/practice/all-your-base/.meta/tests.toml b/exercises/practice/all-your-base/.meta/tests.toml index 1422ae4b..4a1759b8 100644 --- a/exercises/practice/all-your-base/.meta/tests.toml +++ b/exercises/practice/all-your-base/.meta/tests.toml @@ -64,3 +64,4 @@ description = "output base is negative" [0e6c895d-8a5d-4868-a345-309d094cfe8d] description = "both bases are negative" +comment = "We cannot know which condition comes first. So no message is enforced." diff --git a/exercises/practice/all-your-base/AllYourBase.php b/exercises/practice/all-your-base/AllYourBase.php index 18e33cc4..41b15a3f 100644 --- a/exercises/practice/all-your-base/AllYourBase.php +++ b/exercises/practice/all-your-base/AllYourBase.php @@ -24,7 +24,7 @@ declare(strict_types=1); -function rebase(int $number, array $sequence, int $base) +function rebase(int $fromBase, array $digits, int $toBase): array { throw new \BadFunctionCallException("Implement the rebase function"); } diff --git a/exercises/practice/all-your-base/AllYourBaseTest.php b/exercises/practice/all-your-base/AllYourBaseTest.php index f24b0fc3..f9aa8dac 100644 --- a/exercises/practice/all-your-base/AllYourBaseTest.php +++ b/exercises/practice/all-your-base/AllYourBaseTest.php @@ -1,33 +1,7 @@ . - * - * To disable strict typing, comment out the directive below. - */ - declare(strict_types=1); -/** - * These tests are adapted from the canonical data in the - * `problem-specifications` repository. - */ class AllYourBaseTest extends PHPUnit\Framework\TestCase { public static function setUpBeforeClass(): void @@ -35,108 +9,218 @@ public static function setUpBeforeClass(): void require_once 'AllYourBase.php'; } + /** + * uuid 5ce422f9-7a4b-4f44-ad29-49c67cb32d2c + * @testdox Single bit one to decimal + */ public function testSingleBitOneToDecimal(): void { $this->assertEquals([1], rebase(2, [1], 10)); } + /** + * uuid 0cc3fea8-bb79-46ac-a2ab-5a2c93051033 + * @testdox Binary to single decimal + */ public function testBinaryToSingleDecimal(): void { $this->assertEquals([5], rebase(2, [1, 0, 1], 10)); } + /** + * uuid f12db0f9-0d3d-42c2-b3ba-e38cb375a2b8 + * @testdox Single decimal to binary + */ public function testSingleDecimalToBinary(): void { $this->assertEquals([1, 0, 1], rebase(10, [5], 2)); } + /** + * uuid 2c45cf54-6da3-4748-9733-5a3c765d925b + * @testdox Binary to multiple decimal + */ public function testBinaryToMultipleDecimal(): void { $this->assertEquals([4, 2], rebase(2, [1, 0, 1, 0, 1, 0], 10)); } + /** + * uuid 65ddb8b4-8899-4fcc-8618-181b2cf0002d + * @testdox Decimal to binary + */ public function testDecimalToBinary(): void { $this->assertEquals([1, 0, 1, 0, 1, 0], rebase(10, [4, 2], 2)); } + /** + * uuid 8d418419-02a7-4824-8b7a-352d33c6987e + * @testdox Trinary to hexadecimal + */ public function testTrinaryToHexadecimal(): void { $this->assertEquals([2, 10], rebase(3, [1, 1, 2, 0], 16)); } + /** + * uuid d3901c80-8190-41b9-bd86-38d988efa956 + * @testdox Hexadecimal to trinary + */ public function testHexadecimalToTrinary(): void { $this->assertEquals([1, 1, 2, 0], rebase(16, [2, 10], 3)); } + /** + * uuid 5d42f85e-21ad-41bd-b9be-a3e8e4258bbf + * @testdox 15-bit integer + */ public function test15BitIntegers(): void { $this->assertEquals([6, 10, 45], rebase(97, [3, 46, 60], 73)); } - public function testEmptyListReturnsNull(): void + /** + * uuid d68788f7-66dd-43f8-a543-f15b6d233f83 + * @testdox Empty list + */ + public function testEmptyList(): void { - $this->assertEquals(null, rebase(10, [], 10)); + $this->assertEquals([0], rebase(2, [], 10)); } - public function testSingleZeroReturnsNull(): void + /** + * uuid 5e27e8da-5862-4c5f-b2a9-26c0382b6be7 + * @testdox Single zero + */ + public function testSingleZero(): void { - $this->assertEquals(null, rebase(10, [0], 2)); + $this->assertEquals([0], rebase(10, [0], 2)); } - public function testMultipleZerosReturnsNull(): void + /** + * uuid 2e1c2573-77e4-4b9c-8517-6c56c5bcfdf2 + * @testdox Multiple zeros + */ + public function testMultipleZeros(): void { - $this->assertEquals(null, rebase(10, [0, 0, 0], 2)); + $this->assertEquals([0], rebase(10, [0, 0, 0], 2)); } - public function testLeadingZerosReturnsNull(): void + /** + * uuid 3530cd9f-8d6d-43f5-bc6e-b30b1db9629b + * @testdox Leading zeros + */ + public function testLeadingZeros(): void { - $this->assertEquals(null, rebase(10, [0, 6, 0], 2)); + $this->assertEquals([4, 2], rebase(7, [0, 6, 0], 10)); } + /** + * uuid a6b476a1-1901-4f2a-92c4-4d91917ae023 + * @testdox Input base is one + */ public function testFirstBaseIsOne(): void { - $this->assertEquals(null, rebase(1, [6, 0], 2)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('input base must be >= 2'); + + rebase(1, [0], 10); } + /** + * uuid e21a693a-7a69-450b-b393-27415c26a016 + * @testdox Input base is zero + */ public function testFirstBaseIsZero(): void { - $this->assertEquals(null, rebase(0, [6, 0], 2)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('input base must be >= 2'); + + rebase(0, [], 10); } + /** + * uuid 54a23be5-d99e-41cc-88e0-a650ffe5fcc2 + * @testdox Input base is negative + */ public function testFirstBaseIsNegative(): void { - $this->assertEquals(null, rebase(-1, [6, 0], 2)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('input base must be >= 2'); + + rebase(-2, [1], 10); } + /** + * uuid 9eccf60c-dcc9-407b-95d8-c37b8be56bb6 + * @testdox Negative digit + */ public function testNegativeDigit(): void { - $this->assertEquals(null, rebase(10, [1, -1, 0], 2)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('all digits must satisfy 0 <= d < input base'); + + rebase(2, [1, -1, 1, 0, 1, 0], 10); } + /** + * uuid 232fa4a5-e761-4939-ba0c-ed046cd0676a + * @testdox Invalid positive digit + */ public function testInvalidPositiveDigit(): void { - $this->assertEquals(null, rebase(2, [1, 2, 0], 10)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('all digits must satisfy 0 <= d < input base'); + + rebase(2, [1, 2, 1, 0, 1, 0], 10); } + /** + * uuid 14238f95-45da-41dc-95ce-18f860b30ad3 + * @testdox Output base is one + */ public function testSecondBaseIsOne(): void { - $this->assertEquals(null, rebase(2, [1, 1, 0], 1)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('output base must be >= 2'); + + rebase(2, [1, 0, 1, 0, 1, 0], 1); } + /** + * uuid 73dac367-da5c-4a37-95fe-c87fad0a4047 + * @testdox Output base is zero + */ public function testSecondBaseIsZero(): void { - $this->assertEquals(null, rebase(2, [1, 1, 0], 0)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('output base must be >= 2'); + + rebase(10, [7], 0); } + /** + * uuid 13f81f42-ff53-4e24-89d9-37603a48ebd9 + * @testdox Output base is negative + */ public function testSecondBaseIsNegative(): void { - $this->assertEquals(null, rebase(2, [1, 1, 0], -1)); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('output base must be >= 2'); + + rebase(2, [1], -7); } + /** + * uuid 0e6c895d-8a5d-4868-a345-309d094cfe8d + * @testdox Both bases are negative + */ public function testBothBasesIsNegative(): void { - $this->assertEquals(null, rebase(-3, [1, 1, 0], -1)); + $this->expectException(InvalidArgumentException::class); + + rebase(-2, [1], -7); } }