# Introduction to Computer Programming

## Program 2: Simple game REPL

### Due date: Friday, September 29 at 5pm

#### Instructions

• Before proceeding - read this entire document (and the entire stub file) thoroughly!
• Unless otherwise indicated, use only the Python operations and commands we have been using thus far in class and lab - see guidelines.
• Start by working with the supplied starter file, but save the file as `hw2_*yourusername*.py` where yourusername is your `@gm.slc.edu` username.
• Replace `<YOUR NAME GOES HERE>` with your name.
• Fill in all the areas of the supplied file marked by "...".
• As mentioned above, name your file `hw1_*yourusername*.py` where yourusername is your `@gm.slc.edu` username. (If your email was `msiff@gm.slc.edu`, you would name your file `hw1_msiff.py`.)
• When ready to submit your work, reply to email from the instructor the announcing the assignment (it should have the subject: `ICP17: Programming Assignment 2`) and attach the one file. (Do not paste the contents of the file into the body of the message. Do not expect the instructor to read anything in the body of the message. The instructor will only examine the attached file.)
• You are welcome (encouraged) to download a runnable solution module called `hw2x`. If you place that file in the same folder as the file you are working in, then from the IDLE prompt (`>>>`) you can `import` the solution module to see it in action. For example:

``````>>> import hw2x
>>> hw2x.get_board_size()

Choose the number of columns. Enter a value between 5 and 40: 7
Choose the number of rows. Enter a value between 3 and 25: 999
999 is out of range. Please try again.
Enter a value between 3 and 25: 5
(7, 5)``````

#### Guidelines

Unless explicitly indicated otherwise:

• You are welcome to use string multiplication and these string methods:

``lower   upper   isupper   islower   isalpha   isdigit``
• You may use tuples - specifically, pairs.

• When writing fruitful functions, use only one `return` statement in a function and make it the last statement of that function.

### The assignment itself

1. Complete function `char_to_int(c)` so that it returns a number between 0 and 9 corresponding to the character `c` assuming it is one of `'0'`, `'1'`, or ... `'9'`; if not, it returns `None`. Do not use the `int()` function (you are welcome to use the `isdigit()` method). Examples:

``````>>> char_to_int('0')
0
>>> char_to_int('9')
9
>>> char_to_int('x') is None
True
>>> char_to_int('43') is None
True``````
2. Complete `string_to_int(s)` so that it returns a nonnegative integer corresponding to the string `s` assuming it consists entirely of the digits `'0'`, `'1'`, or ... `'9'`; if not, it returns `None`. Examples:

``````>>> string_to_int('0')
0
>>> string_to_int('41933')
41933
>>> string_to_int('000041933')     # leading 0s are ok
41933
>>> string_to_int('-1') is None    # minus sign not allowed
True
>>> string_to_int('3.14') is None
True
>>> string_to_int('5x7') is None
True
>>> string_to_int('') is None
True``````
3. Complete `read_number_in_range(start, stop)` so that it returns a number between `start` (inclusive) and `stop` (exclusive) by repeatedly prompting the user for such a number until a valid one is provided. Example:

``````>>> read_number_in_range(5, 12)
Enter a value between 5 and 12: 19
19 is out of range. Please try again.
Enter a value between 5 and 12: x
x is not a number. Please try again.
Enter a value between 5 and 12: 3
3 is out of range. Please try again.
Enter a value between 5 and 12: 10
10``````
4. Fix `get_board_size()` so that it matches its specification: namely so that it returns column and row dimensions (as a pair of numbers) for the game board after asking for them via user input. It should verify that the dimensions are within the ranges specified by the `MIN`/`MAX` constants. Example:

``````>>> get_board_size()

Choose the number of columns. Enter a value between 5 and 40: 4
4 is out of range. Please try again.
Enter a value between 5 and 40: 40
40 is out of range. Please try again.
Enter a value between 5 and 40: hello
"hello" is not a valid number. Please try again.
Enter a value between 5 and 40: 35
Choose the number of rows. Enter a value between 3 and 25: -33
"-33" is not a valid number. Please try again.
Enter a value between 3 and 25: 14
(35, 14)``````
5. Add an option to the main REPL so that the `help` command triggers the `help()` function to be called to generate the REPL response.

6. Add an option to the main REPL so that if the users requests `status`, `status_check(...)` is called to generate the REPL response.

7. Complete `normalize_action(action)` so it returns a string that represents a normalization of the action string. This should allow for case insensitivity and single-letter abbreviations. Examples:

`````` >>> normalize_action('East')
'east'
>>> normalize_action('e')
'east'
>>> normalize_action('STATUS')
'status'
>>> normalize_action('H')
'help'
>>> normalize_action('WhatEver')   # if action not valid command, still lowercased
'whatever'``````
8. Complete `request_yes(prompt)` that returns `True` if the user, given the string prompt, inputs `yes` or `y` (case insensitive). Returns `False` if the user enters `no` (or `n`, case insensitive). Repeats the request for user input until a valid yes or no is supplied. Examples:

``````>>> request_yes('Keep playing? ')
Keep playing? what?
Enter "yes" or "no".
Keep playing? ok
Enter "yes" or "no".
Keep playing? n
False
>>> request_yes('Need help? ')
Need help? who me?
Enter "yes" or "no".
Need help? YES
True``````
9. Fix `welcome` so that it matches its specification. Examples:

``````>>> welcome()
Welcome to Find the Flag!

Would you like to see the instructions? what?
Enter "yes" or "no".
Would you like to see the instructions? n

>>> welcome()
Welcome to Find the Flag!

Would you like to see the instructions? yes

Your goal is to find the flag hidden on one cell of an invisible
grid in as few moves as possible.

At the outset of the game...``````
10. Modify the main REPL so that the cardinal direction actions work: namely, moving east, north, south or west, moves the player's row and column one position at a time. Be sure to only allow the move if the coordinates remain within the bounds of the game board. If a move is successful, the move counter should be increased by 1. Examples:

``````%> e
ok.

%> s
ok.

%> status
You are at row 5 and column 4.
You are 5 units from the flag.
You have made 2 moves so far.

%> s
ok.

%> status
You are at row 6 and column 4.
You are 6 units from the flag.
You have made 3 moves so far.

%> s
You cannot go that way.

%> status
You are at row 6 and column 4.
You are 6 units from the flag.
You have made 3 moves so far.``````
11. Use the `random.randrange(...)` function to introduce randomness so that:

1. the player's initial position is a random row and column within the range allowed by the game constants `MIN_ROW`, etc.
2. the flag position is a random row and column, but such that it is at least `MIN_DISTANCE` away from the player's starting position. (Hint: use a while loop until the distance requirement is satisfied.)
12. Implement winning: if the player reaches the flag, the game ends. For example:

``````%> n
Congratulations, you have captured the flag!
You played a total of 5 moves.
Thank you for playing.``````
13. Implement losing: if the player fails to reach the flag before `max_moves` are exhausted, the game ends. The maximum number of moves can be computed in relation to the size of the board (you can choose precisely what that relation is). An example of losing:

``````%> s
Unfortunately, you have run out of time.
You played a total of 8 moves.
Thank you for playing.``````
14. Add warmer/colder hints for the player so that when they move if they are getting closer to the flag they receive a "warmer" response, away from the flag, a "colder" response. Examples:

``````%> e
Warmer!
%> s
Warmer!
%> s
Colder.
%> w
Colder.
%> e
Warmer!
%> e
Warmer!
%> e
Warmer!
%> n
Congratulations, you have captured the flag!
You played a total of 8 moves.
Thank you for playing.``````

#### Extra credit

Implement functions `scan_row`, `scan_column` and `scan_board` according to their specification. Be sure to make each of them count for more than one move (otherwise the game is too easy to play)