diff --git a/rotational-cipher/.exercism/config.json b/rotational-cipher/.exercism/config.json
new file mode 100644
index 0000000..d21c3ca
--- /dev/null
+++ b/rotational-cipher/.exercism/config.json
@@ -0,0 +1,30 @@
+{
+ "authors": [
+ "krapes"
+ ],
+ "contributors": [
+ "akashsara",
+ "behrtam",
+ "cmccandless",
+ "Dog",
+ "dotrungkien",
+ "ikhadykin",
+ "lekum",
+ "N-Parsons",
+ "tqa236"
+ ],
+ "files": {
+ "solution": [
+ "rotational_cipher.py"
+ ],
+ "test": [
+ "rotational_cipher_test.py"
+ ],
+ "example": [
+ ".meta/example.py"
+ ]
+ },
+ "blurb": "Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.",
+ "source": "Wikipedia",
+ "source_url": "https://en.wikipedia.org/wiki/Caesar_cipher"
+}
diff --git a/rotational-cipher/.exercism/metadata.json b/rotational-cipher/.exercism/metadata.json
new file mode 100644
index 0000000..2162958
--- /dev/null
+++ b/rotational-cipher/.exercism/metadata.json
@@ -0,0 +1 @@
+{"track":"python","exercise":"rotational-cipher","id":"26e4a0f518d449fa83d98ca4d48f99b9","url":"https://exercism.org/tracks/python/exercises/rotational-cipher","handle":"myFirstCode","is_requester":true,"auto_approve":false}
\ No newline at end of file
diff --git a/rotational-cipher/HELP.md b/rotational-cipher/HELP.md
new file mode 100644
index 0000000..d45cf55
--- /dev/null
+++ b/rotational-cipher/HELP.md
@@ -0,0 +1,130 @@
+# Help
+
+## Running the tests
+
+We use [pytest][pytest: Getting Started Guide] as our website test runner.
+You will need to install `pytest` on your development machine if you want to run tests for the Python track locally.
+You should also install the following `pytest` plugins:
+
+- [pytest-cache][pytest-cache]
+- [pytest-subtests][pytest-subtests]
+
+Extended information can be found in our website [Python testing guide][Python track tests page].
+
+
+### Running Tests
+
+To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_).
+Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded.
+
+Linux/MacOS
+```bash
+$ cd {path/to/exercise-folder-location}
+```
+
+Windows
+```powershell
+PS C:\Users\foobar> cd {path\to\exercise-folder-location}
+```
+
+
+
+Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file:
+
+Linux/MacOS
+```bash
+$ python3 -m pytest -o markers=task {exercise_test.py}
+==================== 7 passed in 0.08s ====================
+```
+
+Windows
+```powershell
+PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py}
+==================== 7 passed in 0.08s ====================
+```
+
+
+### Common options
+- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_)
+- `-v` : enable verbose output.
+- `-x` : stop running tests on first failure.
+- `--ff` : run failures from previous test before running other test cases.
+
+For additional options, use `python3 -m pytest -h` or `py -m pytest -h`.
+
+
+### Fixing warnings
+
+If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax:
+
+```bash
+PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html
+```
+
+To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file.
+We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini].
+
+You can also create your own `pytest.ini` file with the following content:
+
+```ini
+[pytest]
+markers =
+ task: A concept exercise task.
+```
+
+Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings.
+More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers].
+
+Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats].
+
+
+### Extending your IDE or Code Editor
+
+Many IDEs and code editors have built-in support for using `pytest` and other code quality tools.
+Some community-sourced options can be found on our [Python track tools page][Python track tools page].
+
+[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html
+[Python track tools page]: https://exercism.org/docs/tracks/python/tools
+[Python track tests page]: https://exercism.org/docs/tracks/python/tests
+[pytest-cache]:http://pythonhosted.org/pytest-cache/
+[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests
+[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini
+[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats
+[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks
+[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers
+
+## Submitting your solution
+
+You can submit your solution using the `exercism submit rotational_cipher.py` command.
+This command will upload your solution to the Exercism website and print the solution page's URL.
+
+It's possible to submit an incomplete solution which allows you to:
+
+- See how others have completed the exercise
+- Request help from a mentor
+
+## Need to get help?
+
+If you'd like help solving the exercise, check the following pages:
+
+- The [Python track's documentation](https://exercism.org/docs/tracks/python)
+- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python)
+- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
+- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
+
+Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
+
+Below are some resources for getting help if you run into trouble:
+
+- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources.
+- [The Exercism Community on Discord](https://exercism.org/r/discord)
+- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community.
+- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners.
+- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done.
+- [Python Community Forums](https://discuss.python.org/)
+- [Free Code Camp Community Forums](https://forum.freecodecamp.org/)
+- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help)
+- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually.
+
+Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already.
+ If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question.
\ No newline at end of file
diff --git a/rotational-cipher/README.md b/rotational-cipher/README.md
new file mode 100644
index 0000000..e86902c
--- /dev/null
+++ b/rotational-cipher/README.md
@@ -0,0 +1,56 @@
+# Rotational Cipher
+
+Welcome to Rotational Cipher on Exercism's Python Track.
+If you need help running the tests or submitting your code, check out `HELP.md`.
+
+## Instructions
+
+Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.
+
+The Caesar cipher is a simple shift cipher that relies on transposing all the letters in the alphabet using an integer key between `0` and `26`.
+Using a key of `0` or `26` will always yield the same output due to modular arithmetic.
+The letter is shifted for as many values as the value of the key.
+
+The general notation for rotational ciphers is `ROT + `.
+The most commonly used rotational cipher is `ROT13`.
+
+A `ROT13` on the Latin alphabet would be as follows:
+
+```text
+Plain: abcdefghijklmnopqrstuvwxyz
+Cipher: nopqrstuvwxyzabcdefghijklm
+```
+
+It is stronger than the Atbash cipher because it has 27 possible keys, and 25 usable keys.
+
+Ciphertext is written out in the same formatting as the input including spaces and punctuation.
+
+## Examples
+
+- ROT5 `omg` gives `trl`
+- ROT0 `c` gives `c`
+- ROT26 `Cool` gives `Cool`
+- ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.`
+- ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.`
+
+## Source
+
+### Created by
+
+- @krapes
+
+### Contributed to by
+
+- @akashsara
+- @behrtam
+- @cmccandless
+- @Dog
+- @dotrungkien
+- @ikhadykin
+- @lekum
+- @N-Parsons
+- @tqa236
+
+### Based on
+
+Wikipedia - https://en.wikipedia.org/wiki/Caesar_cipher
\ No newline at end of file
diff --git a/rotational-cipher/rotational_cipher.py b/rotational-cipher/rotational_cipher.py
new file mode 100644
index 0000000..60b1b94
--- /dev/null
+++ b/rotational-cipher/rotational_cipher.py
@@ -0,0 +1,63 @@
+"""
+The rotational cipher, also sometimes called the Caesar cipher.
+
+The Caesar cipher is a simple shift cipher that relies on transposing
+all the letters in the alphabet using an integer key between 0 and 26.
+Using a key of 0 or 26 will always yield the same output due to modular
+arithmetic. The letter is shifted for as many values as the value of the key.
+"""
+
+import string
+
+LETTERS_LOWER: str = string.ascii_lowercase
+LETTERS_UPPER: str = string.ascii_uppercase
+
+
+def rotate(text: str, key: int) -> str:
+ """
+ Rotate each letter in the text by the specified key using Caesar cipher.
+
+ Non-alphabetic characters remain unchanged. The rotation wraps around
+ the alphabet (a->z, A->Z) using modular arithmetic.
+
+ :param text: The input string to be rotated
+ :param key: The number of positions to shift each letter (0-25)
+ :return: The rotated string with letters shifted by key positions
+
+ Examples:
+ >>> rotate("abc", 1)
+ "bcd"
+ >>> rotate("Hello, World!", 13)
+ "Uryyb, Jbeyq!"
+ """
+ new_str: list[str] = []
+ for char in text:
+ # Not a letter
+ if not char.isalpha():
+ new_str.append(char)
+ else:
+ new_str.append(replace_char(char, key))
+ # Convert to a string
+ return "".join(new_str)
+
+
+def replace_char(char: str, key: int) -> str:
+ """
+ Shifts the character by the specified key positions within its alphabet
+ (uppercase or lowercase). Uses modular arithmetic to wrap around the
+ alphabet.
+
+ :param char: The alphabetic character to rotate
+ :param key: The number of positions to shift the character
+ :return: The rotated character in the same case as the input
+ """
+ if char in LETTERS_UPPER:
+ new_index: int = LETTERS_UPPER.index(char) + key
+ if new_index < 26:
+ return LETTERS_UPPER[new_index]
+ return LETTERS_UPPER[new_index - 26]
+
+ new_index = LETTERS_LOWER.index(char) + key
+ if new_index < 26:
+ return LETTERS_LOWER[new_index]
+ return LETTERS_LOWER[new_index - 26]
diff --git a/rotational-cipher/rotational_cipher_test.py b/rotational-cipher/rotational_cipher_test.py
new file mode 100644
index 0000000..6dde222
--- /dev/null
+++ b/rotational-cipher/rotational_cipher_test.py
@@ -0,0 +1,46 @@
+# pylint: disable=C0114, C0115, C0116, R0904
+
+# These tests are auto-generated with test data from:
+# https://github.com/exercism/problem-specifications/tree/main/exercises/rotational-cipher/canonical-data.json
+# File last updated on 2023-07-19
+
+import unittest
+
+from rotational_cipher import (
+ rotate,
+)
+
+
+class RotationalCipherTest(unittest.TestCase):
+ def test_rotate_a_by_0_same_output_as_input(self):
+ self.assertEqual(rotate("a", 0), "a")
+
+ def test_rotate_a_by_1(self):
+ self.assertEqual(rotate("a", 1), "b")
+
+ def test_rotate_a_by_26_same_output_as_input(self):
+ self.assertEqual(rotate("a", 26), "a")
+
+ def test_rotate_m_by_13(self):
+ self.assertEqual(rotate("m", 13), "z")
+
+ def test_rotate_n_by_13_with_wrap_around_alphabet(self):
+ self.assertEqual(rotate("n", 13), "a")
+
+ def test_rotate_capital_letters(self):
+ self.assertEqual(rotate("OMG", 5), "TRL")
+
+ def test_rotate_spaces(self):
+ self.assertEqual(rotate("O M G", 5), "T R L")
+
+ def test_rotate_numbers(self):
+ self.assertEqual(rotate("Testing 1 2 3 testing", 4), "Xiwxmrk 1 2 3 xiwxmrk")
+
+ def test_rotate_punctuation(self):
+ self.assertEqual(rotate("Let's eat, Grandma!", 21), "Gzo'n zvo, Bmviyhv!")
+
+ def test_rotate_all_letters(self):
+ self.assertEqual(
+ rotate("The quick brown fox jumps over the lazy dog.", 13),
+ "Gur dhvpx oebja sbk whzcf bire gur ynml qbt.",
+ )