Assignment Review
===
**作者 - 侯柏宇
編輯 - BESTCI跨域人才程式能力培育計畫 / NTU BESA**
**項目**
==Assignment 1 & 2==
**共筆內容**
## 作業解析
### 前言
每一題作業都有許多種解題方式,底下只是提供其中一種想法供大家參考,若有任何疑問都可以提出來討論!
每題的解析都是按照:
- 思考邏輯
- 拆解問題(Decomposition)
- 列出相對應function
- 最終將function定義完成
---
### 1-1
 
- Decomposition:
1. 移動到beeper ⇒ move_to_newspaper()
2. 拿起beeper ⇒ pick_beeper()
3. 移動回原點 ⇒ back_home()
4. 放下beeper ⇒ put_beeper()
- 列出functions:
```python=
def main():
move_to_newspaper()
pick_beeper()
back_home()
put_beeper()
```
- 定義functions:
```python=
def move_to_newspaper():
move()
move()
turn_right()
move()
turn_left()
move()
def back_home():
turn_around()
for i in range(3):
move()
turn_right()
move()
turn_right()
def turn_right():
for i in range(3):
turn_left()
def turn_around():
for i in range(2):
turn_left()
```
- 參考解答:
```python=
def main():
"""
This file shows how Karel walks to door of its
house(Street 3, Avenue 6)and pick up the newspaper (beeper),
and then return to its initial position(Street 3, Avenue 3)
"""
move_to_newspaper()
pick_beeper()
back_home()
put_beeper()
def move_to_newspaper():
"""
Pre-condition: Karel is on the Street 3, Avenue 3, facing East
Post-condition: Karel is on the Street 3, Avenue 6, facing East
"""
turn_right()
move()
turn_left()
while not on_beeper():
move()
def back_home():
"""
Pre-condition: Karel is on the Street 3, Avenue 6, facing East
Post-condition: Karel is on the Street 3, Avenue 3, facing East
"""
turn_around()
for i in range(3):
move()
turn_right()
move()
turn_right()
def turn_right():
"""
Karel will turn left for 3 times
"""
for i in range(3):
turn_left()
def turn_around():
"""
Karel will turn left for 2 times
"""
for i in range(2):
turn_left()
```
---
### 1-2

- 思考邏輯:
填充奇數行的柱子都是由下而上填充,而填充偶數行的柱子則是由上而下填充
- Decomposition:
1. 填充奇數行的柱子 ⇒ build_odd_column()
2. 如果沒有碰到牆壁 ⇒ 移動到偶數的柱子
3. 填充偶數行的柱子 ⇒ build_even_column()
4. 如果沒有碰到牆壁 ⇒ 移動到奇數的柱子
- 列出functions:
```python=
def main():
build_odd_column()
while front_is_clear(): #如果沒有碰到牆壁,就移動到下一個柱子,並且填充柱子(重複)
for i in range(4):
move()
build_even_column()
if front_is_clear(): #如果沒有碰到牆壁,就移動到下一個柱子,並且填充柱子(單次)
for i in range(4):
move()
build_odd_column()
```
- 定義functions:
```python=
def build_odd_column():
turn_left() #讓karel轉向北方
if not on_beeper(): #如果一開始的位置沒有beeper,就放beeper
put_beeper()
while front_is_clear(): #如果沒有碰到牆壁就移動,並且如果移動後沒有在beeper上就放beeper
move()
if not on_beeper():
put_beeper()
turn_right() #讓karel轉向東方
def build_even_column():
turn_right() #讓karel轉向南方
if not on_beeper(): #如果一開始的位置沒有beeper,就放beeper
put_beeper()
while front_is_clear(): #如果沒有碰到牆壁就移動,並且如果移動後沒有在beeper上就放beeper
move()
if not on_beeper():
put_beeper()
turn_left() #讓karel轉向東方
def turn_right():
for i in range(3):
turn_left()
```
- 參考解答:
```python=
def main():
"""
This file shows how Karel builds the arches (regardless of the height
of the columns) with each column spaced 3 avenues apart.
"""
build_odd_column()
while front_is_clear():
for i in range(4):
move()
build_even_column()
if front_is_clear():
for i in range(4):
move()
build_odd_column()
def build_odd_column():
"""
Karel will build the odd column from bottom to top
Pre-condition: Karel is at the bottom of the column, facing East
Post:condition: Karel is at the top of the column, facing East
"""
turn_left()
# Karel at the bottom of the column, facing North
if not on_beeper():
put_beeper()
while front_is_clear():
move()
if not on_beeper():
put_beeper()
turn_right()
def build_even_column():
"""
Karel will build the even column from top to bottom
Pre-condition: Karel is at the top of the column, facing East
Post:condition: Karel is at the bottom of the column, facing East
"""
turn_right()
# Karel is at top of the column, facing South
if not on_beeper():
put_beeper()
while front_is_clear():
move()
if not on_beeper():
put_beeper()
turn_left()
def turn_right():
"""
Karel will turn left for 3 times
"""
for i in range(3):
turn_left()
```
---
### 1-3
 
- 思考邏輯:
除了第一列以外,其餘的偶數列都是由右向左間隔填充beeper,奇數列都是由左向右間隔填充beeper
不過由於不確定碰到牆壁時是否有踩在beeper上(會影響到往上後是否會需要填充beeper),所以會用if函數來區分成有踩在beeper與否
- Decomposition:
1. 第一列由左向右間隔填充beeper ⇒ fill_first_street()
2. 如果可以往上,就往上並由右向左間隔填充偶數列 ⇒ fill_even_street()
3. 如果可以往上,就往上並由左向右間隔填充奇數列 ⇒ fill_odd_street()
- 列出functions:
```python=
def main():
fill_first_street()
while front_is_clear(): #如果沒有碰到牆壁,就往上填充偶數列和奇數列(重複)
fill_even_street()
fill_odd_street()
```
- 定義functions:
```python=
def fill_first_street():
put_beeper()
while front_is_clear(): #如果沒有碰到牆壁,往前移動(重複)
move()
if front_is_clear(): #如果沒有碰到牆壁,先移動後放beeper(單次)
move()
put_beeper()
turn_left() #最後碰到牆壁後轉向北方
def fill_even_street():
if on_beeper(): #如果在beeper上,又如果可以往上走(沒有碰到牆壁),就移動後左轉(面向西方)
if front_is_clear():
move()
turn_left()
else: #如果沒有在beeper上,又如果可以往上走(沒有碰到牆壁),就移動後左轉(面向西方),再放置beeper
if front_is_clear():
move()
turn_left()
put_beeper()
while front_is_clear(): #如果沒有碰到牆壁,又會區分成有無踩在beeper上(重複)
if on_beeper(): #如果有在beeper上,就往前移動
move()
if front_is_clear(): #如果沒有碰到牆壁,先移動後放beeper(單次)
move()
put_beeper()
else: #如果沒有在beeper上
if front_is_clear():
move()
put_beeper()
turn_right() #最後碰到牆壁後轉向北方
def fill_odd_street():
if on_beeper(): #如果在beeper上,又如果可以往上走(沒有碰到牆壁),就移動後右轉(面向東方)
if front_is_clear():
move()
turn_right()
else: #如果沒有在beeper上,又如果可以往上走(沒有碰到牆壁),就移動後右轉(面向東方),再放置beeper
if front_is_clear():
move()
turn_right()
put_beeper()
while front_is_clear(): #如果沒有碰到牆壁,又會區分成有無踩在beeper上(重複)
if on_beeper(): #如果有在beeper上,就往前移動
move()
if front_is_clear(): #如果沒有碰到牆壁,先移動後放beeper(單次)
move()
put_beeper()
else: #如果沒有在beeper上
if front_is_clear():
move()
put_beeper()
turn_left() #最後碰到牆壁後轉向北方
def turn_right():
for i in range(3):
turn_left()
```
- 參考解答:
```python=
def main():
"""
This file shows how Karel draws a checkerboard with
beepers (each beeper spaced 1 avenue apart), regardless
of the rectangle size
"""
fill_first_street()
while front_is_clear():
fill_even_street()
fill_odd_street()
def fill_first_street():
"""
Karel will fill the first street with beepers, and each beeper spaced 1 avenue apart.
Pre-condition: Karel is at the left side of the first street, facing East
Post:condition: Karel is at the right side of the first street, facing North
"""
put_beeper()
while front_is_clear():
move()
if front_is_clear():
move()
put_beeper()
turn_left()
def fill_even_street():
"""
Karel will fill the even street with beepers, and each beeper spaced 1 avenue apart.
Pre-condition: Karel is at the right side of the previous street, facing North
Post:condition: Karel is at the left side of the this street, facing North
"""
if on_beeper():
if front_is_clear():
move()
turn_left()
else:
if front_is_clear():
move()
turn_left()
put_beeper()
# Karel is at the right side of this street, facing West
while front_is_clear():
if on_beeper():
move()
if front_is_clear():
move()
put_beeper()
else:
if front_is_clear():
move()
put_beeper()
turn_right()
def fill_odd_street():
"""
Karel will fill the odd street with beepers(except first street), and each
beeper spaced 1 avenue apart.
Pre-condition: Karel is at the left side of the previous street, facing North
Post:condition: Karel is at the right side of the this street, facing North
"""
if on_beeper():
if front_is_clear():
move()
turn_right()
else:
if front_is_clear():
move()
turn_right()
put_beeper()
# Karel is at the left side of this street, facing East
while front_is_clear():
if on_beeper():
move()
if front_is_clear():
move()
put_beeper()
else:
if front_is_clear():
move()
put_beeper()
turn_left()
def turn_right():
"""
Karel will turn left for 3 times
"""
for i in range(3):
turn_left()
```
---
### 1-4

- 思考邏輯:
為了要找出中點,利用左右放置beeper逐漸往中心點收縮,即可找到中心點
- Decomposition:
1. 找出右邊邊界,並放置beeper ⇒ find_the_wall()
2. 利用beeper,逐漸縮小範圍找到中心點 ⇒ find_midpoint()
3. 在中心點放置beeper
- 列出functions:
```python=
def main():
find_the_wall()
while on_beeper():
find_midpoint()
put_beeper()
```
- 定義functions:
```python=
def find_the_wall():
put_beeper() #在起點放置beeper
while front_is_clear():
move()
if not on_beeper():
put_beeper() #找到右邊邊界後,放置beeper
def find_midpoint():
pick_beeper()
turn_around()
if front_is_clear():
move()
if not on_beeper():
put_beeper() #由上一個beeper往中心點前進一格放置beeper
move()
while not on_beeper():
move() #karel會移動到更接近中心的beeper上
else:
pick_beeper() #karel最終會移除所有beeper
def turn_around():
turn_left()
turn_left()
```
- 參考解答:
```python=
def main():
"""
Karel will put a beeper on the corner closest to the center of 1st Street.
Pre-condition: Karel is at (1,1), facing East.
Post-condition: Karel is on the corner closest to the center of 1st Street, and a beeper is put at the same place.
"""
find_the_wall()
while on_beeper():
find_midpoint()
put_beeper() # A beeper is put on the corner closest to the center of 1st Street.
def find_the_wall():
"""
Pre-condition: Karel is at (1,1), facing East.
Post-condition: Karel is at the Southeast corner of the world, which is at the last avenue of 1st street, facing East.
There is a beeper put at (1,1), and a beeper put at the the last avenue of 1st street.
"""
put_beeper()
while front_is_clear():
move()
if not on_beeper():
put_beeper()
def find_midpoint():
"""
Pre-condition: Karel is at the Southeast corner of the world, which is at the last avenue of 1st street, facing East.
Post-condition: Karel is on the corner closest to the center of 1st Street.
"""
pick_beeper()
turn_around()
if front_is_clear():
move()
if not on_beeper():
put_beeper()
move()
while not on_beeper():
move() # Karel is moving the beepers to reach the corner closest to the center of 1st Street.
else:
pick_beeper() # karel picks all the beepers before puts the last one on the corner closest to the center of 1st Street.
def turn_around():
turn_left()
turn_left()
```
---
### 2-1

- 思考邏輯:
由於a是分母,因此不可為0
```python=
if a == 0:
print("The denominator can't be zero!")
```
再利用課堂上if、elif分別針對(b^2) - (4*a*c)的不同情況(>0、=0、<0)撰寫輸出結果
```python=
discriminant = (b*b) - (4*a*c)
if a == 0:
print("The denominator can't be zero!")
elif discriminant > 0:
x1 = (-b+math.sqrt(discriminant))/(2*a)
x2 = (-b-math.sqrt(discriminant))/(2*a)
print('Two roots: ' + str(x1) + ' , ' + str(x2))
elif discriminant == 0:
x = (-b/(2*a))
print('One root: ' + str(x))
else: #如果discriminant<0
print('No real roots')
```
- 參考解答:
```python=
def main():
"""
This file can calculate the quadratic: ax^2 + bx + c = 0
And the a, b, c can input by the user
"""
print('stanCode Quadratic Solver!')
a = float(input('Enter a: '))
b = float(input('Enter b: '))
c = float(input('Enter c: '))
# Calculate the discriminant value
discriminant = (b*b) - (4*a*c)
# Because a is the denominator, so a can't be zero
if a == 0:
print("The denominator can't be zero!")
# There are two roots
elif discriminant > 0:
x1 = (-b+math.sqrt(discriminant))/(2*a)
x2 = (-b-math.sqrt(discriminant))/(2*a)
print('Two roots: ' + str(x1) + ' , ' + str(x2))
# there is one root
elif discriminant == 0:
x = (-b/(2*a))
print('One root: ' + str(x))
# if discriminant < 0, there are no real roots
else:
print('No real roots')
```
---
### 2-2


- 思考邏輯:
由於題目要求要能夠更改常數(EXIT)後,印出的句子即改變
```python
tem = int(input('Next temperature: (or ' + str(EXIT) + ' to quit) '))
```
由於要計算平均溫度⇒要有輸入的數值總和及輸入的數值個數
要計算有幾天溫度小於16度
```python
if tem == EXIT:
print('No temperatures were entered.')
else:
maximum = tem
minimum = tem
mean = tem
cold = 0 #計算有幾天小於16度
num = 1 #計算輸入幾個數值
while True:
if tem < 16:
cold = cold + 1 #若輸入數值<16,會增加1
tem = int(input('Next temperature: (or ' + str(EXIT) + ' to quit) '))
if tem == EXIT:
break
mean = mean + tem #每次輸入數值都會加上去
num = num + 1 #每次輸入數值都會增加1
if tem > maximum:
maximum = tem
if tem < minimum:
minimum = tem
average = mean / num
```
- 參考解答:
```python=
# This constant controls when to stop
EXIT = -100
def main():
"""
When the user enters some temperatures, this file can
find the maximum, minimum temperature, calculate the
average temperature, and show how many day(s)'s
temperature is lower than 16 degree
"""
print('stanCode "Weather Master 4.0"!')
tem = int(input('Next temperature: (or ' + str(EXIT) + ' to quit) '))
if tem == EXIT:
print('No temperatures were entered.')
else:
maximum = tem
minimum = tem
mean = tem
# "cold" is used to calculate how many days the temperatures are lower than 16 degrees
cold = 0
# "num" is used to calculate how many temperatures the user enters
num = 1
while True:
if tem < 16:
cold = cold + 1
tem = int(input('Next temperature: (or ' + str(EXIT) + ' to quit) '))
if tem == EXIT:
break
mean = mean + tem
num = num + 1
if tem > maximum:
maximum = tem
if tem < minimum:
minimum = tem
average = mean / num
print('Highest temperature = ' + str(maximum))
print('Lowest temperature = ' + str(minimum))
print('Average = ' + str(average))
print(str(cold) + ' cold day(s)')
```
---
### 2-3

- 思考邏輯:
由於n要是正整數,因此若輸入n<0
```python
if n < 0:
print('The number must be a positive integer!')
```
要計算用了幾步會達到1
```python
n = int(input('Enter a number: '))
step = 0 #用來計算用了幾步才到達1
if n < 0:
print('The number must be a positive integer!')
else:
while n != 1:
if n % 2 == 0:
print(int(n), 'is even, so I take half:', int(hailstone(n)))
n = hailstone(n)
step = step + 1 #每進行一次n的改變就加1
else:
print(int(n), 'is odd, so I make 3n+1:', int(hailstone(n)))
n = hailstone(n)
step = step + 1
print('It took ' + str(step) + ' steps to reach 1.')
```
會根據得出的值是奇數/偶數,會進行不同運算,因此定義function⇒`hailstone(n)`
```python
def hailstone(n):
if n % 2 == 0:
n = n/2
return n
else:
n = (3*n)+1
return n
```
- 參考解答:
```python=
def main():
"""
When the user enters a positive integer, this file can compute Hailstone sequence
"""
print('This program computes Hailstone sequences')
n = int(input('Enter a number: '))
# "step" is used to calculate how many steps the program must take to reach 1
step = 0
# The number must be a positive integer to prevent the program from entering an infinite loop
if n < 0:
print('The number must be a positive integer!')
else:
while n != 1:
if n % 2 == 0:
print(int(n), 'is even, so I take half:', int(hailstone(n)))
n = hailstone(n)
step = step + 1
else:
print(int(n), 'is odd, so I make 3n+1:', int(hailstone(n)))
n = hailstone(n)
step = step + 1
print('It took ' + str(step) + ' steps to reach 1.')
def hailstone(n):
"""
The hailstone(n) can return the value, depending on "n" is odd or even
"""
if n % 2 == 0:
n = n/2
return n
else:
n = (3*n)+1
return n
```