PGM2 week 4#
Basis#
ASCII Art#
Belangrijke beperking bij deze opdrachten: In deze opgave mag je de string-vermenigvuldig- en string-opteloperatoren niet gebruiken. Omdat ons doel is om lusconstructies te gebruiken, moet je lussen gebruiken om te herhalen, ook als het met deze operatoren korter zou kunnen. Hier is Ă©Ă©n uitzondering op, echter; je mag string-vermenigvuldiging gebruiken met het spatieteken
Opdracht 1#
Schrijf een functie met de naam print_rect die drie argumenten meekrijgt, width, height en symbol, en een vierkant van width bij height met symbolen afdrukt op het scherm.
def print_rect(width, height, symbol):
""" Drukt een vierkant van symbol af op het scherm van width bij height.
"""
for row in range(height):
for column in range(width):
print(symbol, end=" ")
print()
Om makkelijker bij te houden welke lus de rijen en welke de kolommen, wordt hier row en column als variable namen gebruikt in plaats van i en j.
Opdracht 2#
Schrijf een functie print_triangle die drie argumenten meekrijgt: width, symbol en right_side_up, en een driehoek van symbolen op het scherm afdrukt.
def print_triangle(width, symbol, right_side_up):
""" Drukt een driehoek van symbol af op het scherm met breedte van
width en right_side_up bepaalt of de punt naar boven (True) of naar
beneden (False) moet.
"""
for i in range(0, width):
if right_side_up : # Punt naar boven!
for j in range(0, i + 1):
print(symbol, end = " ")
else:
for j in range(0, width - i):
print(symbol, end = " ")
print()
Bij een punt naar boven bevat de eerste regel 1 symbool en hebben de volgende regels elke keer 1 symbool meer. Dit kun je ook zien als regel nummer staat gelijk aan het aantal symbolen dat naar het scherm geprint moet worden. Hier wordt gebruik van gemaakt door de range in de eerste j-for-lus (de kolom lus) af te laten hangen van i + 1. De + 1 is om te corrigeren dat de range van i begint bij nul.
Bij de punt naar beneden werken we van breed naar smal, van het maximale aantal terug naar 1 symbool. Daarom wordt in het else gedeelte met width - i gewerkt in de range van de for-lus. Hier corrigeren we de range nul van i niet omdat elke regel dan juist een symbool te weinig heeft.
Opdracht 3#
Gebruik nu je functie print_triangle om een functie genaamd print_bumps(num, symbol1, symbol2) te schrijven die het gegeven aantal “heuvels” van twee symbolen afdrukt, waarbij elke heuvel groter is dan de volgende.
def print_bumps(num, symbol1, symbol2):
""" Deze functie drukt het gegeven aantal “heuvels” van twee symbolen
af, waarbij elke heuvel groter is dan de volgende.
"""
for bumps in range(1, num + 1):
print_triangle(bumps, symbol1, True)
print_triangle(bumps, symbol2, False)
Het aantal “heuvels” neemt elke keer met 1 toe. Hier kunnen we de for-lus variable voor gebruiken.
Opdracht 4#
Schrijf een functie print_diamond(width, symbol) die een ruit met symbolen afdrukt waarvan de maximale breedte bepaald wordt door width. Voor deze “ruit”-functies mag je string-vermenigvuldiging gebruiken, maar alleen voor strings van spaties.
def print_diamond(width, symbol):
""" Drukt een ruit af gemaakt met symbol en maximale breedte width.
"""
# Het bovenste deel van de diamond
for i in range(1, width + 1):
print(" " * (width - i), end = "")
for j in range(0, i ):
print (symbol, end = " ")
print()
# Het onderste deel van de diamond
for i in range(1, width):
print(" " * (i), end = "")
for j in range(0, width - i ):
print (symbol, end = " ")
print()
Net als bij de print_triangle functie maken we hier gebruik van op welke regel (i) we zitten en of we van een laag aantal symbolen naar hoog gaan (bovenste deel van de ruit) of juist de andere kant op (het onderste deel van de ruit). In dit geval beginnen we alle ranges met 1 om zo de juiste aantal spaties voor het eerste symbool te krijgen.
Als je moeite hebt met het visualiseren van de opdracht dan kun je proberen om de ruit eerst uit te tekenen op ruitjes papier. Omdat we na het symbool spatie printen wordt de breedte van het symbool veld (width * 2) - 1. Variable i is de rij en variable j is de kolom.
Opdracht 5#
Schrijf nu een functie genaamd print_striped_diamond(width, sym1, sym2) die een “gestreepte ruit” van sym1 en sym2 afdrukt.
def print_striped_diamond(width, symbol1, symbol2):
""" Drukt een ruit gemaakt met symbol1 afgewisseld met symbol2 af met maximale breedte width.
"""
for i in range(1, width + 1):
print(" " * (width - i), end = "")
for j in range(0, i):
if j % 2 == 1:
print (symbol1, end = " ")
else:
print (symbol2, end = " ")
print()
for i in range(1, width):
print(" " * (i), end = "")
for j in range(0, width - i):
if i % 2 == 1:
if j % 2 == 0:
print (symbol1, end = " ")
else:
print (symbol2, end = " ")
else:
if j % 2 == 1:
print (symbol1, end = " ")
else:
print (symbol2, end = " ")
print()
Deze functie is hetzelfde als print_diamond, maar met toevoeging van de if-statement met de modulo operator en de rij (i) en kolom (j) variablen om te bepalen welk van de twee symbolen geprint moet worden.
Opdracht 6#
Schrijf een functie genaamd print_crazy_striped_diamond(width, sym1, sym2, sym1_width, sym2_width) die een “gestreepte ruit” van sym1 en sym2 afdrukt waarbij de strepen verschillende breedtes kunnen hebben
def print_crazy_striped_diamond(width, sym1, sym2, sym1_width, sym2_width):
for i in range(1, width+1):
print(" " * (width - i), end = "")
sym1Count = 0
sym2Count = 0
for j in range(0, i ):
if sym1Count < sym1_width:
print (sym1, end = " ")
sym1Count += 1
if sym1Count >= sym1_width:
sym2Count = 0
else:
print (sym2, end = " ")
sym2Count += 1
if sym2Count >= sym2_width:
sym1Count = 0
print()
for i in range(1, width):
print(" " * (i), end = "")
sym1Count = i % (sym1_width + sym2_width)
sym2Count = 0
if sym1Count >= sym1_width:
sym2Count = sym1Count - sym1_width
for j in range(0, width - i ):
if sym1Count < sym1_width:
print (sym1, end = " ")
sym1Count += 1
if sym1Count >= sym1_width:
sym2Count = 0
else:
print (sym2, end = " ")
sym2Count += 1
if sym2Count >= sym2_width:
sym1Count = 0
print()
Let goed op wanneer je de variablen aanmaakt in de for-lussen. Wanneer zijn ze nodig en wanneer hoeven ze niet meer te bestaan?
Context#
Mandelbrot#
Tijdens deze opdracht ga je een programma schrijven om de punten in en rond de mandelbrotverzameling weer te geven en te verkennen.
# laat deze importregel staan...
from png import *
#
# een testfunctie...
#
def test_fun():
""" algorithmic image-creation one pixel at a time...
this is a test function: it should output
an image named test.png in the same directory
"""
im = PNGImage(300, 200) # maak een afbeelding met width=300, height = 200
# Geneste lussen!
for r in range(200): # lust over de rijen met lusvariabele r
for c in range(300): # lust over de kolommen met c
if c == r:
im.plot_point(c, r, (255, 0, 0))
# else:
# im.plot_point( c, r, (255,0,0))
im.save_file()
#
# zet je functies hieronder neer:
#
def mult(c, n):
"""Mult uses only a loop and addition
to multiply c by the positive integer n
"""
result = 0
for i in range(n):
result += c
return result
assert mult(3, 5) == 15
assert mult(6, 7) == 42
assert mult(1.5, 28) == 42.0
def update(c, n):
"""Update starts with z = 0 and runs z = z**2 + c
for a total of n times. It returns the final z.
"""
z = 0
for i in range(n):
z = z ** 2 + c
return z
assert update(1, 3) == 5
assert update(-1, 3) == -1
assert update(-1, 10) == 0
def in_mset(c, n):
"""in_mset accepts
c for the update step of z = z**2+c
n, the maximum number of times to run that step
Then, it returns
False as soon as abs(z) gets larger than 2
True if abs(z) never gets larger than 2 (for n iterations)
"""
z = 0
for i in range(n):
z = z ** 2 + c
if abs(z) > 2:
return False
#return z
return True
c = 0 + 0j
assert in_mset(c, 25) == True
c = 3 + 4j
assert in_mset(c, 25) == False
c = 0.3 + -0.5j
assert in_mset(c, 25) == True
c = -0.7 + 0.3j
assert in_mset(c, 25) == False
c = 0.42 + 0.2j
assert in_mset(c, 25) == True
assert in_mset(c, 50) == False
def we_want_this_pixel(col, row):
"""This function returns True if we want to show
the pixel at col, row and False otherwise.
"""
if col % 10 == 0 and row % 10 == 0:
# if col % 10 == 0 or row % 10 == 0:
return True
else:
return False
def test():
"""This function demonstrates how
to create and save a PNG image.
"""
width = 300
height = 200
image = PNGImage(width, height)
# maak een lus om wat pixels te tekenen
for col in range(width):
for row in range(height):
if we_want_this_pixel(col, row):
image.plot_point(col, row)
# we hebben door alle pixels gelust; nu schrijven we het bestand
image.save_file()
# test()
def scale(pix, pix_max, float_min, float_max):
"""scale accepts
pix, the CURRENT pixel column (or row)
pix_max, the total # of pixel columns
float_min, the min floating-point value
float_max, the max floating-point value
scale returns the floating-point value
that corresponds to pix
"""
return float_min + (pix/pix_max * (float_max-float_min))
assert scale(100, 200, -2.0, 1.0) == -0.5
assert scale(100, 200, -1.5, 1.5) == 0.0
assert scale(100, 300, -2.0, 1.0) == -1.0
assert scale(25, 300, -2.0, 1.0) == -1.75
# print(scale(299, 300, -2.0, 1.0)) # == 0.99
def mset():
"""Creates a 300x200 image of the Mandelbrot set
"""
NUM_ITER = 50 # aantal updates
XMIN = -2.0 # de kleinste waarde voor de reële coördinaat
XMAX = 1.0 # de grootste waarde voor de reële coördinaat
YMIN = -1.0 # de kleinste waarde voor de imaginaire coördinaat
YMAX = 1.0 # de grootste waarde voor de imaginaire coördinaat
width = 300
height = 200
image = PNGImage(width, height)
# maak een lus om wat pixels te tekenen
for col in range(width):
for row in range(height):
# Gebruik scale twee keer:
# één keer om het reële deel van c te bepalen (x)
x = scale(col, width, XMIN, XMAX)
# Ă©Ă©n keer om het imaginaire deel van c te bepalen (y)
y = scale(row, height, YMIN, YMAX)
# DAARNA ken je c toe, kies je n en test je:
c = x + y*1j
#n = 25
if in_mset(c, NUM_ITER ):
image.plot_point(col, row, (255, 175, 0) )
else:
image.plot_point(col, row, (0, 0, 0))
# we hebben door alle pixels gelust; nu schrijven we het bestand
image.save_file()
# mset()