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 - 作业 3 - 循环、元组、列表和条件语句
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: 这次家庭作业的重点是在 Python 中运用列表、循环、元组和条件语句。它包括三个部分 - 分析文本复杂度、模拟皮卡丘的移动,以及模拟熊、浆果和游客的种群变化。
keywords: ["Python","循环","元组","列表","条件语句"]
license:
comment: true
weight: 0
tags:
- CSCI 1100
- 作业
- RPI
- Python
- 编程
categories:
- 编程语言
collections:
- CSCI 1100
hiddenFromHomePage: false
hiddenFromSearch: false
hiddenFromRss: false
hiddenFromRelated: false
summary: 这次家庭作业的重点是在 Python 中运用列表、循环、元组和条件语句。它包括三个部分 - 分析文本复杂度、模拟皮卡丘的移动,以及模拟熊、浆果和游客的种群变化。
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:
# 有关详细的 front matter 设置,请参阅: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter
---
<!--more-->
## 概述
这次家庭作业占你总家庭作业成绩的 100 分,截止日期为 2024 年 2 月 15 日星期四晚上 11:59:59。你有 1 周时间完成这个作业。
这个作业的目标是运用列表、循环、元组和条件语句。随着你的程序变得越来越长,你需要开发一些策略来测试你的代码。这里有一些简单的策略:尽早开始测试,通过编写一点点代码并进行测试来测试程序的小部分。我们将在家庭作业描述中引导你构建程序,并提供一些测试的想法。
和往常一样,确保你遵循程序结构指南。你将根据程序的正确性以及良好的程序结构进行评分。这包括注释。最低限度,我们期望在提交的开始有一个简短的 docstring 注释块,详细说明目的和简要总结 (你也可以包括额外的信息,如你的姓名和日期); 以及每个你定义的函数的 docstring 注释,详细说明目的、输入和预期的返回值。额外的注释必须伴随你代码中任何复杂的部分。
## 关于过度合作的警告
请记住遵守你在上一个作业中得到的合作政策。它在本学期的这个和所有作业中保持有效。我们将使用软件比较所有提交的程序,寻找不适当的相似之处。这个软件可以处理程序之间的各种差异,所以如果你 (a) 拿了别人的程序,修改了 (或没有修改),并作为你自己的程序提交, (b) 与一个或多个同学一起编写了一个程序,并作为你自己的作业分别提交了修改后的版本,或者 (c) 提交了 (可能稍作修改) 前一年提交的软件作为你的软件,这个软件会将这些提交标记为非常相似。 (a)、 (b) 和 (c) 都超出了本课程可接受的范围 - 它们违反了学术诚信政策。此外,这种抄袭会阻碍你学习如何解决问题,从长远来看会伤害你。你编写自己的代码越多,你学到的就越多。
确保你已经阅读了合作政策,了解可接受的合作水平,以及你如何保护自己。该文件可以在 Submitty 的课程材料页面上找到。过度合作的处罚可高达:
- 家庭作业得 0 分,以及
- 学期成绩额外减少 5%。
受到处罚的学生也将被禁止退出该课程。更严重的违规行为,如盗用他人代码,将导致该课程自动得 F。第二次被发现违反学术诚信的学生将自动得到 F。
通过提交你的家庭作业,你断言你 (a) 理解学术诚信政策,并且 (b) 没有违反它。
最后,请注意,这项政策是针对本课程中将出现的少数问题而制定的。遵循上述策略并在这样做时运用常识的学生不会在学术诚信方面遇到任何麻烦。
## 第 1 部分: 文本中使用的语言有多复杂? (40 分)
为 HW 3 创建一个文件夹。从 Submitty 上的课程材料下载 zip 文件 `hw3_files.zip`。把它放在这个文件夹里并解压。你应该看到一个名为 `syllables.py` 的文件,它将是这个家庭作业的辅助模块。在与此文件相同的文件夹中编写你的程序,并将其命名为 `hw3_part1.py`
在解决这一部分之前要熟悉的几件事。
在这一部分,你必须熟悉一个名为 `.split()` 的函数,它接受一段文本,并将其转换为一个字符串列表。下面是一个示例运行:
```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.']
```
你还需要使用文件 `syllables.py` 中的函数 `find_num_syllables()`,它接受一个英语单词作为字符串输入,并返回该单词中音节的总数作为整数。即使单词有标点符号,该模块也能工作,所以你不需要显式地删除它们。确保你在程序中适当地导入这个模块。
```python
>>> find_num_syllables('computer')
3
>>> find_num_syllables('science')
1
>>> find_num_syllables('introduction')
4
```
显然,第二个结果是不正确的。我们提供的模块不是一个完美的音节计数实现,所以你可能会发现错误。修复它们不是你的工作,按原样使用该模块,包括其中的错误。不要担心它犯的错误。要正确地计算这个,我们需要使用一个自然语言处理 (NLP) 模块,如 NLTK我们在本课程中没有安装。
### 问题规范
在这一部分,你将从用户那里读取一个包含多个英语句子的文本段落。假设句号标志着句子的结束。将段落读取为一行 (长) 文本。计算并打印与该文本的整体可读性相对应的以下度量。
- ASL (平均句子长度) 由每个句子的单词数给出。打印 ASL。
- PHW (困难词的百分比): 要计算这个值,首先计算三个或更多音节且不包含连字符 (-) 的单词数,以及不以 'es' 或 'ed' 结尾的三音节单词数。将这个计数除以文本中的总单词数,再乘以 100 得到百分比。打印 PHW。
- 将 PHW 计算中使用的所有单词收集到一个列表中,与它们在输入中出现的方式完全一致,并打印这个列表。
- ASYL (平均音节数) 由音节总数除以单词总数给出。打印 ASYL。
- GFRI 由公式 0.4*(ASL + PHW) 给出。打印 GFRI。
- FKRI 由公式 206.835-1.015*ASL-86.4*ASYL 给出。打印 FKRI。
请注意GFRI 和 FKRI 这两个指标是著名的可读性指标 Gunning-Fog 和 Flesch Kincaid 的略微修改版本。在 Gunning-fog 中,计算出的值越高,文本就越难读。对于 Flesch Kincaid 来说则相反,值越高表示文本越容易阅读。
你可以在 `hw3_files.zip` 中的 `hw3_part1_01.txt``hw3_part1_02.txt` 中找到程序运行的示例。
完成后,请将你的程序作为 `hw3_part1.py` 提交到 Submitty。你必须使用这个文件名否则你的提交在 Submitty 中将无法工作。你不必提交我们提供的任何文件。
## 第 2 部分: 野外的皮卡丘! (40 分)
假设你有一只皮卡丘站在图像的中间,坐标为 (75, 75)。假设图像左上角的坐标为 (0,0)。
我们将带着皮卡丘在图像中走动,寻找其他宝可梦。这是一种简单的模拟。首先,我们将通过询问用户模拟的回合数 (从第 0 回合开始)、皮卡丘的名字以及我们遇到其他宝可梦的频率来设置模拟参数。此时我们进入一个模拟循环 (while)。你的皮卡丘每回合走 5 步,方向为北 (N)、南 (S)、东 (E) 或西 (W)。每回合,询问用户皮卡丘行走的方向,并将皮卡丘移动到该方向。你应该忽略 N、S、E、W 以外的方向。每隔 often 回合,你就会遇到另一只宝可梦。询问用户类型 (地面 (G) 或水 (W))。如果是地面类型 'G',你的皮卡丘就输了。它转身并以看到另一只宝可梦之前移动方向的相反方向跑 10 步。 (如果最后的方向不是有效方向,你的皮卡丘就不移动。) 如果是水类型 'W',你的皮卡丘就赢了,并向前走 1 步。其他任何情况都意味着你实际上没有看到另一只宝可梦。在列表中记录胜利、失败和 "无宝可梦"。
在 turn 回合结束时,报告你的皮卡丘最终到达的位置,并打印出它的记录。
你必须为这个程序实现至少一个函数:
```python
move_pokemon((row, column), direction, steps)
```
它返回皮卡丘的下一个位置作为一个 (row, column) 元组。图像边界有一个围栏。没有坐标可以小于 0 或大于 150。0 和 150 是允许的。确保你的 `move_pokemon()` 函数不会返回这个范围之外的位置。
你可以使用以下代码来测试你的 `move_pokemon()` 函数。如果你愿意,可以随意编写其他函数,但一定要测试它们以确保它们按预期工作!
```python
from hw3_part2 import move_pokemon
row = 15
column = 10
print(move_pokemon((row, column), 'n', 20)) # 应该打印 (0, 10)
print(move_pokemon((row, column), 'e', 20)) # 应该打印 (15, 30)
print(move_pokemon((row, column), 's', 20)) # 应该打印 (35, 10)
print(move_pokemon((row, column), 'w', 20)) # 应该打印 (15, 0)
row = 135
column = 140
print(move_pokemon((row, column), 'N', 20)) # 应该打印 (115, 140)
print(move_pokemon((row, column), 'E', 20)) # 应该打印 (135, 150)
print(move_pokemon((row, column), 'S', 20)) # 应该打印 (150, 140)
print(move_pokemon((row, column), 'W', 20)) # 应该打印 (135, 120)
```
现在,编写一些代码,为输入的每个命令调用这些函数,并相应地更新皮卡丘的位置。
在文件 `hw3_part2_01.txt``hw3_part2_02.txt` (可以在 `hw03_files.zip` 文件中找到) 中提供了使用 Spyder IDE 运行程序时的两个示例 (它运行时的样子)。在 `hw3_part2_01.txt` 中,请注意 `f` 是无效方向,所以它对皮卡丘的状态没有影响,而 `r` 是无效的宝可梦类型,在结果列表中被标记为 "No Pokemon"。
我们将使用示例文件中的值以及其他一系列值来测试你的代码。好好测试你的代码,当你确定它可以工作时,请将其作为名为 `hw3_part2.py` 的文件提交到 Submitty 作为家庭作业的第 2 部分。
## 第 3 部分: 种群变化 - 有熊 (20 分)
你将编写一个程序来计算一种类似于你在实验 3 中计算的兔子和狐狸的种群平衡问题。这个问题将涉及熊、浆果田和游客。我们将只使用 "浆果" 这个词来表示浆果田的面积。我们也将计算熊和游客的数量。
熊需要大量的浆果来生存并为冬天做准备。因此,浆果田的面积对它们的种群非常重要。浆果田通常会随着时间的推移而扩散,但如果被熊过度践踏,它们可能会停止生长,面积可能会缩小。游客是熊最大的敌人,经常使它们习惯于人类,导致攻击性行为。可悲的是,这可能导致熊被杀死以避免对人类生命的威胁。
下面是每个群体从一年到下一年之间的种群联系方式。假设变量 `bears` 存储在给定年份的熊的数量, `berries` 存储浆果田的面积。
- 给定年份的游客数量按以下方式确定。如果熊的数量少于 4 只或多于 15 只,就没有游客。对他们来说,要么不够有趣,要么太危险。在其他情况下,每只熊最多有 10,000 名游客,每增加一只熊就有 20,000 名游客。为计算游客编写一个函数并单独测试它是一个好主意。
- 根据给定年份的熊、浆果和游客的数量,下一年的熊和浆果的数量由以下公式决定:
```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)
```
请记住,这些值都不能最终为负数。负值应该被限制为零。此外,熊和游客是整数。 `log` 函数在 `math` 模块中。
你必须编写一个函数,它接受给定年份的熊、浆果和游客的数量作为输入,并返回下一年的熊数量和浆果田面积作为元组。
```python
>>> find_next(5, 1000, 40000)
(5, 1071.1984678861438)
```
然后编写主程序,读取两个值,即当前的熊数量和浆果田面积。你的程序然后找到并打印第一年和另外 9 年 (总共 10 年) 的所有三个群体 (熊、浆果和游客) 的数量。你必须使用循环来做到这一点。输出的格式是,所有值都以列的形式打印出来,并在每一列内左对齐。每一列的宽度正好是 10 个字符 (如果需要,用空格填充)。所有浮点值需要打印成正好一位小数。
完成后,你的程序应该输出: 在你的计算中达到的熊、浆果和游客数量的最小值和最大值。这些值应该使用与每年种群值相同的格式规则输出。
文件 `hw3_part3_01.txt` (可以在 `hw03_files.zip` 文件中找到) 提供了一个使用 Spyder IDE 运行程序时的示例 (它运行时的样子)。请注意,熊的数量可能会降到零,然后再回升。为什么? 邻近地区的熊可以迁移过来。熊、浆果和游客的最小值和最大值可能来自不同的年份。
我们将使用示例文件中的值以及其他一系列值来测试你的代码。好好测试你的代码,当你确定它可以工作时,请将其作为名为 `hw3_part3.py` 的文件提交到 Submitty 作为家庭作业的第 3 部分。
## 支持文件
{{< link href="HW3.zip" content="HW3.zip" title="下载 HW3.zip" download="HW3.zip" card=true >}}
## 参考答案
### 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,389 @@
---
title: CSCI 1100 - 作业 4 - 循环和列表;密码和隔离
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: 本文概述了 CSCI 1100 计算机科学导论课程第四次作业的要求和指南。作业包括两部分内容:使用 Python 编程评估密码强度,以及分析 COVID-19 疫情期间各州的隔离情况。
keywords: ["CSCI 1100","计算机科学","Python","密码强度","COVID-19"]
license:
comment: true
weight: 0
tags:
- CSCI 1100
- 作业
- RPI
- Python
- 编程
categories:
- 编程语言
collections:
- CSCI 1100
hiddenFromHomePage: false
hiddenFromSearch: false
hiddenFromRss: false
hiddenFromRelated: false
summary: 本文概述了 CSCI 1100 计算机科学导论课程第四次作业的要求和指南。作业包括两部分内容:使用 Python 编程评估密码强度,以及分析 COVID-19 疫情期间各州的隔离情况。
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:
# 查看详细的 front matter: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter
---
<!--more-->
## 作业概述
本次作业总分为 100 分,将计入你的总作业成绩。截止日期为一周后,即 2024 年 2 月 22 日(星期四)晚上 11:59:59。和往常一样作业包括自动评分、教师测试用例评分和助教评分三部分。作业分为两个部分需分别提交。所有部分都必须在截止日期前提交否则你的程序将被视为逾期。
关于评分标准和过度合作的讨论,请参阅提交指南和合作政策手册。这些规则将在本学期剩余时间内持续有效。
你需要使用我们在 `hw4_files.zip` 中提供的实用工具和数据文件,所以请务必从 Submitty 的课程资料部分下载该文件,并将其解压缩到你的作业 4 目录中。
`hw4_util.py` 模块旨在帮助你从文件中读取信息。你不需要了解 `hw4_util.py` 中提供的函数是如何实现的(但如果你感兴趣,可以随意查看代码),只需直接使用它们即可。
最后需要注意的是,你需要在本次作业中使用循环。我们将根据任务和你的个人偏好,让你自行选择使用 while 循环还是 for 循环。
## 第一部分:密码强度
创建密码时,通常会评估其强度。强度估计是通过应用几个规则来计算的,包括密码长度、特定类型字符的存在、与常见密码的匹配程度,甚至与车牌号的匹配程度。在作业的这一部分,你将实现一些简单的强度判断规则,然后确定密码是被拒绝,还是被评为差、一般、好或优秀。
你的程序应该先要求用户输入一个密码并读取它。然后根据以下规则评估密码强度。每个规则都会对一个数值分数(初始为 0产生影响
1. **长度**:如果密码长度为 6 或 7 个字符,则加 1 分;如果长度为 8、9 或 10 个字符,则加 2 分;如果长度超过 10 个字符,则加 3 分。
2. **大小写**:如果密码包含至少两个大写字母和两个小写字母,则加 2 分;如果至少包含一个大写字母和一个小写字母,则加 1 分。
3. **数字**:如果密码包含至少两个数字,则加 2 分;如果至少包含一个数字,则加 1 分。
4. **标点符号**:如果密码包含至少一个 !@#$ 符号,则加 1 分;如果至少包含一个 %^&* 符号,则再加 1 分(总共最多加 2 分)。
5. **纽约车牌**:如果密码包含三个字母(大写或小写)后跟四个数字,则可能与纽约州车牌号格式匹配。在这种情况下,扣 2 分。
6. **常见密码**:如果密码的小写形式与常见密码列表中的某个密码完全匹配,则扣 3 分。
每当应用一条规则导致分数发生变化时,生成一行解释性输出。在应用所有规则后,输出最终得分,然后将其转换为密码的强度等级:
- **拒绝**:分数小于或等于 0。
- **差**:分数为 1 或 2。
- **一般**:分数为 3 或 4。
- **好**:分数为 5 或 6。
- **优秀**:分数为 7 或以上。
### 注意事项
1. 对于第一部分和第二部分,你应该编写函数以保持代码的整洁、清晰和易于管理。
2. 我们为你提供了许多示例,展示了输出值和格式。请仔细遵循这些示例。
3. 常见密码是从文件中提取的。我们提供的实用函数之一会读取该文件并返回这些密码的列表。要使用此函数,首先确保 `hw4_util.py``password_list_top_100.txt` 与你的代码在同一文件夹中。然后在你的程序中添加以下行:
```python
import hw4_util
```
最后,调用不带任何参数的函数 `hw4_util.part1_get_top()`。它将返回一个包含 100 个密码的字符串列表供你进行比较。
4. 只提交你的程序文件 `hw4_part1.py`。不要提交 `hw4_util.py`。
## 第二部分COVID-19 隔离州
纽约州 COVID-19 旅行建议 [COVID-19 Travel Advisory](https://coronavirus.health.ny.gov/covid-19-travel-advisory) 要求从 COVID-19 社区传播严重的州来到纽约的个人必须自我隔离 14 天。一个州的"严重传播"是指:
- 在过去七天中,平均每天每 10 万居民中有超过 10 人检测呈阳性,或者
- 在过去七天中,平均每天超过 10% 的检测呈阳性。
我们将具有严重传播的州称为隔离州。在作业的这一部分中,你将使用从 [COVID Tracking Project](https://covidtracking.com/) 下载的各州数据来回答有关哪些州是隔离州以及何时是隔离州的查询。
我们获得的数据是在 2023 年 10 月 5 日以大型"逗号分隔值"文件的形式下载的。该文件每个州每天包含一行,每行有许多字段。我们已将其浓缩为适合 CS1 作业的形式。这些数据是根据知识共享 BY 4.0 许可证共享的,这意味着我们可以:
- 共享:以任何媒体或格式复制和重新分发材料,以及
- 改编:以任何目的重新混合、转换和构建材料,甚至是商业目的。
我们提供了一个简单的实用程序,让你可以访问浓缩后的数据。要使用它(与第一部分类似),你必须在与你自己的代码相同的文件夹中拥有 `hw4_util.py` 和 `prob2_data.csv` 文件。然后你必须在程序中导入 `hw4_util` 模块:
```python
import hw4_util
```
`hw4_util` 有一个名为 `part2_get_week` 的函数,它接受一个整数参数 `w`,并返回一个列表的列表。参数 `w` 是前几周的索引,其中 `w==1` 表示最近一周,`w==2` 表示前一周,以此类推,直到 `w==29`,对应于 29 周前,一直追溯到 3 月 15 日。返回的列表包含每个州一个子列表,加上哥伦比亚特区 (DC) 和波多黎各 (PR),总共 52 个。每个州的子列表有 16 个元素:
- 元素 0 是一个字符串,表示两个字母(大写)的州缩写。这些缩写是正确的。
- 元素 1 是一个整数,表示该州的人口估计值,来自 2019 年人口普查局估计 [Census Bureau estimate](https://www.census.gov/newsroom/press-kits/2019/national-state-estimates.html)。
- 元素 2-8 是指定周的七天中每一天该州的阳性检测数,最近的日期在前。
- 元素 9-15 是指定周的七天中每一天该州的阴性检测数,最近的日期在前。
例如,第 1 周阿拉斯加州的子列表是:
```text
['AK',\
731545,\
189,147,128,132,106,125,118,\
3373,3819,6839,4984,6045,6140,1688]
```
以下是你在这个作业中需要完成的任务。你的程序应该在一个循环中,首先要求用户指定一个周的索引,如上所述。(你可以假设输入一个整数作为周数。)负数表示程序应该结束。对于非负数,如果该周的数据不可用,函数将返回一个空列表;在这种情况下,跳过循环体的其余部分。否则,在获得列表的列表后,程序应该回答关于该周的四个不同信息请求之一。回答请求首先由用户输入一个关键字。关键字包括 'daily'、'pct'、'quar'、'high'。对于每个请求,程序必须执行以下操作:
- **'daily'**:询问用户州缩写,然后输出该州在给定周内平均每日每 10 万人中的阳性病例数,精确到小数点后一位。
- **'pct'**:询问用户州缩写,然后输出该州在给定周内平均每日检测阳性百分比,精确到百分之一。
- **'quar'**:按两个字母缩写的字母顺序输出给定周的旅行隔离州的州缩写列表,如上所述。每行应有十个州缩写,使用你的缩写列表调用 `hw4_util.print_abbreviations` 函数以按要求打印输出。(注意:每周至少有一个隔离州。)
- **'high'**:输出在给定周内平均每日每 10 万人中阳性病例数最高的州的两个字母缩写,并输出这个平均数,精确到小数点后一位。
输入的关键字和州缩写可以使用大写或小写字母,程序仍然应该能够正确匹配。如果关键字不是这四个之一,或者由于州缩写输入错误而未找到对应的州,则输出一个简单的错误消息,并在当前循环迭代中不执行其他操作。
## 注意事项
1. 和往常一样,查看我们提供的示例输出并准确遵循它。
2. 所有报告的阳性和阴性检测结果数量至少为 0但有些可能为 0。不过你可以假设不会出现一周内所有日子的阴性检测数都为 0 的情况。
3. 通过对一周的阳性病例求和以及对一周的阴性病例求和来计算每日检测阳性的百分比。如果这些和分别为 P 和 N则阳性百分比为 $P/(P+N) * 100$。这与一周内每日百分比的平均值不完全相同,但更容易计算。
4. 只提交你的程序文件 `hw4_part2.py`。不要提交 `hw4_util.py`。
## 支持文件
{{< link href="HW4.zip" content="HW4.zip" title="下载 HW4.zip" download="HW4.zip" card=true >}}
## 参考答案
### 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 - 作业5 - 嵌套列表、网格和路径规划
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: 本文概述了 CSCI 1100 计算机科学导论课程中一项关于使用 Python 进行嵌套列表、网格和路径规划的编程作业。文章包括每个部分的问题描述、指导方针和示例输出。
keywords: ["Python","计算机科学","列表","网格","路径规划"]
license:
comment: true
weight: 0
tags:
- CSCI 1100
- 作业
- RPI
- Python
- 编程
categories:
- 编程语言
collections:
- CSCI 1100
hiddenFromHomePage: false
hiddenFromSearch: false
hiddenFromRss: false
hiddenFromRelated: false
summary: 本文概述了 CSCI 1100 计算机科学导论课程中一项关于使用 Python 进行嵌套列表、网格和路径规划的编程作业。文章包括每个部分的问题描述、指导方针和示例输出。
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:
# 有关详细信息请参阅前言https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter
---
<!--more-->
## 作业概述
本次作业总分值 100 分,将计入你的总作业成绩。截止日期为 2024 年 2 月 29 日星期四晚上 11:59:59。和往常一样作业评分由自动评分、讲师测试用例和助教评分三部分组成。作业分为两个部分需分别提交。两部分都应在截止日期前提交否则将被视为逾期。
关于评分标准和过度合作的定义,请参阅提交指南和合作政策。这些规则将在本学期剩余时间内执行。
你将需要我们在 `hw5_files.zip` 中提供的数据文件,请务必从 Submitty 的课程资料部分下载并解压到你的作业 5 目录。压缩包内包含实用代码、数据文件以及程序的示例输入/输出。
## 问题描述
计算机科学和工程领域的许多问题都是在二维数值网格上求解的,常用技术包括"梯度上升(或下降)"、贪心搜索或爬山算法。我们将使用手工生成的高程数据来研究其简化版本。
我们主要使用的表示方法是"高度"(也称"海拔",这里简称"高度")的嵌套列表。例如:
```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]]
```
这个网格包含四个长度为六的整数列表。每个元素表示一个高度值如海拔高度以固定间隔测量间隔可小至厘米也可大至公里。美国地质调查局USGS和一些私营公司都在维护和分发此类高程数据。这些数据在评估径流、确定风力涡轮机位置以及规划道路和建设等方面都很重要。我们将以规划徒步路线为例来研究这个问题。
对于这些数据,我们可能会问以下问题:
1. 最高点(最大高度)在哪里?这也称为"全局最大值",因为它是数据中的最大值。在上例中,最大高度为 23出现在第 1 行第 2 列(简写为 (1, 2),假设第一个值表示行,第二个值表示列)。我们称 (1, 2) 为一个"位置"。
2. 数据中是否存在"局部最大值"?即高度大于周围值但小于全局最大值的点。在上例中,位置 (2, 4) 处的 22 就是一个局部最大值。
3. 从给定位置出发,到达全局最大值的最佳路径是什么?这是一个棘手的问题,因为我们需要定义"最佳路径"。一个简单的定义是:能否从给定位置出发,只走最陡的路线到达全局最大值(是否能徒步到"山顶")?例如,从 (3, 0) 出发,经过 (3, 0)、(3, 1)、(3, 2)、(2, 2)、(1, 2) 的路径是最陡的,可以到达顶峰。这是一种"梯度上升"方法。但如果从 (3, 5) 出发,会生成路径 (3, 5)、(3, 4)、(2, 4),之后就无法继续向上到达全局最大值。
我们还可以提出并回答更多问题。有些问题很容易解决,有些则需要复杂的算法和大量计算。
在开始实际作业之前,我们需要定义网格中"相邻"位置的概念,即从给定位置允许走到的位置。在本作业中,从位置 (r, c) 出发,相邻位置包括 (r-1, c)、(r, c-1)、(r, c+1) 和 (r+1, c)。
换句话说,相邻位置必须与当前位置在同一行或同一列。此外,相邻位置不能超出网格边界。例如,对于位置 (r, 0),只有 (r-1, 0)、(r, 1)、(r+1, 0) 是允许的相邻位置。
## 入门指南
请下载 `hw5_files.zip` 并将所有文件放在你要编写解决方案的同一目录下。`hw5_util.py``hw5_grids.txt` 这两个文件非常重要:`hw5_util.py` 包含从 `hw5_grids.txt` 读取网格和起始位置的实用函数。具体来说:
- `hw5_util.num_grids()` 返回数据中不同网格的数量。
- `hw5_util.get_grid(n)` 返回第 n 个网格,其中 n==1 表示第一个网格n == `hw5_util.num_grids()` 表示最后一个网格。
- `hw5_util.get_start_locations(n)` 返回一个元组列表,给出第 n 个网格要考虑的一个或多个起始位置。
- `hw5_util.get_path(n)` 返回一个元组列表,给出第 n 个网格的一条可能路径。
建议你先试用这些函数并打印结果,以确保你理解它们的功能。
你可以对数据做如下假设:
1. 网格至少有两行。
2. 每行至少有两个元素(列),且每行的列数相同。
3. 所有高度值都是正整数。
4. 起始位置都在网格的行列范围内。
5. 路径上的位置都在网格的行列范围内。
## 第一部分
编写一个 Python 程序 `hw5_part1.py`,完成以下任务:
1. 询问用户要使用的网格编号,并循环询问直到得到正确范围内的编号。将网格编号记为 n。
2. 获取第 n 个网格。
3. 询问用户是否要打印网格。如果用户输入单个字符 'Y' 或 'y',则打印网格,否则不打印。打印时可假设高度值小于 1000 米。参考示例输出。
4. 获取与第 n 个网格关联的起始位置,对于每个起始位置,打印其在网格边界内的相邻位置。例如,如果第 n 个网格有 8 行 10 列,起始位置列表为 `[(4, 6), (0, 3), (7, 9)]`,则输出应为:
```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)
```
非常重要:我们强烈建议你编写一个名为 `get_nbrs` 的函数,它接受行、列位置以及网格的行数和列数作为参数,返回一个元组列表,包含给定位置在网格边界内的所有相邻位置。你会经常用到这个函数。
5. 获取建议路径,判断它是否有效(每个位置都与下一个位置相邻),然后计算总下降高度和总上升高度。例如,对于上面的网格,如果路径为 `(3, 1), (3, 0), (2, 0), (1, 0), (1, 1), (0, 1), (0, 2), (1, 2)`,则下降高度为从 (3, 1) 到 (3, 0)(变化 4和从 (1, 1) 到 (0, 1)(变化 3总计 7上升高度为从 (3, 0) 到 (2, 0)、从 (2, 0) 到 (1, 0)、从 (1, 0) 到 (1, 1)、从 (0, 1) 到 (0, 2) 以及从 (0, 2) 到 (1, 2),总计 (2 + 1 + 6 + 2 + 5) = 16。输出应为
```plaintext
有效路径
下降 7
上升 16
```
如果路径无效,代码应输出 `路径:从 point1 到 point2 的无效步骤。` 其中 point1 和 point2 是表示无效步骤起点和终点的元组。
只提交文件 `hw5_part1.py`,不要提交其他任何内容。
## 第二部分
修改第一部分的解决方案,并将其提交为 `hw5_part2.py`。程序应再次要求用户输入网格编号,但不应打印网格。接下来,它应找到并输出全局最大高度的位置和高度值。例如,对于上面的简单网格,输出应为 `全局最大值:(1, 2) 23`。你可以不加验证地假设全局最大值是唯一的。
第二部分的主要任务是为网格的每个起始位置找到并输出两条路径。第一条是最陡峭的上升路径,第二条是最平缓的上升路径。每条路径上的步骤必须在相邻位置之间,与第一部分相同。此外,在每条路径上,不允许走到高度相同或更低的位置,并且步长(新位置与当前位置的高度差)不能超过最大步高(由用户输入)。
接下来,确定每条路径是到达了网格中全局最大高度的位置、局部最大值还是都不是。如果当前位置的唯一上升步骤相对于当前高度太高,就可能出现后一种情况。当然,真正的徒步路径可以上下起伏,但在这种更复杂的情况下寻找"最优路径"需要我们尚未准备好开发的更复杂算法。
以上面的网格为例:
```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]]
```
从位置 (3, 0) 出发,最大步高为 4最陡峭的路径是 (3, 0)、(3, 1)、(3, 2)、(2, 2)、(2, 3)、(1, 3)、(1, 2),最平缓的路径是 (3, 0)、(2, 0)、(1, 0)、(0, 0)、(0, 1)、(0, 2)、(0, 3)、(1, 3)、(1, 2)。两条路径都到达了全局最大值,并且在第一次接近时都避免了直接走到全局最大值,因为步高太大。注意,从位置 (3, 5) 出发的最陡峭和最平缓路径都将在局部最大值 (2, 4) 处结束。最陡峭的路径将在 4 步后结束(路径上有 5 个位置),最平缓的路径将在 6 步后结束(路径上有 7 个位置)。如果最大步高只有 3那么从 (3, 5) 出发的两条路径都将在到达任何最大值之前的位置 (3, 4) 处停止。
路径输出时每行 5 个位置,例如:
```plaintext
steepest path
(3, 0) (2, 0) (1, 0) (0, 0) (0, 1)
(0, 2) (0, 3) (1, 3) (1, 2)
global maximum
```
更多细节请参考示例输出。
最后,如果用户请求,输出一个"路径网格",在每个位置给出包含该位置的路径数量。这可以通过创建一个新的嵌套列表来处理,其中每个元素表示一个计数,初始化为 0。对于每条路径和路径上的每个位置 (i, j),应增加嵌套列表中相应的计数。最后,在生成所有路径并将其添加到计数后,输出网格。在此输出中,对于不在任何路径上的位置,不要输出 0而是输出 '.',这将使输出更清晰。请参阅示例输出。
## 注意事项
1. 在选择路径的下一个位置时,如果有多个选择,则选择 `get_nbrs` 函数生成的列表中较早出现的位置。例如,在上面的示例网格中,从高度为 11 的位置 (0, 5) 出发,(0, 4) 和 (1, 5) 的高度都是 12。在这种情况下(0, 4) 将在 `get_nbrs` 列表中较早出现,因此被选为路径上的下一个位置。
2. 在确保其他所有内容都正常工作之前,请不要处理路径网格输出(最后一步)。
3. 最平缓和最陡峭的路径都是贪心算法的示例,其中在每一步都做出当前最优选择,而不重新考虑之前的决定。更复杂的算法会考虑某种形式的回溯,即撤销决策并重新考虑替代方案。
## 支持文件
{{< link href="HW5.zip" content="HW5.zip" title="下载 HW5.zip" download="HW5.zip" card=true >}}
## 参考答案
### 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)
```