Apologist's Card & Fine-Tuning Report
Apologetic question: "Who am I, what question am I wrestling with — and is the universe designed?"
Project 1 — Apologist’s Card & Fine-Tuning Report
“You can’t measure your growth if you never wrote down where you started.”
“The most incomprehensible thing about the universe is that it is comprehensible.” — Albert Einstein
Chapter: 1 — The Sport of Programming and the Memory It Runs On
Due: End of Week 1
Submit: A link to your code — an OnlineGDB project URL or a public GitHub repo URL — with p1_apologist_card.cpp as the main source file. See Appendix A for the full workflow.
Allowed tools: Everything through Chapter 1 — cout, cin, getline, the five primitive types (int, double, bool, char, string), const, arithmetic, static_cast, setprecision/fixed, and comments.
Not yet allowed: Conditionals (if/else), loops, functions you define yourself, arrays, structs, classes.
Estimated time: Normal 4–6 hrs · Medium 6–8 hrs · Hard 8–10 hrs
The Setup
Every sport prints cards. Baseball cards, soccer kits with the name on the back, a boxer’s stat sheet listing weight class and reach. And every one of them has the same two sides. The front is a face and a name. The back is where the card stops being a picture and starts being a claim: at-bats, ERA, minutes played, the numbers that either hold up or don’t.
Apologists could use a card. That’s what you’re building this week — one program, one card, two sides.
The front side is you. Your name, where you’re from, the hours you’ve committed, and one question you’d actually like to be able to think clearly about by Week 8. Not a placeholder. The real one — the question a friend could ask you over coffee that you’d currently answer with a shrug. Write it down now, while it still stings a little. In Week 8 you get to look at it again.
The back side is the numbers. Pick a physical constant. Give the program its measured value and the bounds of the range in which life as we know it is possible, and let it compute how much room there actually is: the width of the window, where in the window the measurement sits, and whether it’s inside at all. Then add your own study tally — how many constants are on your shortlist, and how many you’ve actually worked the numbers on rather than just read about.
Nobody on any side of the religion-and-science conversation seriously disputes that a handful of physical constants sit within extraordinarily narrow ranges, and that small changes give you a universe in which life as we know it cannot exist. What people disagree about is what to make of that. Your program will not settle it. Your program does the arithmetic and makes the numbers legible, which is the only honest thing a hundred lines of C++ can do for a fifty-year-old debate. A card that reports numbers is worth something. A card that concludes “therefore, God” in cout is worth nothing, to anybody, on either side.
The two halves belong in one file for the same reason they belong in one week. The front is input with almost no arithmetic. The back is arithmetic with almost no input. Real programs are both, and the seam between them — a value a human typed, landing in a variable of a type you chose, coming back out formatted — is exactly what Chapter 1 was about.
Coach’s Note — Build the front side first and get it printing before you touch the back. Two working halves shipped in sequence beats one ambitious half-built card every time. If Session 3 ended early for you, start the front side there; that’s the hour Session 1 borrowed.
Learning Targets
By completing this project, you will demonstrate that you can:
- Write a complete, compiling C++ program from a blank file.
- Read multi-word input with
getline, including immediately after acin >>read (thecin.ignore()boundary). - Use all five primitive types —
int,double,bool,char,string— in one program, each for a value that genuinely needs it. - Declare
constvalues and use one in arithmetic. - Do mixed
int/doublearithmetic without falling into the integer-division trap, and prove it in your own output. - Build a
boolout of comparisons and print it astrue/false. - Control number formatting with
setprecision, and decide which numbers should be formatted and which should be left alone. - Shape multi-line output on purpose with borders, labels, and alignment.
- Read your own compiler errors without panicking.
That last one is not decoration. In this course you are the only person in the room, and a compiler error you can read is a bug that costs you thirty seconds instead of an evening.
Normal Tier
Goal: One program that prompts for ten pieces of information, prints a bordered front side built from three of them, then prints a bordered back side carrying the fine-tuning arithmetic built from the other seven.
Required features
1. A reflection comment block at the very top of p1_apologist_card.cpp (exact shape in Submission).
2. Front side — three inputs, all read with getline. Every one of these can contain spaces, so cin >> is the wrong tool for all three:
- your full name
- where you’re from — a town, a home congregation, a campus, your call
- one question you want to be able to think clearly about by Week 8
3. Two const values, one of them used in arithmetic printed on the front side. For example const int WEEKS_IN_COURSE = 8; and const double HOURS_PER_WEEK = 12.0;, with the product printed as the total hours this course is asking of you. (§1.14 does this arithmetic; the answer is 96, and it is not a metaphor.) The user must not be able to type these — that’s the point of const.
4. Print the front side as a bordered panel that is:
- at least 6 lines long,
- opened and closed by identical border lines,
- carrying a title row,
- showing all three typed answers in labeled rows,
- showing the
constarithmetic from feature 3 in a labeled row.
5. Back side — seven more inputs, in this order, each into a variable of the correct type:
| Prompt | Type | Read with |
|---|---|---|
Category letter (G, C, E, N, or O) | char | cin >> |
| Constant name — spaces allowed | string | getline |
| Measured value | double | cin >> |
| Low bound of the life-permitting range | double | cin >> |
| High bound of the life-permitting range | double | cin >> |
| How many constants are on your shortlist | int | cin >> |
| How many you’ve worked the numbers on | int | cin >> |
The char read followed by a getline is deliberate. Without a cin.ignore() between them your constant name comes back empty and every row after it is wrong. §1.10 has the fix; §1.22 bug 16 has the symptom.
6. Compute these four values:
range_width = high_bound - low_bound
margin = (measured_value - low_bound) / range_width
life_permitting = (measured_value >= low_bound) && (measured_value <= high_bound)
fraction_worked = static_cast<double>(constants_worked) / constants_shortlisted
life_permitting must be a bool. fraction_worked must survive the integer-division trap.
7. Print the fraction twice. One row labeled Fraction (trap): computed as plain int / int, and one row labeled Fraction (fixed): computed with the cast. This is not busywork — it is the single most valuable two lines of output you will write this week, because you get to watch a correct program and a silently wrong one sit next to each other in your own terminal.
8. Print the back side as a bordered panel that is:
- at least 8 lines long,
- opened and closed by identical border lines,
- carrying a title row,
- labeling every input from feature 5 and every computed value from features 6 and 7,
- printing
life_permittingastrue/false, not1/0(cout << boolalpha;once near the top ofmain).
9. Format the ratios, leave the physical values alone. margin and the two fractions print with setprecision(4). The measured value, the bounds, and the range width print in C++‘s default form. Do not put fixed anywhere near the physical values — §1.18 lesson 3 shows 5.9e-39 rendering as 0.00 under fixed, which doesn’t round the number, it erases it. Remember that setprecision is sticky: once you send it, it applies to everything printed afterward. So print the physical values first, then send setprecision(4), then print the ratios.
10. Compiles cleanly with g++ -std=c++17 -Wall -Wextra p1_apologist_card.cpp -o p1_apologist_card. Zero errors, zero warnings. In OnlineGDB, -Wall -Wextra goes in the project’s compiler-flags box — Appendix A shows you where it lives.
11. It reads as one card, not two programs. The two panels should share a visual language — same border width, same label column, same left margin. A stranger should see a front and a back, not two unrelated printouts that happen to be in the same file.
Example run
This is a real session from a working solution. The text after each prompt is what the user typed; everything else is the program. The constant’s measured value and bounds are the illustrative values this book uses throughout (§1.20) — sample data for the exercise, not a scholarly citation. The 9 and 7 are one student’s own study tally.
Your full name: Marcus Aurelius Reyes
Where you're from (town or congregation): Concordia, Nebraska
One question you want to think clearly about by Week 8: Why is there anything at all instead of nothing?
+------------------------------------------------------------------+
| APOLOGIST CARD (FRONT) |
+------------------------------------------------------------------+
Name: Marcus Aurelius Reyes
From: Concordia, Nebraska
Week: 1 of 8
Training: 12 hrs/week = 96 hrs total
Question: Why is there anything at all instead of nothing?
+------------------------------------------------------------------+
Category letter (G/C/E/N/O): G
Constant name (spaces are fine): gravitational coupling
Measured value: 5.9e-39
Low bound of the life-permitting range: 1.0e-40
High bound of the life-permitting range: 1.0e-38
Constants on your shortlist: 9
How many have you worked the numbers on? 7
+------------------------------------------------------------------+
| APOLOGIST CARD (BACK) - THE NUMBERS |
+------------------------------------------------------------------+
Constant: gravitational coupling (G)
Measured value: 5.9e-39
Life range: [1e-40, 1e-38]
Range width: 9.9e-39
Life-permitting: true
Margin in range: 0.5859
Shortlist worked: 7 of 9
Fraction (trap): 0
Fraction (fixed): 0.7778
+------------------------------------------------------------------+
Your card does not have to look like this one. Wider, narrower, different border characters, different label wording, more decoration or less — all fine. What is not optional is the list of required features above, and this: read the last two data rows again. Same two integers, same division, one static_cast, and the difference between 0 and 0.7778. That is the whole reason the report half exists.
Two smaller things worth noticing in that transcript, because both are C++ telling you something. 1.0e-40 was typed and 1e-40 came back — trailing zeros are dropped on display; the value never changed. And 12 came back for 12.0 for the same reason, while 96 is a double that happens to hold a whole number.
Grading rubric — Normal (out of 100)
| Criterion | Points |
|---|---|
Compiles cleanly with g++ -std=c++17 -Wall -Wextra — zero errors, zero warnings | 10 |
Front side reads all three inputs with getline; multi-word answers arrive intact | 10 |
| Front panel: identical top/bottom borders, a title row, at least 6 lines, every input labeled | 5 |
Two const values declared, one used in the arithmetic printed on the front | 5 |
char category read with cin >>, then the multi-word constant name via getline — the cin.ignore() is present and works | 10 |
Three double inputs and two int inputs read into variables of the right type | 10 |
range_width and margin computed correctly | 10 |
life_permitting built as a bool from two comparisons and printed as true/false | 10 |
No integer-division bug — both Fraction (trap) and Fraction (fixed) printed, and the fixed one is right | 10 |
Ratios printed with setprecision(4); physical values left in default form (no fixed on them) | 5 |
| Back panel: identical top/bottom borders, a title row, at least 8 lines, every input and every computed value labeled | 5 |
| Labels aligned; the two panels read as one card rather than two programs in one file | 5 |
Link opens and runs; p1_apologist_card.cpp carries a filled-in reflection comment block | 5 |
Medium Tier (+up to 25% extra credit)
Layer these on top of a finished Normal. One feature earns partial extra credit; all three earn full Medium. Do not start Medium with a broken Normal — a finished Normal beats an abandoned Medium every time, and the rubric above is where the 100 points live.
M1. Perturb it and see what breaks
Add one more double input: a perturbation factor, a number near 1.0 (1.001 shifts the constant by one tenth of one percent). Then compute and print:
perturbed_value = measured_value * perturbation_factor
still_permitting = (perturbed_value >= low_bound) && (perturbed_value <= high_bound)
Print both, with the second as true/false. Now feed it a factor big enough to push the value out of the window and watch the boolean flip. That flip is the entire fine-tuning conversation in one line of output, and you built it.
M2. Real columns with setw
The Normal tier lets you align labels by counting spaces in string literals. That works until a value is longer than you planned. Rebuild the back side’s value column with setw(n) from <iomanip> (§1.18) so every value starts in the same column no matter how long the label or the number is.
Remember what §1.18 taught about setw: it applies to the next item only and then resets, unlike fixed and setprecision, which stick. If your third column drifts, you almost certainly sent setw once and expected it to stay.
M3. A readiness score with no if in sight
Add three more inputs — hours you actually logged this week (int), reps you actually finished (int), and whether you passed the §1.24 Checkpoint (char, y or n) — and compute a readiness score out of 100 using the boolean-as-arithmetic trick from §1.19:
int readiness = 40 * (hours_logged >= 12)
+ 30 * (reps_done >= 12)
+ 30 * (checkpoint_passed == 'y');
Each comparison is 1 or 0, so each term contributes its weight or nothing. Print the score on the front side. This is a stopgap and it is supposed to feel like one — Chapter 2 gives you if, and you should switch the moment it does. The point of writing it the awkward way once is to feel that arithmetic and logic are the same thing inside the machine.
Coach’s Note — M3 is also a small honesty test. The score is computed from numbers you type about your own week. Nobody is checking. That is exactly the situation this entire book is designed around, so notice what you type.
Hard Tier (+up to 25% additional extra credit)
Pick one. Each is worth full Hard credit on its own. Stacking is allowed and ambitious; a clean single feature beats three half-finished ones.
H1. Two constants, side by side
Read a second complete constant — category, name, measured value, both bounds — and print a comparison block with both on it. You have no arrays until Chapter 3, so you will brute-force it with a second full set of variables: constant_name_2, measured_value_2, low_bound_2, and so on.
Then add a row that names which window is narrower, using boolean arithmetic and no if:
int narrower = 1 * (range_width_1 <= range_width_2)
+ 2 * (range_width_2 < range_width_1);
Print it as Narrower window: constant #N. Note the <= on one side and the strict < on the other — that pairing is what keeps a tie from producing 3. Test it with two constants whose widths are equal and confirm you get 1, not 3.
The tedium of duplicating five variables is the lesson. That itch has a name — you want a collection — and Chapter 3 scratches it.
H2. The Week 8 card
Print a third panel after the back side: the same person’s card as it will read in Week 8. Same typed data, different framing — Week: 8 of 8, the question repeated back with a prompt to answer it now, the training total spent rather than committed. Give it a visibly different border style so nobody confuses the two.
Same variables, used again in a different shape, with the differences hard-coded. That is your first taste of reuse, and it is deliberately slightly painful: you will find yourself copying and lightly editing a dozen cout lines and wishing you could name the whole block once and call it twice. That wish is called a function. It arrives in Chapter 3.
H3. The flex move
Find one C++ feature this chapter did not cover, use it in your program, and earn it. Browser-friendly candidates that fit this project:
setfill('.')withsetwfrom<iomanip>— dot leaders between label and value, like a table of contents.leftandrightfrom<iostream>— change which sidesetwpads.scientificfrom<iostream>— force exponent notation, the third option alongsidefixedand default.constant_name.length()— astringcan tell you how long it is, which is how you’d stop a long answer from running past your border.fabs(x)from<cmath>— absolute value, so you can report how far the measurement sits from the center of the window regardless of which side it’s on.
Your reflection comment block must then answer four questions: (1) what the feature does, (2) where you found out about it, (3) why it earned a place in this program, and (4) one limitation you hit while using it. Question 4 is the one that matters. A feature you can’t name a limitation of is a feature you pasted rather than learned.
Submission
Submit one URL:
- An OnlineGDB project link (recommended). Create the project at onlinegdb.com, put
-Wall -Wextrain the compiler-flags box, build your solution, and share the link. Appendix A walks the whole workflow, including where the share button hides. - Or a public GitHub repo link, if you’ve set up a local toolchain on your own. You are responsible for the code compiling when the grader opens it.
What the linked project must contain
1. The main source file — p1_apologist_card.cpp — with your full solution.
2. A reflection comment block at the very top of that file:
/*
* Tier targeted: Normal / Medium / Hard
* Features done: list each feature you completed
* What I learned: one short paragraph (no bullets)
* What I'd change: one sentence
* AI usage: where and how, if any. Be honest.
*/
3. The program left in a demonstrable state. Your program asks for ten answers. A grader who has to guess ten answers is a grader who sees your program fail. So pre-fill OnlineGDB’s Stdin panel with your own ten answers, one per line, in the order the program asks for them — then the grader presses Run once and your card appears. The panel’s contents look like this:
Marcus Aurelius Reyes
Concordia, Nebraska
Why is there anything at all instead of nothing?
G
gravitational coupling
5.9e-39
1.0e-40
1.0e-38
9
7
Replace every line with your own. If you added Medium or Hard inputs, add their lines in the right positions.
That’s the whole submission. No demo.txt, no screenshots, no separate README. The grader opens your link, reads the comment block, presses Run, and grades against the rubric above.
Coach’s Note — You and your grader are looking at the exact same browser-hosted compiler. That’s on purpose: there is no “works on my machine” in this course, in either direction. Which also means a program that fails for the grader failed for you too — you just didn’t press Run after your last edit. Press Run after your last edit.
Hints
Read these when something specific breaks. Every symptom below is one a real Week 1 program actually produced.
“My constant name comes back empty, and every row after it is garbage.” The cin >> category left the newline you pressed sitting in the input buffer, and getline obediently read from there to the end of the line — nothing at all. One line fixes it:
cin >> category;
cin.ignore(); // eat the leftover newline
getline(cin, constant_name);
You need cin.ignore() exactly once, at the one boundary in this program where a >> read is followed by a getline. See §1.10.
“I typed a word for the category letter and the whole back side collapsed.” Real behavior, observed: type Gravity at the category prompt and cin >> category takes the G, leaving ravity in the buffer. cin.ignore() then eats the r, and getline returns avity as your constant name. Every later read is now one line out of step, and the numeric reads fail — the back side prints Measured value: 0 and Life range: [0, 0]. Type one letter at that prompt. If your output ever shows shifted-by-one values, suspect a read that consumed less than a whole line.
Worked numeric check #1 — the margin. Don’t debug margin with numbers like 5.9e-39 where you can’t tell right from wrong at a glance. Run your program once with these:
measured value = 5.0 low bound = 1.0 high bound = 11.0
Your program must print Range width: 10 and Margin in range: 0.4. Work it by hand: the window is 11 − 1 = 10 wide, the measurement sits 5 − 1 = 4 above the bottom, and 4 / 10 = 0.4. If you get 0, you have integer division somewhere in margin. If you get something else, you have a parentheses bug — measured_value - low_bound has to be computed before the division, so it needs its own parentheses.
Worked numeric check #2 — the trap. With 9 on the shortlist and 7 worked, the two fraction rows must print Fraction (trap): 0 and Fraction (fixed): 0.7778. Nothing at all versus seven ninths — same two integers, one static_cast apart.
A warning about that check. Pick integers that don’t divide evenly. Enter 8 and 8 and both rows print 1, because 8 / 8 is 1 under integer rules too. The trap is still there; it’s just hiding. Nine and seven expose it. So do four and one (0 versus 0.25).
“My margin is always 0.” Integer division, every time. Either an input you meant as a double was declared int, or you divided two ints and stored the result in a double — and §1.16 is emphatic that declaring the destination double fixes nothing. The damage happens during the division, one step before the assignment.
“5.9e-39 won’t read / comes out as 5.” Scientific notation only lands in a floating-point variable. Check that measured_value is double, not int.
“My tiny numbers print as 0.00.” You sent fixed. Take it off the physical values. fixed with two decimals is the recipe for money; for numbers with exponents in the minus-thirties it prints a zero where your data used to be (§1.18, lesson 3).
“My margin prints as 0.585859 instead of 0.5859.” That’s the default six significant digits — your setprecision(4) either never ran or ran after the line. And if the opposite happened and your measured value came out as 5.9e-39 but your range width lost digits, remember setprecision is sticky: it changes everything printed after it. Send it once, on its own line, after the physical values and before the ratios.
“My bool prints 1.” cout << boolalpha; once, near the top of main. It stays on for the rest of the program.
“My borders don’t line up.” Two fixes, and the second is better. You can count the characters by hand every time you type the border — or you can declare it once and print the variable:
string border = "+--------------------------------+";
cout << border << endl;
// ... rows ...
cout << border << endl;
One string, no arrays required, and the two borders can never disagree again. The title row still has to be counted by hand; count it once and don’t touch it.
“A long answer runs past my border.” It will. getline accepts whatever the user types, and a forty-character question printed inside a thirty-character card overflows. At Normal that is acceptable — pick a card wide enough for your own answers and move on. If it bothers you, that’s H3’s constant_name.length() waiting for you.
“When I pre-fill the Stdin panel, all my prompts print jammed together on one line.” Correct, and not a bug. Your prompts only look interleaved when a human types the answers, because the terminal is echoing what they typed. Fed from a file or a Stdin panel, nothing is echoed, so the prompts run back-to-back and the panels appear below them. Your grader knows this. Don’t restructure your program to “fix” it.
“Which errors am I likely to see?” 'setprecision' was not declared in this scope means you forgot #include <iomanip> (§1.22 bug 13) — note that fixed and boolalpha live in <iostream> and don’t need it, which is why this error shows up halfway through prettying your output. invalid conversion from 'const char*' to 'char' means you wrote category = "G" with double quotes; a char takes single quotes (§1.22 bug 7).
“How long should this take?” Normal: 4–6 hours, including the debugging, if you did the reps. Medium: 6–8 total. Hard: 8–10 total. If Normal is taking you past eight hours, stop coding and go re-run the §1.24 Checkpoint — the fastest fix for a project that won’t come together is usually a missing rep, not another hour of staring. If Normal took you ninety minutes, re-read the required-features list; something is missing.
What Mastery Looks Like
The rubric tells you what to do. Here’s what to aim for.
A great Project 1 is specific. Your actual name, your actual town, your actual question. Not Name: Student. Not Question: How do I know God exists? if the real one is Why did my grandmother's cancer not get healed?. The grader can tell, and more importantly your Week 8 self can tell. The card is only worth building if it’s honest.
A great Project 1 has killed the integer-division trap dead. You can look at any line in your program and say what type each intermediate value is and where the promotion happens. You didn’t sprinkle static_cast<double> everywhere hoping something would stick — you cast in exactly one place, on purpose, and you can explain why that place and not another.
A great Project 1 makes a formatting decision. The ratios are rounded because a human reads them; the physical values aren’t because rounding them would destroy them. If someone asks why margin got setprecision(4) and measured_value didn’t, you have an answer, and it isn’t “it looked better.”
A great Project 1 is readable out loud. Your .cpp file, not your output. A grader reading your source should be able to predict the shape of the card before pressing Run. That is what clean code feels like from the outside.
A great Project 1 doesn’t oversell itself. The back side reports numbers. It does not conclude. The numbers, made legible, can speak to a reader willing to think about them — and a reader who isn’t won’t be moved by a cout statement. Let the program be a calculator and let you be the apologist.
When You’re Done
- Read
p1_apologist_card.cppout loud, slowly. Listen to the types. Every line where a number is created, say the type out loud. The line where you hesitate is the line to look at. - Run it three times, with three different sets of inputs — one measurement clearly inside the window, one clearly above the high bound, one clearly below the low bound.
life_permittingmust readtrue,false,false. If it doesn’t, your comparison chain is wrong, not your printing. - Run worked check #1 from the Hints (
5.0,1.0,11.0→0.4) one final time. It takes twenty seconds and it is the single check most likely to catch the bug that would have cost you ten rubric points. - Fill in the reflection comment block honestly — the real tier, the real features, the real AI usage. It is the one part of this submission nobody can verify, which is precisely what makes it worth something.
- Pre-fill the Stdin panel, press Run one last time, and submit the link.
- Then open Chapter 2. Your programs are about to start making decisions and doing things more than once.
Coach’s Note — No one is going to walk past your desk and tell you this one is good. That’s the deal in an online course, and it cuts both ways: nobody catches you slipping, and nobody hands you the confidence either. So build the habit now of being your own first grader. Read it out loud. Run the checks. Decide for yourself whether it’s finished — and then believe your own verdict, because for the next eight weeks it’s the only one you’ll have before the grade posts.
Whatever hour it is where you are: you made a machine talk, listen, remember, and do arithmetic you can trust. That’s the first pillar, whole. Close the laptop.