p3-ciphers
EECS 183 Project 3: Ciphers — Student Quickstart
Full specification (all details + sample runs): Full Spec
This page is a shorter, student-first version of the full spec. It keeps every requirement, but organizes them for faster onboarding.
Note: you will need to use the details in the full specification to complete the project.
0) Logistics (Dates, Grading, Submissions)
Due date: Friday, February 27, 2026 at 8:00 p.m. (accepted until 11:59:59 p.m.)
Autograder: Direct autograder link
Early bonus (autograder score):
- Last submission on Wednesday, February 25: +5%
- Last submission on Thursday, February 26: +2.5%
Grading:
- 10 points testing (
test.cpp) - 60 points correctness
- 10 points style
Submissions:
- 4 submissions per day with feedback
- 1 extra wildcard submission (once during the project period)
- Best submission counts for style
- If multiple submissions tie in score, the last of those is used for style
1) Big Picture (What You’re Building)
You will implement three ciphers and a menu-driven driver program:
- Caesar cipher
- Vigenere cipher
- Polybius Square
- A
ciphers()program that asks the user what to do and prints the result - A test suite in
test.cpp
2) Files You’re Given (and One You Create)
Download the starter files using this link.
| File | Purpose | You Edit? |
|---|---|---|
utility.h / utility.cpp |
helper string/char utilities | Yes (.cpp) |
caesar.h / caesar.cpp |
Caesar cipher | Yes (.cpp) |
vigenere.h / vigenere.cpp |
Vigenere cipher | Yes (.cpp) |
polybius.h / polybius.cpp |
Polybius Square | Yes (.cpp) |
ciphers.cpp |
user-facing menu + I/O | Yes |
start.cpp |
main() menu to run tests or ciphers |
No |
test.cpp |
your tests (you must create this) | Yes |
Note: the project will not compile until test.cpp exists and defines startTests().
Important constants in utility.h:
SIZE = 6(Polybius grid size)ALNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
3) Read the RME Comments Like Contracts
Every function declaration in the headers has an RME comment:
- Requires: preconditions the caller must satisfy.
- Modifies: what the function is allowed to change.
- Effects: what the function returns or does.
If your tests or ciphers() violate a Requires clause, the autograder will penalize you. Treat RMEs like a contract between the caller and callee.
4) Collaboration and Partnering
Allowed collaboration:
- Help understanding course concepts
- Discuss the spec and design ideas
- Help debug or interpret compiler errors
Not allowed:
- Copying or deriving code from others
- Sharing your code in any form (public or private)
- Collaborating so solutions are identifiably similar
- Receiving help that tells you what to write
- Sharing test cases submitted for grading
If unsure, ask course staff first.
Partnering:
- You may work with one other currently enrolled EECS 183 student
- You must register your group on the autograder before submitting
- You cannot change partners or add a partner mid-project
- Group gets the same submit limit (no extra submits)
- Partners share an autograder and submissions - you can and should have the same code as your partner
- Review partner/late-day policies: partner guidelines
5) Suggested Implementation Order
This order reduces confusion and makes later functions easier:
utility.cppcaesar.cppvigenere.cpppolybius.cppciphers.cpp
6) Test Suite Basics
You must create test.cpp with a startTests() function. Write tests before you implement each function. There is no main() in test.cpp.
Full details: Test Suite
Testing notes:
- Do not call functions with inputs that violate their Requires clauses.
- The autograder runs your
test.cppagainst both correct and buggy staff implementations and compares output. - If the outputs differ, you exposed a bug. You do not need to find all bugs to get full testing points.
- Style is not graded in
test.cpp.
Minimal test.cpp skeleton:
#include "utility.h"
#include "caesar.h"
#include "vigenere.h"
#include "polybius.h"
#include <iostream>
#include <string>
using namespace std;
void startTests() {
// call your test functions here
}
Functions to test:
toUpperCase()removeNonAlphas()removeDuplicate()charToInt()shiftAlphaCharacter()caesarCipher()vigenereCipher()fillGrid()mixKey()findInGrid()polybiusSquare()
Bug IDs the autograder may report (names only):
- CAESAR_SHIFTALPHACHARACTER1
- CAESAR_SHIFTALPHACHARACTER2
- CAESARCIPHER
- UTILITY_CHARTOINT
- UTILITY_REMOVEDUPLICATE
- UTILITY_REMOVENONALPHAS1
- UTILITY_REMOVENONALPHAS2
- UTILITY_TOUPPERCASE
- POLYBIUS_FILLGRID
- POLYBIUS_FINDINGRID
- POLYBIUS_MIXKEY
- POLYBIUSSQUARE
- VIGENERECIPHER
7) Cipher Rules (Short Version)
Full details: Ciphers section
Caesar Cipher
| Rule | Meaning |
|---|---|
| Shift letters by key | Wrap around A–Z and a–z |
| Preserve case | Uppercase stays uppercase, lowercase stays lowercase |
| Non-letters unchanged | Punctuation, spaces, digits stay the same |
| Decrypt = shift backward | Use negative shift or reverse direction |
Functions:
shiftAlphaCharacter(char c, int n)caesarCipher(string original, int key, bool encrypt)
Vigenere Cipher
Steps:
- Convert keyword to uppercase
- Remove non-letters from keyword
- Repeat keyword across letters only in the message
- Shift letters by keyword letter distance (A=0, B=1, …)
- Preserve case in the message
- Non-letters unchanged
Function:
vigenereCipher(string original, string keyword, bool encrypt)
Requires:
- keyword must contain at least one alphabetical character
Polybius Square
Rules:
- Grid is 6x6 using
ALNUM(A–Z then 0–9) - Build a mixed grid using a key with no duplicates
- Encrypt by replacing each character with row/column digits
- Decrypt by reversing those coordinates
- Spaces are allowed and stay as spaces
Functions:
mixKey(string key)fillGrid(char grid[SIZE][SIZE], string content)findInGrid(char c, char grid[SIZE][SIZE])polybiusSquare(char grid[SIZE][SIZE], string key, string original, bool encrypt)
Requires:
keyis uppercase, alphanumeric, no duplicatesoriginaluses only uppercase alphanumeric or spaces
Note:
- Decrypted Polybius output being all uppercase is expected and acceptable.
8) ciphers() Input Rules (Very Important)
Your ciphers() function must validate user input to avoid violating RMEs.
Full details: Error handling in ciphers()
Prompts (exact text + a single trailing space):
Choose a cipher (Caesar, Vigenere, or Polybius):
Encrypt or decrypt:
Enter a message:
What is your key:
The encrypted message is:
The decrypted message is:
Accepted cipher inputs (case-insensitive):
caesarorcvigenereorvpolybiusorp
Accepted mode inputs (case-insensitive):
encryptoredecryptord
Error handling:
- Invalid cipher -> print
Invalid cipher!and return - Invalid mode -> print
Invalid mode!and return - Caesar: you may assume the key is an integer when Caesar is selected
- Vigenere: keyword must contain at least one letter, else
Invalid key! - Polybius message: must be alphanumeric or space; convert to uppercase before calling
polybiusSquare, elseInvalid message! - Polybius key: must be alphanumeric only, uppercase, no duplicates; uppercase + remove duplicates before calling
polybiusSquare, elseInvalid key!
Input tips:
- Prefer
getlineto read messages/keys that may include spaces. - Accept
c,v,p,e,d(any case) as shorthand.
Sample runs: Sample Output
9) Function Dependency Map (Who Calls What)
Full details: Function Table
| Function | Should call | Purpose |
|---|---|---|
caesarCipher() |
shiftAlphaCharacter() |
Shift characters |
vigenereCipher() |
toUpperCase(), removeNonAlphas(), shiftAlphaCharacter() |
Clean keyword, shift |
mixKey() |
removeDuplicate() |
Build Polybius key |
polybiusSquare() |
mixKey(), fillGrid(), findInGrid(), charToInt() |
Encrypt/decrypt via grid |
10) Style and Autograder Reminders
Full details: Style Checklist
Style essentials:
- No global variables
- No magic numbers like
26or65 - No
break/continuein loops - No
if (someBool == true)comparisons - 80 characters per line max
- Write helpful comments
- Do not edit provided header files
- Keep RMEs above function declarations (if you add helper functions in
ciphers.cpp, add RMEs above those declarations) - Do not use numeric ASCII values for characters (use
'A','a', etc.)
Autograder reminders:
- Submit:
caesar.cpp,utility.cpp,test.cpp,ciphers.cpp,polybius.cpp,vigenere.cpp - Whitespace differences can fail tests
- You get 4 submissions per day + 1 wildcard submission
- Best submission counts for style
- If multiple submissions tie in score, the last of those is used for style
11) Recommended Timeline (Winter 2026)
| Date | Suggested milestone |
|---|---|
| Feb 9 | Starter files set up; project compiles; spec read |
| Feb 13 | utility.cpp implemented and tested |
| Feb 18 | caesar.cpp implemented and tested |
| Feb 20 | vigenere.cpp implemented and tested |
| Feb 23 | polybius.cpp implemented and tested; start ciphers() |
| Feb 24 | All code complete; debugging |
| Feb 25 | Last day for 5% bonus |
| Feb 27, 2026 | Final due |
12) Fast Start Checklist
- Download and unzip starter files
- Create
test.cppwithstartTests() - Implement and test
utility.cpp - Implement and test
caesar.cpp - Implement and test
vigenere.cpp - Implement and test
polybius.cpp - Implement and test
ciphers.cpp - Submit early and often
13) Warm-Up Questions (Quick Review)
- What does
%do? - Difference between
charandstring? - How to get a string’s length?
- How to get the first, last, or nth character?
- How to represent an empty string?
- How to concatenate strings?
- Difference between
0and'0'? - How to check if a character is lowercase, uppercase, alphabetic, or alphanumeric?
14) Library Notes You Can Use
cctypefunctions likeisalpha,isdigit,isspacereturn non-zero for true. Useif (isalpha(ch)), notif (isalpha(ch) == true).to_string(int)converts an integer to a string. It does not convert achar.
15) Optional Challenge
- S’More (optional): Project 3 S’More