Skip to content

Commit 50fa361

Browse files
committed
Updated unit tests, README, and Vignette
Changes: - Added unit tests for app.R - Updated README file - Updated Vignette
1 parent 866ed53 commit 50fa361

12 files changed

Lines changed: 154 additions & 79 deletions

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ RoxygenNote: 7.3.3
2121
Imports:
2222
checkmate (>= 2.3.4),
2323
shiny (>= 1.13.0)
24-
Suggests:
24+
Suggests:
2525
knitr,
2626
rmarkdown,
2727
shinytest2,

R/app.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,13 @@ server <- function(input, output, session) {
328328
# Print win or loss message in large bold text
329329
tagList(if (is_winner(picked(), sequence())) {
330330
p("You won! That was the highest number.",
331-
style = "font-size: 20px; font-weight: bold;")
331+
style = "font-size: 20px; font-weight: bold; color: #28a745;")
332332
} else {
333333
p(paste("You lost! The highest number was", max_label),
334-
style = "font-size: 20px; font-weight: bold;")
334+
style = "font-size: 20px; font-weight: bold; color: #dc3545;")
335335
},
336336
# Add action button to restart the game
337-
actionButton("restart", "Play again"))
337+
div(style = "text-align: center;", actionButton("restart", "Play again")))
338338
})
339339

340340
# Reset all game state when the player clicks Play again, returning to setup.

README.md

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,43 @@
11
# GoogolGame
2-
Play the googol game to explore the theory of optimal stopping or use it as a task in your research!
3-
4-
In the coming weeks I want to create an application that allows users to play the googol game (also known as secretary problem, marriage problem, and more).
5-
The googol game demonstrates a scenario involving optimal stopping theory.
6-
7-
The basic idea is simple: a set of cards (e.g. 10) each contains a random number between zero and infinity. The cards are shuffled, placed face down in a line, and revealed one at a time. After each reveal, the player must decide whether to stop or continue searching for a higher number. Once a card is passed, the player cannot return to it later. The goal is to stop on the highest number in the deck.
8-
9-
My application will allow players to use card sets of different sizes, with values either entered manually or generated randomly.
10-
The game can be used to explore optimal stopping theory and may also have applications in research or education.
112

123
<!-- badges: start -->
134
[![R-CMD-check](https://github.com/Programming-The-Next-Step-2026/GoogolGame/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/Programming-The-Next-Step-2026/GoogolGame/actions/workflows/R-CMD-check.yaml)
145
<!-- badges: end -->
6+
7+
## Do You Know This Problem?
8+
9+
You just finished your workout and it's time to shower. But first — that email you've been putting off all day. Then the dishes, and the floor isn't going to vacuum itself. After all that housework you deserve a little reward, so you sit down to finish your favourite series. By now the sweat has long dried, so it barely matters anyway. And it's late and your roommates are asleep, so it would be rude to shower. And you were planning to work out again tomorrow anyways — so what's the point of showering at all? You could go on like this forever.
10+
11+
The question is: **when is the right moment**? To stop and say: now I decide to do it?
12+
13+
To take the shower, to take out the trash, or to pick the card with the highest number…
14+
15+
The card with the highest number, you ask? The idea comes from Martin Gardner who first described a gambling game called Googol.
16+
17+
## What is the Googol Game?
18+
19+
The Googol Game demonstrates optimal stopping theory. The rules are simple: Player 1 writes any numbers they like on a set of cards, then turns them face down and shuffles them. Player 2 turns over one card at a time and must decide when to stop — betting that the current card is the highest. Crucially, you cannot go back. If you pass a card, it's gone.
20+
21+
Is there an optimal point to stop?
22+
23+
Explore this question with the Googol Game app!
24+
25+
## Installation
26+
27+
```r
28+
# install.packages("devtools")
29+
devtools::install_github("Programming-The-Next-Step-2026/GoogolGame")
30+
```
31+
32+
## Usage
33+
34+
```r
35+
GoogolGame::play_googol()
36+
```
37+
38+
## Features
39+
40+
- **Random mode**: the app generates a sequence of numbers across a wide range of scales — from small integers up to Googol-sized values (e.g. "3 Million", "7 Googol").
41+
- **Manual mode**: enter your own numbers one at a time using a base value and a multiplier (None, Million, Billion, Trillion, Googol).
42+
- Players can reveal cards one at a time and decide to stop if they think they found the highest number.
43+
- Win and loss messages are displayed, with an option to play again.

tests/testthat/test-app.R

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,8 @@ test_that("app loads on setup page", {
88
app$stop()
99
})
1010

11-
# # 2. Random mode: Start switches to game page
12-
# test_that("random mode Start switches to game page", {
13-
# app <- AppDriver$new(play_googol())
14-
# app$set_inputs(mode = "random", n_cards = 3)
15-
# app$click("start")
16-
# app$wait_for_idle()
17-
# # Reveal first card so the Pick button appears
18-
# app$click("next_card")
19-
# app$wait_for_idle()
20-
# expect_true("pick" %in% names(app$get_values()$input))
21-
# app$stop()
22-
# })
23-
#
24-
# # 3. Pick switches to result page
25-
# test_that("Pick switches to result page", {
26-
# app <- AppDriver$new(play_googol())
27-
# app$set_inputs(mode = "random", n_cards = 3)
28-
# app$click("start")
29-
# app$wait_for_idle()
30-
# app$click("next_card")
31-
# app$wait_for_idle()
32-
# app$click("pick")
33-
# app$wait_for_idle()
34-
# expect_true("restart" %in% names(app$get_values()$input))
35-
# app$stop()
36-
# })
37-
#
38-
# # 4. Play again returns to setup
39-
# test_that("Play again returns to setup page", {
40-
# app <- AppDriver$new(play_googol())
41-
# app$set_inputs(mode = "random", n_cards = 3)
42-
# app$click("start")
43-
# app$wait_for_idle()
44-
# app$click("next_card")
45-
# app$wait_for_idle()
46-
# app$click("pick")
47-
# app$wait_for_idle()
48-
# app$click("restart")
49-
# app$wait_for_idle()
50-
# expect_true("start" %in% names(app$get_values()$input))
51-
# app$stop()
52-
# })
53-
54-
# 5. Manual mode with valid numbers starts game
55-
test_that("manual mode with valid numbers starts game", {
11+
# 2. Start switches to game page
12+
test_that("Start switches to game page", {
5613
app <- AppDriver$new(play_googol())
5714
app$set_inputs(mode = "manual", number_1 = 100, multiplier_1 = "None")
5815
app$click("add_row")
@@ -67,7 +24,43 @@ test_that("manual mode with valid numbers starts game", {
6724
app$stop()
6825
})
6926

70-
# 6. Manual mode with invalid entry (i.e. only 1 number) shows an error and stays on setup
27+
# 3. Pick switches to result page
28+
test_that("Pick switches to result page", {
29+
app <- AppDriver$new(play_googol())
30+
app$set_inputs(mode = "manual", number_1 = 100, multiplier_1 = "None")
31+
app$click("add_row")
32+
app$wait_for_idle()
33+
app$set_inputs(number_2 = 500, multiplier_2 = "None")
34+
app$click("start")
35+
app$wait_for_idle()
36+
app$click("next_card")
37+
app$wait_for_idle()
38+
app$click("pick")
39+
app$wait_for_idle()
40+
expect_true("restart" %in% names(app$get_values()$input))
41+
app$stop()
42+
})
43+
44+
# 4. Play again returns to setup
45+
test_that("Play again returns to setup page", {
46+
app <- AppDriver$new(play_googol())
47+
app$set_inputs(mode = "manual", number_1 = 100, multiplier_1 = "None")
48+
app$click("add_row")
49+
app$wait_for_idle()
50+
app$set_inputs(number_2 = 500, multiplier_2 = "None")
51+
app$click("start")
52+
app$wait_for_idle()
53+
app$click("next_card")
54+
app$wait_for_idle()
55+
app$click("pick")
56+
app$wait_for_idle()
57+
app$click("restart")
58+
app$wait_for_idle()
59+
expect_true("start" %in% names(app$get_values()$input))
60+
app$stop()
61+
})
62+
63+
# 5. Manual mode with invalid entry (i.e. only 1 number) shows an error and stays on setup
7164
test_that("manual mode with invalid entry shows error and stays on setup page", {
7265
app <- AppDriver$new(play_googol())
7366
app$set_inputs(mode = "manual", number_1 = 100, multiplier_1 = "None")

vignettes/how-to-use-the-googol-game-app.Rmd

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,61 +14,114 @@ knitr::opts_chunk$set(
1414
)
1515
```
1616

17-
```{r setup}
18-
library(GoogolGame)
19-
```
20-
2117
## What is the Googol Game?
2218

23-
The Googol Game is based on the mathematical Secretary Problem. A sequence of
24-
numbers is revealed one at a time. Your goal is to pick the highest number in
19+
The Googol Game is a gambling problem first described by Martin Gardner. A sequence
20+
of numbers is revealed one at a time. Your goal is to pick the highest number in
2521
the sequence — but once you pass a number, you cannot go back. You win only if
2622
the number you pick turns out to be the highest in the entire sequence,
2723
including numbers you never saw.
2824

25+
## How to install the app
26+
27+
```{r, eval = FALSE}
28+
# install.packages("devtools")
29+
devtools::install_github("Programming-The-Next-Step-2026/GoogolGame")
30+
```
31+
2932
## How to launch the app
3033

3134
```{r, eval = FALSE}
35+
library(GoogolGame)
3236
play_googol()
3337
```
3438

35-
## Step-by-step instructions
39+
## Scenario
40+
41+
**Purpose**: scenario that describes how to use the GoogolGame app.
42+
43+
**User**: everybody that is interested in the Googol Game or optimal stopping theory.
44+
It is especially fun if you play it together with a second person!
45+
46+
**Equipment**: any computer with a supported browser. You must have installed R. All
47+
other dependencies will be installed automatically when downloading the package.
3648

37-
### Step 1: Choose a sequence type
49+
**Scenario**:
50+
51+
**Step 1: Choose a sequence type**
3852

3953
When the app opens, choose how to generate the sequence of numbers:
4054

4155
- **Random**: the app generates a sequence of random numbers for you. Enter
42-
how many cards you want and click **Start game**.
56+
how many cards you want (e.g. 3) and click **Start game**.
57+
58+
<img src="images/random_generation.png" width="100%" />
59+
4360
- **Manual**: enter your own numbers one at a time. For each number, type a
4461
value and optionally select a multiplier (e.g. select `2` and `Googol` to
4562
enter 2 Googol). Click **Add number** to add another number. You need at
46-
least 2 numbers and you can add as many numbers as you want.
63+
least 2 numbers and you can add as many numbers as you want.
64+
65+
<img src="images/manual_generation.png" width="100%" />
66+
4767
**Note**: manual entry requires a second person — one who enters the numbers
4868
and one who plays the game! Hand the keyboard to a friend to enter the
49-
numbers and don't peek at the screen ;)
69+
numbers and don't peek at the screen.
70+
71+
**Step 2: Play the game**
5072

51-
### Step 2: Play the game
73+
After clicking **Start game**, all cards are shown face-down in blue. Click
74+
**Reveal first card** to turn over the first card.
5275

53-
After clicking **Start game**, the cards are revealed one at a time:
76+
<img src="images/reveal_first_card.png" width="100%" />
5477

55-
- Cards you have already seen are shown with their number.
56-
- The current card shows its number and is the one you can pick.
57-
- Cards not yet revealed are shown as `?`.
78+
From there, after each reveal you have two choices:
5879

59-
At each card you have two choices:
80+
- Click **Pick this number** if you think the current card (highlighted in
81+
green) is the highest.
82+
- Click **Next** to pass it and reveal the next card. Passed cards turn grey.
6083

61-
- Click **Pick this number** to select the current card as your answer.
62-
- Click **Next** to pass and reveal the next card.
84+
<img src="images/next_or_pick.png" width="100%" />
6385

6486
On the last card, only **Pick this number** is available — you must pick.
6587

66-
### Step 3: See the result
88+
<img src="images/pick_this_number.png" width="100%" />
89+
90+
**Step 3: See the result**
6791

6892
After picking, the app shows whether you won or lost:
6993

7094
- **Win**: your chosen number was the highest in the sequence.
7195
- **Loss**: a higher number existed elsewhere in the sequence, along with what
7296
that number was.
7397

98+
<img src="images/win_or_loss.png" width="100%" />
99+
74100
Click **Play again** to return to the setup page and start a new game.
101+
102+
## Flowchart
103+
104+
The flowchart below shows the full flow of the app, distinguishing between
105+
user actions and the software functions triggered behind the scenes.
106+
107+
**Colours**: <span style="color:#2c7be5">■</span> blue = user action,
108+
<span style="color:#28a745">■</span> green = software action.
109+
110+
<img src="images/flowchart.png" width="80%" />
111+
112+
## Extra: optimal stopping theory
113+
114+
Is there a strategy that maximises your chances of picking the highest number?
115+
Yes — and the answer comes from mathematics.
116+
117+
The optimal strategy is to let the first 37% of cards pass without
118+
picking, no matter how high they are. After that, pick the next card that is
119+
higher than all the cards you have already seen. If no such card appears, pick
120+
the last card.
121+
122+
This strategy gives you approximately a 37% chance of picking the highest
123+
number, regardless of how many cards there are. Remarkably, no other strategy
124+
can do better in the long run.
125+
126+
Try it out: with 10 cards, skip the first 3 or 4 and then pick the next card
127+
that beats them all.

vignettes/images/flowchart.png

291 KB
Loading
34.6 KB
Loading

vignettes/images/next_or_pick.png

9.13 KB
Loading
10.3 KB
Loading
12.3 KB
Loading

0 commit comments

Comments
 (0)