add hw-3 hw-4 hw-5

This commit is contained in:
JamesFlare1212
2024-03-13 15:55:10 -04:00
parent c53391f4b6
commit 3b6a0249bb
12 changed files with 2595 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,435 @@
---
title: CSCI 1100 - Homework 3 - Loops, Tuples, Lists, and Ifs
subtitle:
date: 2024-03-13T14:28:32-04:00
slug: csci-1100-hw-3
draft: false
author:
name: James
link: https://www.jamesflare.com
email:
avatar: /site-logo.avif
description: This homework assignment focuses on working with lists, loops, tuples, and if statements in Python. It includes three parts - analyzing text complexity, simulating Pikachu's movement, and modeling population changes of bears, berries, and tourists.
keywords: ["Python","loops","tuples","lists","if statements"]
license:
comment: true
weight: 0
tags:
- CSCI 1100
- Homework
- RPI
- Python
- Programming
categories:
- Programming
collections:
- CSCI 1100
hiddenFromHomePage: false
hiddenFromSearch: false
hiddenFromRss: false
hiddenFromRelated: false
summary: This homework assignment focuses on working with lists, loops, tuples, and if statements in Python. It includes three parts - analyzing text complexity, simulating Pikachu's movement, and modeling population changes of bears, berries, and tourists.
resources:
- name: featured-image
src: featured-image.jpg
- name: featured-image-preview
src: featured-image-preview.jpg
toc: true
math: false
lightgallery: false
password:
message:
repost:
enable: true
url:
# See details front matter: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter
---
<!--more-->
## Overview
This homework is worth 100 points toward your overall homework grade, and is due Thursday, February 15th, 2024 at 11:59:59 pm. You have 1 week to finish this assignment.
The goal of this assignment is to work with lists, loops, tuples and use if statements. As your programs get longer, you will need to develop some strategies for testing your code. Here are a few simple ones: start testing early, and test small parts of your program by writing a little bit and testing. We will walk you through program construction in the homework description and provide some ideas for testing.
As always, make sure you follow the program structure guidelines. You will be graded on program correctness as well as good program structure. This includes comments. Minimally, we expect a brief docstring comment block at the start of the submission detailing the purpose and a brief summary (you may also include additional information like your name and date); and docstring comments for each function you define detailing the purpose, inputs, and expected return values. Additional comments have to accompany any complicated sections of your code.
## Fair Warning About Excess Collaboration
Please remember to abide by the Collaboration Policy you were given last assignment. It remains in force for this and all assignments this semester. We will be using software that compares all submitted programs, looking for inappropriate similarities. This handles a wide variety of differences between programs, so that if you either (a) took someone elses program, modified it (or not), and submitted it as your own, (b) wrote a single program with one or more colleagues and submitted modified versions separately as your own work, or (c) submitted (perhaps slightly modified) software submitted in a previous year as your software, this software will mark these submissions as very similar. All of (a), (b), and (c) are beyond what is acceptable in this course — they are violations of the academic integrity policy. Furthermore, this type of copying will prevent you from learning how to solve problems and will hurt you in the long run. The more you write your own code, the more you learn.
Make sure that you have read the Collaboration Policy for acceptable levels of collaboration and so you know how you can protect yourself. The document can be found on the Course Materials page on Submitty. Penalties for excess collaboration can be as high as:
- 0 on the homework, and
- an additional overall 5% reduction on the semester grade.
Penalized students will also be prevented from dropping the course. More severe violations, such as stealing someone elses code, will lead to an automatic F in the course. A student caught in a second academic integrity violation will receive an automatic F.
By submitting your homework you are asserting that you both (a) understand the academic integrity policy and (b) have not violated it.
Finally, please note that this policy is in place for the small percentage of problems that will arise in this course. Students who follow the strategies outlined above and use common sense in doing so will not have any trouble with academic integrity.
## Part 1: How complex is the language used in the text? (40 pts)
Create a folder for HW 3. Download the zip file `hw3_files.zip` from the Course Materials on Submitty. Put it in this folder and unzip it. You should see a file named `syllables.py` which will be a helper module for this homework. Write your program in the same folder as this file and name it `hw3_part1.py`.
A few things to get familiar with before solving this part.
In this part, you must get familiar with a function called `.split()` that takes a piece of text, and converts it to a list of strings. Here is an example run:
```python
>>> line = "Citadel Morning News. News about the Citadel in the morning, pretty self explanatory."
>>> m = line.split()
>>> m
['Citadel', 'Morning', 'News.', 'News', 'about', 'the', 'Citadel', 'in', 'the', 'morning,', 'pretty', 'self', 'explanatory.']
```
You will also need to use the function `find_num_syllables()` from the file `syllables.py` which takes as input an English word as a string and that returns the total number of syllables in that word as an integer. The module works even if the word has punctuation symbols, so you do not need to remove those explicitly. Make sure you import this module appropriately into your program.
```python
>>> find_num_syllables('computer')
3
>>> find_num_syllables('science')
1
>>> find_num_syllables('introduction')
4
```
Clearly, the second result is incorrect. The module we provided is not a perfect implementation of syllable counting, so you may find errors. It is not your job to fix them, use the module as it is, with errors and all. Do not worry about the mistakes it makes. To properly compute this, we would need to use a Natural Language Processing (NLP) module like NLTK, which we have not installed in this course.
### Problem specification
In this part, you will read a paragraph containing multiple English sentences as text from the user. Assume a period marks the end of a sentence. Read the paragraph as a single (long) line of text. Compute and print the following measures corresponding to the overall readability of this text.
- ASL (average sentence length) is given by the number of words per sentence. Print ASL.
- PHW (percent hard words): To compute this first count the number of words of three or more syllables that do not contain a hyphen (-) and three-syllable words that do not end with 'es' or 'ed'. Divide this count by the total number of words in the text and multiply the result by 100 to get a percentage. Print PHW.
- Collect all words that are used in the PHW computation in a list exactly as they appear in the input, and print this list.
- ASYL (average number of syllables) is given by the total number of syllables divided by the total number of words. Print ASYL.
- GFRI is given by the formula 0.4*(ASL + PHW). Print GFRI.
- FKRI is given by the formula 206.835-1.015*ASL-86.4*ASYL. Print FKRI.
Note that the measures GFRI and FKRI are slightly modified versions of well-known readability measures named Gunning-Fog and Flesch Kincaid. In Gunning-fog, the higher the value calculated, the more difficult it is to read a text. For Flesch Kincaid it is the opposite with higher values indicating more easily read text.
You can find example runs of the program in `hw3_part1_01.txt` and `hw3_part1_02.txt` from `hw3_files.zip`.
When you are finished, submit your program to Submitty as `hw3_part1.py`. You must use this filename, or your submission will not work in Submitty. You do not have to submit any of the files we have provided.
## Part 2: Pikachu in the Wild! (40 pts)
Suppose you have a Pikachu that is standing in the middle of an image, at coordinates (75, 75). Assume the top left corner of the board is (0,0) like in an image.
We are going to walk a Pikachu around the image looking for other Pokemon. This is a type of simple simulation. First, we will set the parameters of the simulation by asking the user for the number of turns, to run the simulation (starting at turn 0), the name, of your Pikachu and how often, we run into another Pokemon. At this point we enter a simulation loop (while). Your Pikachu walks 5 steps per turn in one of (N)orth, (S)outh, (E)ast or (W)est. Every turn, ask the user for a direction for your Pikachu to walk and move your Pikachu in that direction. You should ignore directions other than N, S, E, W. Every often turns, you meet another Pokemon. Ask the user for a type ((G)round or (W)ater). If it is a ground type, 'G', your Pikachu loses. It turns and runs 10 steps in the direction opposite to the direction in which it was moving before it saw another Pokemon. (If the last direction was not a valid direction, your Pikachu doesnt move.) If it is a water type, 'W', your Pikachu wins and takes 1 step forward. Anything else means you did not actually see another Pokemon. Keep track of wins, losses, and "No Pokemon" in a list.
At the end of turn turns report on where your Pikachu ended up and print out its record.
You must implement at least one function for this program:
```python
move_pokemon((row, column), direction, steps)
```
That returns the next location of the Pikachu as a (row, column) tuple. There is a fence along the boundary of the image. No coordinate can be less than 0 or greater than 150. 0 and 150 are allowed. Make sure your `move_pokemon()` function does not return positions outside of this range.
You can use the following code to test your `move_pokemon()` function. Feel free to write other functions if you want, but be sure to test them to make sure they work as expected!
```python
from hw3_part2 import move_pokemon
row = 15
column = 10
print(move_pokemon((row, column), 'n', 20)) # should print (0, 10)
print(move_pokemon((row, column), 'e', 20)) # should print (15, 30)
print(move_pokemon((row, column), 's', 20)) # should print (35, 10)
print(move_pokemon((row, column), 'w', 20)) # should print (15, 0)
row = 135
column = 140
print(move_pokemon((row, column), 'N', 20)) # should print (115, 140)
print(move_pokemon((row, column), 'E', 20)) # should print (135, 150)
print(move_pokemon((row, column), 'S', 20)) # should print (150, 140)
print(move_pokemon((row, column), 'W', 20)) # should print (135, 120)
```
Now, write some code that will call these functions for each command entered and update the location of the Pikachu accordingly.
Two examples of the program run (how it will look when you run it using Spyder IDE) are provided in files `hw3_part2_01.txt` and `hw3_part2_02.txt` (can be found inside the `hw03_files.zip` file). In `hw3_part2_01.txt`, note that `f` is an invalid direction, so it has no effect on the Pikachus state, and `r` is an invalid Pokemon type which gets flagged as a "No Pokemon" in the results list.
We will test your code with the values from the example files as well as a range of other values. Test your code well and when you are sure that it works, please submit it as a file named `hw3_part2.py` to Submitty for Part 2 of the homework.
## Part 3: Population Change — with Bears (20 pts)
You are going to write a program to compute a type of population balance problem similar to the bunnies and foxes you computed in Lab 3. This problem will have bears, berry fields, and tourists. We will just use the word berries to mean the area of the berry fields. We will count the number of bears and tourists, as well.
Bears need a lot of berries to survive and get ready for winter. So the area of berry fields is a very important part for their population. Berry fields in general spread over time, but if they are trampled too heavily by bears, then they may stop growing and may reduce in size. Tourists are the worst enemy of bears, often habituating them to humans and causing aggressive behavior. Sadly, this can lead to bears being killed to avoid risk to human life.
Here is how the population of each group is linked to one another from one year to the next. Suppose the variable `bears` stores the number of bears in a given year and `berries` stores the area of the berry fields.
- The number of tourists in a given year is determined as follows. If there are less than 4 or more than 15 bears, there are no tourists. It is either not interesting enough or too dangerous for them. In other cases, there are 10,000 tourists for each bear up to and including 10 and then 20,000 tourists for each additional bear. It is a great idea to write a function for computing tourists and test it separately.
- The number of bears and berries in the next year is determined by the following formulas given the population of bears, berries, and tourists in the given year:
```python
bears_next = berries/(50*(bears+1)) + bears*0.60 - (math.log(1+tourists,10)*0.1)
berries_next = (berries*1.5) - (bears+1)*(berries/14) - (math.log(1+tourists,10)*0.05)
```
Remember none of these values can end up being negative. Negative values should be clipped to zero. Also, bears and tourists are integers. The `log` function is in the `math` module.
You must write a function that takes as input the number of bears, berries, and tourists in a given year and returns the next years bears population and berry field area as a tuple.
```python
>>> find_next(5, 1000, 40000)
(5, 1071.1984678861438)
```
Then write the main program that reads two values, the current population of bears, and the area of berry fields. Your program then finds and prints the population of all three groups (bears, berries, and tourists) for the first year and another 9 years (10 years total). You must use a loop to do this. The output is formatted such that all values are printed in columns and are aligned to the left within each column. The width of each column is exactly 10 characters (padded with spaces, if necessary). All floating point values need to be printed with exactly one decimal place.
Once completed, your program should output: the smallest and largest values of the population of bears, berries, and tourists reached in your computation. These values should be output using the same formatting rules as for the population values for each of the years.
An example of the program run how it will look when you run it using the Spyder IDE is provided in file `hw3_part3_01.txt` (can be found inside the `hw03_files.zip` file). Note that the number of bears may go down to zero and then come back up. Why? Bears from neighboring areas can move in. The min and max values for each of bears, berries, and tourists may come from different years.
We will test your code with the values from the example file as well as a range of other values. Test your code well and when you are sure that it works, please submit it as a file named `hw3_part3.py` to Submitty for Part 3 of the homework.
## Supporting Files
{{< link href="HW3.zip" content="HW3.zip" title="Download HW3.zip" download="HW3.zip" card=true >}}
## Solutions
### hw3_part1.py
```python
import syllables
#user_input = "We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness."
#user_input = "There is a theory which states that if ever anyone discovers exactly what the Universe is for and why it is here, it will instantly disappear and be replaced by something even more bizarre and inexplicable. There is another theory which states that this has already happened."
user_input = str(input("Enter a paragraph => ")).strip()
print(user_input)
# Calculate ASL
sentences = user_input.split(". ")
words_per_sentence = []
#print(sentences)
for sentence in sentences:
words = sentence.split()
words_per_sentence.append(len(words))
asl = sum(words_per_sentence) / len(words_per_sentence)
#print(asl)
# Calculate PHW
words = user_input.split()
#print(len(words))
#find hard words
hard_words = []
for word in words:
num_syllables = syllables.find_num_syllables(word)
#print(num_syllables)
if num_syllables >= 3 and "-" not in word and word[-2:] != "es" and word[-2:] != "ed":
#print(words)
hard_words.append(word)
#print(hard_words)
#print(hard_words)
#print(len(hard_words))
#print(words)
#print(len(words))
phw = len(hard_words) / len(words) * 100
# Calculate ASYL
total_syllables = 0
for word in words:
total_syllables += syllables.find_num_syllables(word)
asyl = total_syllables / len(words)
# Caclulate GFRI
gfri = 0.4 * (asl + phw)
# Calculate FKRI
fkri = 206.835 - 1.015 * asl - 86.4 * asyl
print("Here are the hard words in this paragraph:\n" + str(hard_words))
print("Statistics: ASL:{:.2f} PHW:{:.2f}% ASYL:{:.2f}".format(asl, phw, asyl))
print("Readability index (GFRI): {:.2f}".format(gfri))
print("Readability index (FKRI): {:.2f}".format(fkri))
```
### hw3_part2.py
```python
# Get user input
num_turn = int(input("How many turns? => ").strip())
print(num_turn)
pikachu_name = str(input("What is the name of your pikachu? => ").strip())
print(pikachu_name)
often_turn = int(input("How often do we see a Pokemon (turns)? => ").strip())
print(str(often_turn) + "\n")
position = (75, 75)
wins, losses, no_pokemon = 0, 0, 0
turn_counter = 0
records = []
last_direction = ""
# Debugging
#num_turn = 5
#print(num_turn)
#pikachu_name = "Piki"
#print(pikachu_name)
#often_turn = 1
#print(often_turn)
def move_pokemon(coords, direction, steps):
global position
x,y = coords
direction = direction.lower()
if direction in ['n', 's', 'e', 'w']:
if direction == 'n':
x = max(0, x - steps)
elif direction == 'e':
y = min(150, y + steps)
elif direction == 's':
x = min(150, x + steps)
elif direction == 'w':
y = max(0, y - steps)
position = (x, y)
def walk(repeat):
global turn_counter, last_direction
for _ in range(repeat):
direction = input("What direction does " + pikachu_name + " walk? => ").strip()
print(direction)
direction = direction.lower()
if direction in ['n', 's', 'e', 'w']:
move_pokemon(position, direction, 5)
last_direction = direction
turn_counter += 1
def turn_message(turn_counter, position):
print("Turn " + str(turn_counter) + ", " + pikachu_name + " at " + str(position))
def battle(pokemon_type):
global records, position, last_direction
if pokemon_type.lower() == 'g':
records.append('Lose')
opposite_directions = {'n': 's', 's': 'n', 'e': 'w', 'w': 'e'}
move_pokemon(position, opposite_directions[last_direction], 10)
print(pikachu_name + " runs away to " + str(position))
elif pokemon_type.lower() == 'w':
records.append('Win')
move_pokemon(position, last_direction, 1)
print(pikachu_name + " wins and moves to " + str(position))
else:
records.append('No Pokemon')
print("Starting simulation, turn 0 " + pikachu_name + " at (75, 75)")
for i in range(num_turn // often_turn):
walk(often_turn)
turn_message(turn_counter, position)
pokemon_type = input("What type of pokemon do you meet (W)ater, (G)round? => ").strip()
print(pokemon_type)
battle(pokemon_type)
if num_turn < often_turn:
for i in range(num_turn):
direction = input("What direction does " + pikachu_name + " walk? => ").strip()
print(direction)
direction = direction.lower()
if direction in ['n', 's', 'e', 'w']:
move_pokemon(position, direction, 5)
last_direction = direction
turn_counter += 1
print(pikachu_name + " ends up at " + "(" + str(position[0]) + ", " + str(position[1]) + ")" + ", Record: " + str(records))
```
### hw3_part3.py
```python
import math
n_bear = input("Number of bears => ").strip()
print(n_bear)
n_size = input("Size of berry area => ").strip()
print(n_size)
n_bear = int(n_bear)
n_size = float(n_size)
year = 10
block_size = 10
data = []
title = ["Year", "Bears", "Berry", "Tourists"]
def print_line(b1, b2, b3, b4):
b1 = b1 + " " * int(10 - len(b1))
b2 = b2 + " " * int(10 - len(b2))
b3 = b3 + " " * int(10 - len(b3))
b4 = b4 + " " * int(10 - len(b4))
print(b1 + b2 + b3 + b4)
def show_data(data):
data_copy = data.copy()
for line in data_copy:
line[2] = "{:.1f}".format(float(line[2]))
line = [str(i) for i in line]
print_line(line[0], line[1], line[2], line[3])
def conclusion(data):
#print(data)
initial_line = data[0]
max_bears, max_berry, max_tourists = initial_line[1], float(initial_line[2]), initial_line[3]
min_bears, min_berry, min_tourists = initial_line[1], float(initial_line[2]), initial_line[3]
for i in data:
max_bears = max(max_bears, i[1])
max_berry = max(max_berry, float(i[2]))
max_tourists = max(max_tourists, i[3])
min_bears = min(min_bears, i[1])
min_berry = min(min_berry, float(i[2]))
min_tourists = min(min_tourists, i[3])
message = []
message.append(["Min:", str(min_bears), str(min_berry), str(min_tourists)])
message.append(["Max:", str(max_bears), str(max_berry), str(max_tourists)])
show_data(message)
def find_next(bears, berry, tourists):
bears_next = berry / (50*(bears+1)) + bears*0.60 - (math.log(1+tourists,10)*0.1)
berries_next = (berry*1.5) - (bears+1)*(berry/14) - (math.log(1+tourists,10)*0.05)
if berries_next < 0:
berries_next = 0
return (int(bears_next), berries_next)
def find_tourists(bears):
bears = int(bears)
if bears < 4 or bears > 15:
tourists = 0
elif bears <= 10:
tourists = 10000*bears
elif bears > 10:
tourists = 100000 + 20000*(bears-10)
return tourists
for i in range(year):
tourists = find_tourists(n_bear)
data.append([i+1, n_bear, n_size, tourists])
n_bear, n_size = find_next(n_bear, n_size, tourists)
print_line(title[0], title[1], title[2], title[3])
show_data(data)
print()
conclusion(data)
```

Binary file not shown.

View File

@@ -0,0 +1,390 @@
---
title: CSCI 1100 - Homework 4 - Loops and Lists; Passwords and Quarantine
subtitle:
date: 2024-03-13T15:15:44-04:00
slug: csci-1100-hw-4
draft: false
author:
name: James
link: https://www.jamesflare.com
email:
avatar: /site-logo.avif
description: This blog post outlines the requirements and guidelines for completing Homework 4 in the CSCI 1100 - Computer Science 1 course, which consists of two parts focusing on password strength evaluation and analyzing COVID-19 quarantine states using Python programming.
keywords: ["CSCI 1100","Computer Science","Python","Password Strength","COVID-19"]
license:
comment: true
weight: 0
tags:
- CSCI 1100
- Homework
- RPI
- Python
- Programming
categories:
- Programming
collections:
- CSCI 1100
hiddenFromHomePage: false
hiddenFromSearch: false
hiddenFromRss: false
hiddenFromRelated: false
summary: This blog post outlines the requirements and guidelines for completing Homework 4 in the CSCI 1100 - Computer Science 1 course, which consists of two parts focusing on password strength evaluation and analyzing COVID-19 quarantine states using Python programming.
resources:
- name: featured-image
src: featured-image.jpg
- name: featured-image-preview
src: featured-image-preview.jpg
toc: true
math: true
lightgallery: false
password:
message:
repost:
enable: true
url:
# See details front matter: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter
---
<!--more-->
## Overview
This homework is worth 100 points total toward your overall homework grade. It is due in 1 week i.e., on Thursday, February 22, 2024 at 11:59:59 pm. As usual, there will be a mix of autograded points, instructor test case points, and TA graded points. There are two parts in the homework, each to be submitted separately. All parts should be submitted by the deadline or your program will be considered late.
See the handout for Submission Guidelines and Collaboration Policy for a discussion on grading and on what is considered excessive collaboration. These rules will be in force for the rest of the semester.
You will need the utilities and data files we provide in `hw4_files.zip`, so be sure to download this file from the Course Materials section of Submitty and unzip it into your directory for HW 4.
Module `hw4_util.py` is written to help you read information from the files. You do not need to know how functions provided in `hw4_util.py` are implemented (but feel free to examine the code, if you are interested), you can simply use them.
Final note, you will need to use loops in this assignment. We will leave the choice of the loop type up to you. Please feel free to use while loops or for loops depending on the task and your personal preference.
## Part 1: Password Strength
Often when you create a password it is judged for its strength. The estimate of strength is computed by applying several rules — about the length of the password, the presence of certain types of characters, its match against common passwords, and even its match against license plates. In this part of the homework you will implement a few simple strength judgment rules and then determine if a password is to be rejected, or rated poor, fair, good or excellent.
Your program should start by asking for, and reading in, a password. The program should then evaluate the password based on the following rules. Each rule contributes to a numerical score (which starts at 0):
1. **Length**: If the password is 6 or 7 characters long then add 1 to the score; if it is 8, 9 or 10 characters long then add 2; and longer than 10 add 3.
2. **Case**: If it contains at least two upper case letters and two lower case letters add 2 to the score, while if it contains at least one of each, add 1 to the score.
3. **Digits**: If it contains at least two digits add 2 to the score and if it contains at least one digit then add 1.
4. **Punctuation**: If it contains at least one of !@#$ add 1 and if it contains at least one of %^&* then add 1 (total possible of 2).
5. **NY License**: If it contains three letters (upper or lower case) followed by four digits, then it potentially matches a NY state license plate. In this case, subtract 2 from the score.
6. **Common Password**: If the lower case version of the password exactly matches a password found in a list of common passwords, then subtract 3 from the score.
Whenever a rule is applied that creates a change in the score, generate an explanatory line of output. After applying all the rules, output the score and then convert it to a final strength rating of the password:
- **Rejected**: the score is less than or equal to 0.
- **Poor**: the score is 1 or 2.
- **Fair**: the score is 3 or 4
- **Good**: the score is 5 or 6
- **Excellent**: the score is 7 or above.
### Notes
1. For this part and for part 2 you should write functions to keep the code clean, clear and easy to manage.
2. We have provided you with a number of examples that show output values and formatting. Please follow these examples closely.
3. The common passwords are extracted from a file. One of the utility functions we have provided reads this file and return a list of these passwords. To use this function, start by making sure that `hw4_util.py` and `password_list_top_100.txt` are in the same folder as your code. Then add the line
```python
import hw4_util
```
into your program. Finally, call function `hw4_util.part1_get_top` with no arguments. It will return a list of strings containing 100 passwords for you to compare against.
5. Submit only your program file `hw4_part1.py`. Do not submit `hw4_util.py`.
## Part 2: COVID-19 Quarantine States
The NY State COVID-19 Travel Advisory at [COVID-19 Travel Advisory](https://coronavirus.health.ny.gov/covid-19-travel-advisory) requires that individuals who travel to New York from states that have significant community spread of COVID-19 must self-quarantine for 14 days. “Significant spread” in a state is measured as either:
- a daily average of more than 10 people per 100,000 residents tested positive in the previous seven days, or
- a daily average of more than 10% of tests were positive in the previous seven days.
We will refer to states having a significant spread as quarantine states. In this part of HW 4 you will use per state data downloaded from [COVID Tracking Project](https://covidtracking.com/) to answer queries about which states were quarantine states and when.
The data we obtained was downloaded (on October 5, 2023) in the form of a large “comma-separated value” file. This file contains one line per day per state, and there are many fields per line. We have condensed it to a form suitable for a CS 1 homework. The data is shared under the Creative Commons BY 4.0 license which means we can:
- Share: copy and redistribute the material in any medium or format and
- Adapt: remix, transform, and build upon the material for any purpose, even commercially.
We have provided a simple utility to give you access to the condensed data. To use this (similar to Part 1) you must have the files `hw4_util.py` and `prob2_data.csv` in the same folder as your own code. You must then
```python
import hw4_util
```
into your program. `hw4_util` has a function called `part2_get_week` that accepts a single integer argument, `w`, and returns a list of lists. Argument `w` is the index of a previous week, with `w==1` being the most recent week, `w==2` being the week before that, etc., up to `w==29` which corresponds to 29 weeks ago, all the way back to March 15. The returned list contains one list per state, plus the District of Columbia (DC) and Puerto Rico (PR) — 52 in all. Each state list has 16 items:
- Item 0 is a string giving the two letter (upper case) state abbreviation. These are correct.
- Item 1 is an integer giving the states population estimate — from the 2019 Census Bureau estimate [Census Bureau estimate](https://www.census.gov/newsroom/press-kits/2019/national-state-estimates.html).
- Items 2-8 are the number of positive tests for that state in each of the seven days of the specified week — most recent day first.
- Items 9-15 are the number of negative tests for the state in each of the seven days of
- the specified week — most recent day first.
For example, the list for Alaska for week 1 is
```text
['AK',\
731545,\
189,147,128,132,106,125,118,\
3373,3819,6839,4984,6045,6140,1688]
```
Here is what you need to do for this assignment. Your program, in a loop, must start by asking the user to specify the index for a week, as described above. (You may assume an integer is input as the week number.) A negative number for the week indicates that the program should end. For non-negative numbers, if the data are not available for that week the function will return an empty list; in this case, skip the rest of loop body. Otherwise, after getting the list of lists back, the program should answer one of four different requests for information about that week. Answering the request starts by the user typing in a keyword. The keywords are 'daily', 'pct', 'quar', 'high'. Heres what the program must do for each request:
- **'daily'**: Ask the user for the state abbreviation and then output the average daily positive cases per 100,000 people for that state for the given week, accurate to the nearest tenth.
- **'pct'**: Ask the user for the state abbreviation and then output the average daily percentage of tests that are positive over the week, accurate to the nearest tenth of a percent.
- **'quar'**: Output the list of state abbreviations, alphabetically by two-letter abbreviation, of travel quarantine states for the given week as discussed above. There should be ten state abbreviations per line—call `hw4_util.print_abbreviations` with your list of abbreviations to print the output as required. (Note: every week has at least one quarantine state.)
- **'high'**: Output the two-letter abbreviation of the state that had the highest daily average number of positive cases per 100,000 people over the given week, and output this average number, accurate to the nearest tenth.
Input key words and state abbreviations may be typed in upper or lower case and still match correctly. If a key word is not one of these four or if a state is not found (because its abbreviation is incorrectly typed), output a simple error message and do nothing more in the current loop iteration.
## Notes
1. As always, look at the example output we provide and follow it accurately.
2. All reported values for numbers of positive and negative test results will be at least 0; however, some may be 0. You may assume, however, that there will never be a week where all days have 0 negative tests.
3. Compute the daily percentage of tests that are positives by summing the positive cases for the week, and summing negative cases for the week. If these sums are P and N respectively, then the percentage positive is $P/(P +N) * 100$. This is not exactly the same as the average of daily percentages for a week, but it is easier to compute.
4. Submit only your program file `hw4_part2.py`. Do not submit `hw4_util.py`.
## Supporting Files
{{< link href="HW4.zip" content="HW4.zip" title="Download HW4.zip" download="HW4.zip" card=true >}}
## Solution
### hw4_part1.py
```python
"""
This script is used to test password strength based on certain criteria.
Author: Jinshan Zhou
"""
import hw4_util
if __name__ == "__main__":
# initialize variables
strength = 0
report = ""
# Debugging
#user_password = "AdmIn123%^%*(&"
#user_password = "jaX1234"
# get user input
user_password = str(input("Enter a password => ").strip())
# print the password for testing purposes
print(user_password)
# get the length of the password
length = len(user_password)
# check the length of the password and update strength and report accordingly
if length <= 7 and length >= 6:
strength += 1
report += "Length: +1\n"
elif length >= 8 and length <= 10:
strength += 2
report += "Length: +2\n"
elif length > 10:
strength += 3
report += "Length: +3\n"
# count the number of uppercase and lowercase letters in the password
num_upper = sum(1 for c in user_password if c.isupper())
num_lower = sum(1 for c in user_password if c.islower())
# check the number of uppercase and lowercase letters and update strength and report accordingly
if num_upper >= 2 and num_lower >= 2:
strength += 2
report += "Cases: +2\n"
elif num_upper >= 1 and num_lower >= 1:
strength += 1
report += "Cases: +1\n"
# count the number of digits in the password
num_digits = sum(1 for c in user_password if c.isdigit())
# check the number of digits and update strength and report accordingly
if num_digits >= 2:
strength += 2
report += "Digits: +2\n"
elif num_digits >= 1:
strength += 1
report += "Digits: +1\n"
# check for special characters and update strength and report accordingly
if any(c in "!@#$" for c in user_password):
strength += 1
report += "!@#$: +1\n"
if any(c in "%^&*" for c in user_password):
strength += 1
report += "%^&*: +1\n"
# check for a specific pattern and update strength and report accordingly
if (num_upper + num_lower) == 3 and num_digits == 4 and len(user_password) > 3:
check = user_password.replace(user_password[0:3], "")
if sum(1 for c in check if c.isdigit()) == 4:
strength -= 2
report += "License: -2\n"
# check if the password is in the top 10,000 most common passwords and update strength and report accordingly
if user_password.lower() in hw4_util.part1_get_top():
strength -= 3
report += "Common: -3\n"
# add the combined score to the report
report += "Combined score: " + str(strength) + "\n"
# check the strength and add the appropriate message to the report
if strength <= 0:
report += "Password is rejected"
elif strength >= 1 and strength <= 2:
report += "Password is poor"
elif strength >= 3 and strength <= 4:
report += "Password is fair"
elif strength >= 5 and strength <= 6:
report += "Password is good"
elif strength >= 7:
report += "Password is excellent"
# print the report
print(report)
```
### hw4_part2.py
```python
import hw4_util
"""
hw4_util.part2_get_week(1)[0] ==> ['AK',\
731545, 189, 147, 128, 132, 106, 125,\
118, 3373, 3819, 6839, 4984, 6045,\
6140, 1688]
"""
def find_state(states, state):
state = state.upper()
found_status = False
for i in states:
if i[0].upper() == state:
found_status = True
return i
if not found_status:
return []
def get_postive_per_100k(status):
population = status[1]
total_postive = 0
for i in range (2, 9):
total_postive += status[i]
postive_per_100k = ((total_postive / 7) / population) * 100000
return postive_per_100k
def get_pct_postive_tests(status):
num_tested = 0
num_postive = 0
for i in range (2, 16):
num_tested += status[i]
for i in range (2, 9):
num_postive += status[i]
pct_postive_tests = num_postive / num_tested
return pct_postive_tests
def action_valid(request_code):
request_code = request_code.lower()
allowed_action = ["daily", "pct", "quar", "high"]
if request_code in allowed_action:
return True
else:
return False
def quar(week):
states = []
for i in week:
if get_postive_per_100k(i) >= 10 or get_pct_postive_tests(i) >= 0.1:
states.append(i[0])
states.sort()
return states
def high(week):
highest = ""
highest_value = 0
for i in week:
if get_postive_per_100k(i) > highest_value:
highest = i[0]
highest_value = get_postive_per_100k(i)
return highest.upper()
def show_high(week):
highest = high(week)
highest_postive_per_100k = get_postive_per_100k(find_state(week, highest))
print("State with highest infection rate is", highest)
print("Rate is {:.1f} per 100,000 people".format(highest_postive_per_100k))
if __name__ == "__main__":
index_week = 0 # Initialize index_week
print("...")
while index_week != -1:
# Get index of week
index_week = input("Please enter the index for a week: ").strip()
print(index_week)
index_week = int(index_week)
# Stop if the index is -1
if index_week < 0:
break
# Get the week, check if the week is valid
week = hw4_util.part2_get_week(index_week).copy()
if week == []:
print("No data for that week")
print("...")
continue
# Get the Action
request_code = input("Request (daily, pct, quar, high): ").strip()
print(request_code)
request_code = request_code.lower()
# Check if the action is valid
if not action_valid(request_code):
print("Unrecognized request")
print("...")
continue
# Perform the action
if request_code == "daily":
state = input("Enter the state: ").strip()
print(state)
state = state.upper()
if find_state(week,state) == []:
print("State {} not found".format(state))
print("...")
else:
state_data = find_state(week,state)
print("Average daily positives per 100K population: {:.1f}".format(get_postive_per_100k(state_data)))
print("...")
elif request_code == "pct":
state = input("Enter the state: ").strip()
print(state)
state = state.upper()
if find_state(week,state) == []:
print("State {} not found".format(state))
print("...")
else:
state_data = find_state(week,state)
print("Average daily positive percent: {:.1f}".format(get_pct_postive_tests(state_data)*100))
print("...")
elif request_code == "quar":
print("Quarantine states:")
hw4_util.print_abbreviations(quar(week))
print("...")
elif request_code == "high":
show_high(week)
print("...")
```

Binary file not shown.

View File

@@ -0,0 +1,473 @@
---
title: CSCI 1100 - Homework 5 - Lists of Lists; Grids; Path Planning
subtitle:
date: 2024-03-13T15:36:47-04:00
slug: csci-1100-hw-5
draft: false
author:
name: James
link: https://www.jamesflare.com
email:
avatar: /site-logo.avif
description: This blog post provides an overview of a homework assignment for CSCI 1100 - Computer Science 1, focusing on lists of lists, grids, and path planning using Python. It includes problem descriptions, guidelines, and example outputs for each part of the assignment.
keywords: ["Python","Computer Science","Lists","Grids","Path Planning"]
license:
comment: true
weight: 0
tags:
- CSCI 1100
- Homework
- RPI
- Python
- Programming
categories:
- Programming
collections:
- CSCI 1100
hiddenFromHomePage: false
hiddenFromSearch: false
hiddenFromRss: false
hiddenFromRelated: false
summary: This blog post provides an overview of a homework assignment for CSCI 1100 - Computer Science 1, focusing on lists of lists, grids, and path planning using Python. It includes problem descriptions, guidelines, and example outputs for each part of the assignment.
resources:
- name: featured-image
src: featured-image.jpg
- name: featured-image-preview
src: featured-image-preview.jpg
toc: true
math: false
lightgallery: false
password:
message:
repost:
enable: true
url:
# See details front matter: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter
---
<!--more-->
## Overview
This homework is worth 100 points total toward your overall homework grade. It is due Thursday, February 29, 2024 at 11:59:59 pm. As usual, there will be a mix of autograded points, instructor test case points, and TA graded points. There are two parts to the homework, each to be submitted separately. Both parts should be submitted by the deadline or your program will be considered late.
See the handout for Submission Guidelines and Collaboration Policy for a discussion on grading and on what is considered excessive collaboration. These rules will be in force for the rest of the semester.
You will need the data files we provide in `hw5_files.zip`, so be sure to download this file from the Course Materials section of Submitty and unzip it into your directory for HW 5. The zip file contains utility code, data files and example input / output for your program.
## Problem Description
Many problems in computer science and in engineering are solved on a two-dimensional numerical grid using techniques that are variously called “gradient ascent” (or “descent”), greedy search, or hill-climbing. We are going to study a simplified version of this using hand-generated elevation data.
The main representation we need is a list of lists of “heights” (also called “elevations”, but we will use the simpler term “heights” here). For example:
```python
grid = [[15, 16, 18, 19, 12, 11],
[13, 19, 23, 21, 16, 12],
[12, 15, 17, 19, 22, 10],
[10, 14, 16, 13, 9, 6]]
```
This grid has four lists of six integer entries each. Each entry represents a height — e.g., meters above sea level — and the heights are measured at regularly-spaced intervals, which could be as small as centimeters or as large as kilometers. The USGS, United States Geological Survey, maintains and distributes elevation data like this, but private companies do so as well. Such data are important for evaluating water run-off, determining placement of wind turbines, and planning roads and construction, just to name a few uses. We are going to use the analogy of planning hiking paths on a plot of land.
Questions we might ask about this data include:
1. What is the highest point (greatest height)? This is also called the “global maximum” because it is the greatest value in the data. In our example, this height value is 23 and it occurs in list 1, entry 2. We will refer to this as row 1, column 2 (or “col 2”), and write these values as a tuple, (1, 2), where we assume the first value is the row and the second is the column. We refer to (1, 2) as a “location”.
2. Are there “local maxima” in the data? These are entries whose value is greater than their immediately surrounding values, but smaller than the global maximum. In our example there is a local maxima of 22 at location (2, 4).
3. Starting at a given location, what is the best path to the global maxima? This is a tricky question because we need to define “best path”. Here is a simple one: can we start at a given location and only take the steepest route and get to the global maximum (can we hike up to the “peak”)? For example, if we start at (3, 0) then the path through locations (3, 0), (3, 1), (3, 2), (2, 2), (1, 2) follows the steepest route and reaches the top. This is a “gradient ascent” method. But, if we start at location (3, 5) then we will generate the route (3, 5), (3, 4), (2, 4), but then there is no way to continue up to reach the global maximum.
There are many more questions that we can ask and answer. Some of them can be solved easily, while others require sophisticated algorithms and expensive computations.
Before getting started on the actual assignment, it is important to define the notion of a “neighbor” location in the grid — one that we are allowed to step to from a given location. For our purposes, from location (r, c), the neighbor locations are (r-1, c), (r, c-1), (r, c+1), and (r+1, c).
In other words, a neighbor location must be in the same row or the same column as the current location. Finally, neighbors cannot be outside the grid, so for example at location (r, 0) only (r-1, 0), (r, 1), (r+1, 0) are allowed as neighbors.
## Getting Started
Please download `hw5_files.zip` and place all the files in the same folder that you are going to write your solutions. Files `hw5_util.py` and `hw5_grids.txt` are quite important: `hw5_util.py` contains utility functions to read grids and starting locations from `hw5_grids.txt`. In particular:
- `hw5_util.num_grids()` returns the number of different grids in the data.
- `hw5_util.get_grid(n)` returns grid n, where n==1 is the first grid and n == `hw5_util.num_grids()` is the last.
- `hw5_util.get_start_locations(n)` returns a list of tuples giving one or more starting locations to consider for grid n.
- `hw5_util.get_path(n)` returns a list of tuples giving a possible path for grid n.
We suggest you start by playing around with these functions and printing out what you get so that you are sure you understand.
You may assume the following about the data:
1. The grid has at least two rows.
2. Each row has at least two entries (columns) and each row has the same number of columns.
3. All heights are positive integers.
4. The start locations are all within the range of rows and columns of the grid.
5. The locations on the path are all within the range of rows and columns of the grid.
## Part 1
Write a python program, `hw5_part1.py` that does the following:
1. Asks the user for a grid number and loops until one in the proper range is provided. Denote the grid number as n.
2. Gets grid n.
3. Asks the user if they want to print the grid. A single character response of 'Y' or 'y' should cause the grid to be printed. For anything else the grid should not be printed. When printing, you may assume that the elevations are less than 1,000 meters. See the example output.
4. Gets the start locations associated with grid n and for each it prints the set of neighbor locations that are within the boundaries of the grid. For example if grid n has 8 rows and 10 columns, and the list of start locations is `[(4, 6), (0, 3), (7, 9)]` then the output should be:
```plaintext
Neighbors of (4, 6): (3, 6) (4, 5) (4, 7) (5, 6)
Neighbors of (0, 3): (0, 2) (0, 4) (1, 3)
Neighbors of (7, 9): (6, 9) (7, 8)
```
Very important: we strongly urge you to write a function called `get_nbrs` that takes as parameters a row, col location, together with the number of rows and columns in the grid, and returns a list of tuples containing the locations that are neighbors of the row, col location and are within the bounds of the grid. You will make use of this function frequently.
5. Gets the suggested path, decides if it is a valid path (each location is a neighbor of the next), and then calculates the total downward elevation change and the total upward elevation change. For example using the grid above, if the path is `(3, 1), (3, 0), (2, 0), (1, 0), (1, 1), (0, 1), (0, 2), (1, 2)` the downward elevation changes are from (3, 1) to (3, 0) (change of 4) and from (1, 1) to (0, 1) (change) of 3 for a total of 7, and the upward elevation changes are from (3, 0) to (2, 0), from (2, 0) to (1, 0), from (1, 0) to (1, 1), from (0, 1) to (0, 2) and from (0, 2) to (1, 2) for a total of (2 + 1 + 6 + 2 + 5) = 16). The output should be:
```plaintext
Valid path
Downward 7
Upward 16
```
If the path is invalid, the code should print `Path: invalid step from point1 to point2.` Here point1 and point2 are the tuples representing the start and end of an invalid step.
Submit just the file `hw5_part1.py` and nothing else.
## Part 2
Revise your solution to Part 1 and submit it as `hw5_part2.py`. The program should again ask the user for the grid number, but it should not print the grid. Next, it should find and output the location and height of the global maximum height. For example for the simple example grid, the output should be `global max: (1, 2) 23`. You may assume without checking that the global maximum is unique.
The main task of Part 2 is to find and output two paths from each start location for the grid. The first is the steepest path up, and the second is the most gradual path up. The steps on each path must be between neighboring locations as in Part 1. Also, on each path no steps to a location at the same height or lower are allowed, and the step size (the change in height) can be no more than a maximum step height (difference between heights at the new location and at the current location). Your code must ask the user for the value of this maximum step height.
Next, determine for each path if it reaches the location of the global maximum height in the grid, a local maximum, or neither. The latter can happen at a location where the only upward steps are too high relative to the height at the current location. Of course, true hiking paths can go both up and down, but finding an “optimal path” in this more complicated situation requires much more sophisticated algorithms than we are ready to develop here.
As an example of the required results, here is the same grid as above:
```python
grid = [[15, 16, 18, 19, 12, 11],
[13, 19, 23, 21, 16, 12],
[12, 15, 17, 19, 20, 10],
[10, 14, 16, 13, 9, 6]]
```
Starting at location (3, 0) with a maximum height change of 4, the steepest path is (3, 0), (3, 1), (3, 2), (2, 2), (2, 3), (1, 3), (1, 2), while the most gradual path is (3, 0), (2, 0), (1, 0), (0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (1, 2). Both reach the global maximum, and both avoid stepping to the global maximum the first time they are close because the step height is too large. Note that both the steepest and most gradual paths from location (3, 5) would end at the local maximum (2, 4). The steepest path would end after four steps (five locations on the path) and the most gradual would end after six steps (seven locations on the path). If the max step height were only 3, then both paths from (3, 5) would stop at location(3, 4) before any maximum is reached.
Paths should be output with 5 locations per line, for example:
```plaintext
steepest path
(3, 0) (2, 0) (1, 0) (0, 0) (0, 1)
(0, 2) (0, 3) (1, 3) (1, 2)
global maximum
```
See the example output for further details.
Finally, if requested by the user, output a grid — well call it the “path grid” — giving at each location the number of paths that include that location. This can be handled by forming a new list of lists, where each entry represents a count — initialized to 0. For each path and for each location (i, j) on the path, the appropriate count in the list of lists should be incremented. At the end, after all paths have been generated and added to the counts, output the grid. In this output, rather than printing a 0 for a locations that are not on any path, please output a '.'; this will make the output clearer. See the example output.
## Notes
1. In deciding the choice of next locations on a path, if there is a tie, then pick the one that is earlier in the list produced by your `get_nbrs` function. For example starting at (0, 5) with elevation 11 in the above example grid, both (0, 4) and (1, 5) have elevation 12. In this case (0, 4) would be earlier in the `get_nbrs` list and therefore chosen as the next location on the path.
2. Please do not work on the path grid output — the last step — until you are sure you have everything else working.
3. Both the most gradual and steepest paths are examples of greedy algorithms where the best choice available is made at every step and never reconsidered. More sophisticated algorithms would consider some form of backtracking where decisions are undone and alternatives reconsidered.
## Supporting Files
{{< link href="HW5.zip" content="HW5.zip" title="Download HW5.zip" download="HW5.zip" card=true >}}
## Solution
### hw5_part1.py
```python
import hw5_util
def show_grid(grid):
""" Display the grid in a human-readable format. """
display = ""
for row in grid:
for cell in row:
display += " {:2d}".format(int(cell))
display += "\n"
print(display, end="")
def find_grid_size(grid):
""" Find the size of the grid. """
return (len(grid), len(grid[0]))
def find_neighbors(point, grid):
""" Find the neighbors of a point in the grid. """
neighbors = []
y, x = point
max_y, max_x = find_grid_size(grid)
neighbors.append((y-1, x)) if y-1 >= 0 else None
neighbors.append((y, x-1)) if x-1 >= 0 else None
neighbors.append((y, x+1)) if x+1 < max_x else None
neighbors.append((y+1, x)) if y+1 < max_y else None
neighbors.append((y-1, x-1)) if y-1 >= 0 and x-1 >= 0 else None
neighbors.append((y-1, x+1)) if y-1 >= 0 and x+1 < max_x else None
neighbors.append((y+1, x-1)) if y+1 < max_y and x-1 >= 0 else None
neighbors.append((y+1, x+1)) if y+1 < max_y and x+1 < max_x else None
return neighbors
def show_neighbors(start_locations, grid):
""" Display the neighbors of the start locations."""
for i in start_locations:
neighbors = ""
for j in find_neighbors(i, grid):
neighbors += str(j) + " "
neighbors = neighbors.strip()
print("Neighbors of {}: {}".format(i, neighbors))
def path_validator(path, grid):
""" Validate the path. """
result = (True, "Valid path")
for i in range(1, len(path)):
if path[i] not in find_neighbors(path[i-1], grid):
result = (False, "Path: invalid step from {} to {}".format(path[i-1], path[i]))
break
return result
def movement_status(path, grid):
""" Determine the movement status of the path. """
downward = 0
upward = 0
for i in range(1, len(path)):
change = grid[path[i][0]][path[i][1]] - grid[path[i-1][0]][path[i-1][1]]
if change > 0:
upward += change
elif change < 0:
downward += change
return (downward, upward)
if __name__ == "__main__":
grid_index = input("Enter a grid index less than or equal to 3 (0 to end): ").strip()
#grid_index = 1 # Debugging
print(grid_index)
grid_index = int(grid_index)
grid = hw5_util.get_grid(int(grid_index))
#print(grid) # Debugging
"""
grid = [[15, 16, 18, 19, 12, 11],\
[13, 19, 23, 21, 16, 12],\
[12, 15, 17, 19, 20, 10],\
[10, 14, 16, 13, 9, 6]]
"""
print_gride = input("Should the grid be printed (Y or N): ").strip()
#print_gride = "Y" # Debugging
print(print_gride)
if print_gride.upper() == "Y":
print("Grid {}".format(grid_index))
show_grid(grid)
print("Grid has {} rows and {} columns".format(find_grid_size(grid)[0], find_grid_size(grid)[1]))
start_locations = hw5_util.get_start_locations(grid_index)
"""start_locations = [(3, 3), (3, 0), (3, 5), (0, 2)]"""
show_neighbors(start_locations, grid)
"""find_neighbors((3, 3), grid) = [(2, 3), (3, 2), (3, 4)]"""
suggested_path = hw5_util.get_path(grid_index)
#print("Suggested path: ", suggested_path) # Debugging
"""Suggested path: [(3, 1), (3, 0), (2, 0), (1, 0), (1, 1), (0, 1), (0, 2), (1, 2)]"""
print(path_validator(suggested_path, grid)[1])
"""
(True, 'Valid path')
(False, 'Path: invalid step from (2, 4) to (3, 3)')
"""
if path_validator(suggested_path, grid)[0]:
downward, upward = movement_status(suggested_path, grid)
downward = abs(downward)
print("Downward {}\nUpward {}".format(downward, upward))
```
### hw5_part2.py
```python
import hw5_util
def find_height(point, grid):
""" Find the height of a point in the grid. """
return grid[point[0]][point[1]]
def find_grid_size(grid):
""" Find the size of the grid. """
return (len(grid), len(grid[0]))
def find_global_max(grid):
""" Find the global maximum of the grid. """
max_height = ((0,0), 0)
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j] > max_height[1]:
max_height = ((i,j), grid[i][j])
return max_height
def find_neighbors(point, grid):
""" Find the neighbors of a point in the grid. """
neighbors = []
y, x = point
max_y, max_x = find_grid_size(grid)
neighbors.append((y-1, x)) if y-1 >= 0 else None
neighbors.append((y, x-1)) if x-1 >= 0 else None
neighbors.append((y, x+1)) if x+1 < max_x else None
neighbors.append((y+1, x)) if y+1 < max_y else None
return neighbors
def find_steepest_path(start, grid, max_step):
""" Find the steepest path."""
path = [start]
current = start
while True:
neighbors = find_neighbors(current, grid)
next_step = None
max_height_diff = 0
for n in neighbors:
height_diff = find_height(n, grid) - find_height(current, grid)
if height_diff > 0 and height_diff <= max_step and height_diff > max_height_diff:
next_step = n
max_height_diff = height_diff
if next_step is None:
break
path.append(next_step)
current = next_step
return path
def find_gradual_path(start, grid, max_step):
"""" Find the most gradual path."""
path = [start]
current = start
while True:
neighbors = find_neighbors(current, grid)
next_step = None
min_height_diff = float("inf")
for n in neighbors:
height_diff = find_height(n, grid) - find_height(current, grid)
if height_diff > 0 and height_diff <= max_step and height_diff < min_height_diff:
next_step = n
min_height_diff = height_diff
if next_step is None:
break
path.append(next_step)
current = next_step
return path
def show_path(path):
"""" Display the path."""
display = ""
counter = 0
for i in range(len(path)):
if counter == 5:
display += "\n"
counter = 0
display += "({}, {}) ".format(path[i][0], path[i][1])
counter += 1
print(display)
def find_path_end(path, grid):
""" Find the end of the path."""
end_point = path[-1]
end_height = find_height(end_point, grid)
max_point, max_height = find_global_max(grid)
if end_height == max_height:
return "global maximum"
neighbors = find_neighbors(end_point, grid)
is_local_max = True
for n in neighbors:
if find_height(n, grid) > end_height:
is_local_max = False
break
if is_local_max:
return "local maximum"
else:
return "no maximum"
def build_path_grid(grid, paths):
""" Build the path grid."""
rows, cols = find_grid_size(grid)
path_grid = [[0] * cols for _ in range(rows)]
for path in paths:
for point in path:
y, x = point
path_grid[y][x] += 1
return path_grid
def print_path_grid(path_grid):
""" Display the path grid."""
for i in range(len(path_grid)):
row = " "
for j in range(len(path_grid[i])):
if path_grid[i][j] > 0:
row += str(path_grid[i][j]) + " "
else:
row += "." + " "
print(row.rstrip())
def print_path(path, path_type):
""" Display the path."""
print("{} path".format(path_type))
show_path(path)
print(find_path_end(path, grid))
if __name__ == "__main__":
grid_index = input("Enter a grid index less than or equal to 3 (0 to end): ").strip()
#grid_index = 1 # Debugging
print(grid_index)
grid_index = int(grid_index)
grid = hw5_util.get_grid(int(grid_index))
"""
grid = [[15, 16, 18, 19, 12, 11],\
[13, 19, 23, 21, 16, 12],\
[12, 15, 17, 19, 20, 10],\
[10, 14, 16, 13, 9, 6]]
"""
start_locations = hw5_util.get_start_locations(grid_index)
max_step_height = input("Enter the maximum step height: ").strip()
#max_step_height = "4" # Debugging
print(max_step_height)
max_step_height = int(max_step_height)
print_path_grid_choice = input("Should the path grid be printed (Y or N): ").strip()
#print_path_grid_choice = "Y" # Debugging
print(print_path_grid_choice)
print_path_grid_choice = print_path_grid_choice.upper()
print("Grid has {} rows and {} columns".format(find_grid_size(grid)[0], find_grid_size(grid)[1]))
print("global max: {} {}".format(find_global_max(grid)[0], find_global_max(grid)[1]))
print("===")
paths = []
for start in start_locations:
steepest = find_steepest_path(start, grid, max_step_height)
gradual = find_gradual_path(start, grid, max_step_height)
print_path(steepest, "steepest")
print("...")
print_path(gradual, "most gradual")
print("===")
paths.append(steepest)
paths.append(gradual)
path_grid = build_path_grid(grid, paths)
print("Path grid")
print_path_grid(path_grid)
```