Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['8.2', '8.3', '8.4', '8.5']

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
php-version: ${{ matrix.php-version }}
ini-values: xdebug.max_nesting_level=512

- name: Validate composer.json and composer.lock
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/code-style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
php-version: '8.2'

- name: Install dependencies
run: composer update --prefer-dist --no-progress --no-suggest
run: composer update --prefer-dist --no-progress

- name: Run script
run: vendor/bin/phpcs -n
37 changes: 20 additions & 17 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,33 @@ Please help us keep our issue list small by adding fixes: #{$ISSUE_NO} to the co
#### What is an Algorithm?

An Algorithm is one or more functions (or classes) that:
* take one or more inputs,
* perform some internal calculations or data manipulations,
* return one or more outputs,
* have minimal side effects (Ex. print(), plot(), read(), write()).

- take one or more inputs,
- perform some internal calculations or data manipulations,
- return one or more outputs,
- have minimal side effects (Ex. print(), plot(), read(), write()).

Algorithms should be packaged in a way that would make it easy for readers to put them into larger programs.

Algorithms should:
* have intuitive class and function names that make their purpose clear to readers
* use PHP naming conventions and intuitive variable names to ease comprehension
* be flexible to take different input values
* have PHP type hints for their input parameters and return values
* raise PHP exceptions (UnexpectedValueException, etc.) on erroneous input values
* have docstrings with clear explanations and/or URLs to source materials
* contain doctests that test both valid and erroneous input values
* return all calculation results instead of printing or plotting them

- have intuitive class and function names that make their purpose clear to readers
- use PHP naming conventions and intuitive variable names to ease comprehension
- be flexible to take different input values
- have PHP type hints for their input parameters and return values
- raise PHP exceptions (UnexpectedValueException, etc.) on erroneous input values
- have docstrings with clear explanations and/or URLs to source materials
- contain doctests that test both valid and erroneous input values
- return all calculation results instead of printing or plotting them

Algorithms in this repo should not be how-to examples for existing PHP packages. Instead, they should perform internal calculations or manipulations to convert input values into different output values. Those calculations or manipulations can use data types, classes, or functions of existing PHP packages but each algorithm in this repo should add unique value.

#### Coding Style

We want your work to be readable by others; therefore, we encourage you to note the following:

- Please write in PHP 7.1+
- Please put thought into naming of functions, classes, and variables. Help your reader by using __descriptive names__ that can help you to remove redundant comments
- Please write in PHP 8.2+
- Please put thought into naming of functions, classes, and variables. Help your reader by using **descriptive names** that can help you to remove redundant comments
- Single letter variable names are _old school_ so please avoid them unless their life only spans a few lines
- Please follow the [PHP Basic Coding Standard](https://www.php-fig.org/psr/psr-12/) style guide. So functionNames should be camelCase, CONSTANTS in UPPER_CASE, Name\Spaces and ClassNames should follow an "autoloading" PSR, etc.

Expand All @@ -66,13 +68,14 @@ We want your work to be readable by others; therefore, we encourage you to note

- Avoid importing external libraries for basic algorithms. Only use them for complicated algorithms

- Ensure code is linted with phpcs, and passing all linting checks (vendor/bin/phpcs -n)
- Ensure code is strictly typed and passes static analysis (`composer phpstan`)
- Ensure code is properly linted and formatted (`vendor/bin/php-cs-fixer fix` and `vendor/bin/phpcs -n`)

#### Other Standard While Submitting Your Work

- File extension for code should be `.php`
- File extension for code should be `.php`
- After adding a new File/Directory, please make sure to update the [DIRECTORY.md](DIRECTORY.md) file with the details.
- If possible, follow the standard *within* the folder you are submitting to
- If possible, follow the standard _within_ the folder you are submitting to
- If you have modified/added code work, make sure the code compiles before submitting
- If you have modified/added documentation work, ensure your language is concise and contains no grammar errors
- Add a corresponding explanation to [Algorithms-Explanation](https://github.com/TheAlgorithms/Algorithms-Explanation) (Optional but recommended).
Expand Down
8 changes: 6 additions & 2 deletions Ciphers/AtbashCipher.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Encrypt a message using the Atbash Cipher.
* The Atbash Cipher is a simple substitution cipher where each letter in the plaintext is
Expand All @@ -9,7 +11,7 @@
* @param string $plainText The plaintext to encrypt.
* @return string The encrypted message.
*/
function atbash_encrypt($plainText)
function atbash_encrypt($plainText): string
{
$result = '';
$plainText = strtoupper($plainText);
Expand All @@ -21,8 +23,10 @@ function atbash_encrypt($plainText)
} else {
$encryptedChar = $char; // Non-alphabet characters remain unchanged
}

$result .= $encryptedChar;
}

return $result;
}

Expand All @@ -33,7 +37,7 @@ function atbash_encrypt($plainText)
* @param string $cipherText The ciphertext to decrypt.
* @return string The decrypted message.
*/
function atbash_decrypt($cipherText)
function atbash_decrypt($cipherText): string
{
return atbash_encrypt($cipherText); // Decryption is the same as encryption
}
3 changes: 3 additions & 0 deletions Ciphers/CaesarCipher.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Encrypt given text using caesar cipher.
*
Expand Down Expand Up @@ -41,6 +43,7 @@ function decrypt(string $text, int $shift): string
if ($placeValue < 0) { // Handling case where remainder is negative
$placeValue += 26;
}

$placeValue += ord(ctype_upper($c) ? 'A' : 'a');
$newChar = chr($placeValue); // Getting new character from new value (i.e. A-Z)
$decryptedText .= $newChar; // Appending decrypted character
Expand Down
20 changes: 11 additions & 9 deletions Ciphers/MonoAlphabeticCipher.php
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
<?php

declare(strict_types=1);

// A mono-alphabetic cipher is a simple substitution cipher
// https://www.101computing.net/mono-alphabetic-substitution-cipher/

function monoAlphabeticCipher($key, $alphabet, $text)
function monoAlphabeticCipher(string $key, $alphabet, $text): false|string
{
$cipherText = ''; // the cipher text (can be decrypted and encrypted)

// check if the text length matches
if (strlen($key) != strlen($alphabet)) {
if (strlen($key) !== strlen((string) $alphabet)) {
return false;
}

$text = preg_replace('/[0-9]+/', '', $text); // remove all the numbers
$text = preg_replace('/\d+/', '', (string) $text); // remove all the numbers

for ($i = 0; $i < strlen($text); $i++) {
$index = strripos($alphabet, $text[$i]);
if ($text[$i] == " ") {
for ($i = 0; $i < strlen((string) $text); $i++) {
$index = strripos((string) $alphabet, $text[$i]);
if ($text[$i] === " ") {
$cipherText .= " ";
} else {
$cipherText .= ( ctype_upper($text[$i]) ? strtoupper($key[$index]) : $key[$index] );
$cipherText .= (ctype_upper($text[$i]) ? strtoupper($key[$index]) : $key[$index]);
}
}

return $cipherText;
}

function maEncrypt($key, $alphabet, $text)
function maEncrypt($key, $alphabet, $text): string|false
{
return monoAlphabeticCipher($key, $alphabet, $text);
}

function maDecrypt($key, $alphabet, $text)
function maDecrypt($key, $alphabet, $text): string|false
{
return monoAlphabeticCipher($alphabet, $key, $text);
}
33 changes: 20 additions & 13 deletions Ciphers/MorseCode.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Encode text to Morse Code.
*
Expand All @@ -10,7 +12,8 @@
function encode(string $text): string
{
$text = strtoupper($text); // Makes sure the string is uppercase
$MORSE_CODE = array( // Array containing morse code translations
$MORSE_CODE = [
// Array containing morse code translations
"A" => ".-",
"B" => "-...",
"C" => "-.-.",
Expand Down Expand Up @@ -47,17 +50,18 @@ function encode(string $text): string
"8" => "---..",
"9" => "----.",
"0" => "-----",
" " => "/"
);
" " => "/",
];

$encodedText = ""; // Stores the encoded text
foreach (str_split($text) as $c) { // Going through each character
if (array_key_exists($c, $MORSE_CODE)) { // Checks if it is a valid character
$encodedText .= $MORSE_CODE[$c] . " "; // Appends the correct character
} else {
throw new \Exception("Invalid character: $c");
throw new \Exception('Invalid character: ' . $c);
}
}

substr_replace($encodedText, "", -1); // Removes trailing space
return $encodedText;
}
Expand All @@ -69,7 +73,8 @@ function encode(string $text): string
*/
function decode(string $text): string
{
$MORSE_CODE = array( // An array containing morse code to text translations
$MORSE_CODE = [
// An array containing morse code to text translations
".-" => "A",
"-..." => "B",
"-.-." => "C",
Expand Down Expand Up @@ -106,18 +111,20 @@ function decode(string $text): string
"---.." => "8",
"----." => "9",
"-----" => "0",
"/" => " "
);
"/" => " ",
];

$decodedText = ""; // Stores the decoded text
foreach (explode(" ", $text) as $c) { // Going through each group
if (array_key_exists($c, $MORSE_CODE)) { // Checks if it is a valid character
$decodedText .= $MORSE_CODE[$c]; // Appends the correct character
} else {
if ($c) { // Makes sure that the string is not empty to prevent trailing spaces or extra spaces from breaking this
throw new \Exception("Invalid character: $c");
}
if (array_key_exists($c, $MORSE_CODE)) {
// Checks if it is a valid character
$decodedText .= $MORSE_CODE[$c];
// Appends the correct character
} elseif ($c !== '' && $c !== '0') {
// Makes sure that the string is not empty to prevent trailing spaces or extra spaces from breaking this
throw new \Exception('Invalid character: ' . $c);
}
}

return $decodedText;
}
20 changes: 13 additions & 7 deletions Ciphers/RailfenceCipher.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Encode a message using the Rail Fence Cipher.
* (https://en.wikipedia.org/wiki/Rail_fence_cipher)
Expand All @@ -19,15 +21,17 @@ function Railencode($plainMessage, $rails): string
if (!isset($cipherMessage[$step])) {
$cipherMessage[$step] = '';
}

// Check if the character should go in the rail
if ($index % $position == $step || $index % $position == $position - $step) {
if ($index % $position === $step || $index % $position == $position - $step) {
$cipherMessage[$step] .= $plainMessage[$index];
} else {
// Add a placeholder for empty spaces
$cipherMessage[$step] .= ".";
}
}
}

// Combine and remove placeholders to form the cipher message
return implode('', str_replace('.', '', $cipherMessage));
}
Expand All @@ -44,7 +48,7 @@ function Raildecode($cipherMessage, $rails): string
{
$position = ($rails * 2) - 2;
$textLength = strlen($cipherMessage);
$minLength = floor($textLength / $position);
$minLength = intdiv($textLength, $position);
$balance = $textLength % $position;
$lengths = [];
$strings = [];
Expand All @@ -55,27 +59,29 @@ function Raildecode($cipherMessage, $rails): string
if ($rowIndex != 0 && $rowIndex != ($rails - 1)) {
$lengths[$rowIndex] += $minLength;
}

if ($balance > $rowIndex) {
$lengths[$rowIndex]++;
}

if ($balance > ($rails + ($rails - $rowIndex) - 2)) {
$lengths[$rowIndex]++;
}

$strings[] = substr($cipherMessage, $totalLengths, $lengths[$rowIndex]);
$totalLengths += $lengths[$rowIndex];
}

// Convert the rows of characters to plain message
$plainText = '';
while (strlen($plainText) < $textLength) {
for ($charIndex = 0; $charIndex < $position; $charIndex++) {
if (isset($strings[$charIndex])) {
$index = $charIndex;
} else {
$index = $position - $charIndex;
}
$index = isset($strings[$charIndex]) ? $charIndex : $position - $charIndex;

$plainText .= substr($strings[$index], 0, 1);
$strings[$index] = substr($strings[$index], 1);
}
}

return $plainText;
}
4 changes: 4 additions & 0 deletions Ciphers/VignereCipher.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Encrypts a plaintext using the Vigenère cipher.
* (https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher)
Expand Down Expand Up @@ -29,6 +31,7 @@ function vigenere_encrypt($plaintext, $key): string
$encryptedText .= $char;
}
}

return $encryptedText;
}

Expand Down Expand Up @@ -59,5 +62,6 @@ function vigenere_decrypt($ciphertext, $key): string
$decryptedText .= $char;
}
}

return $decryptedText;
}
Loading