# Preliminaries¶

All assignments for this class will be fetched, worked-on, and submitted via a dynamic in-browser Python development and testing environment known as the Jupyter Notebook.

This first machine problem is intended to familiarize you with the environment and assignment retrieval/submission system, and to have you write some simple Python functions and test them using unit test cells, which will be found in all subsequent assignments.

## Fetching assignments¶

If you're reading this, then you're likely already familiar with the procedure for fetching an assignment. To recap:

• After logging in using your @hawk.iit.edu account, you'll either click "Start Server" or "My Server" to go to the Jupyter dashboard
• From there, go to the "Assignments" tab, where you'll see any newly released assignments in the "Released assignments" area. You can fetch the files by clicking the "Fetch" button next to each assignment.
• After an assignment has been fetched, you'll see it in the "Downloaded assignments" area, where you can expand the assignment to click on individual notebooks to open them up. You can also validate and submit your work here. Alternatively, you can also browse into an assignment folder from the "Files" tab and click on notebook files to open them up there.

## Exercise 1: Factorial¶

Most of the machine problems you'll be working on will have auto-graded pieces. Typically, these involve functions you need to complete, paired with test-cases written for you.

Below, for instance, is a stubbed out factorial function for you to complete. If you've forgotten, the factorial of a positive integer n is simply the product of all integers from n down through 1. E.g., the factorial of $5 = 5 \times 4 \times 3 \times 2 \times 1 = 120$.

Go ahead and complete the implementation of factorial now. (You should delete the comment and the raise statement.)

In [ ]:
def factorial(n):
raise NotImplementedError()


When you're done with your solution, you can run the tests in the cell below (but don't modify its contents!) to see how you did. Any errors will be displayed as output; if there is no output after the cell is evaluated, it means you passed all the tests contained therein.

In [ ]:
# (2 points)
import unittest
tc = unittest.TestCase()
tc.assertEqual(factorial(1), 1)
tc.assertEqual(factorial(5), 120)
tc.assertEqual(factorial(10), 3628800)


## Exercise 2: Multiples of 3 and 5¶

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Complete the following function, which finds the sum of all the multiples of 3 or 5 below the argument n.

In [ ]:
def multiples_of_3_and_5(n):
raise NotImplementedError()

In [ ]:
# (3 points)
import unittest
tc = unittest.TestCase()
tc.assertEqual(multiples_of_3_and_5(10), 23)
tc.assertEqual(multiples_of_3_and_5(500), 57918)
tc.assertEqual(multiples_of_3_and_5(1000), 233168)


## Exercise 3: Integer Right Triangles¶

Given a perimeter of 60, we can find two right triangles with integral length sides: [(10, 24, 26), (15, 20, 25)]. Complete the following function, which takes an integer p and returns a list of tuples (a, b, c) corresponding to the integral lengths of the sides of comforming right triangles. Each tuple should have $a \le b \lt c$, and the list should contain no duplicate solutions, and be sorted in order of ascending a.

In [ ]:
def integer_right_triangles(p):
raise NotImplementedError()

In [ ]:
# (1 point)
import unittest
tc = unittest.TestCase()
tc.assertEqual(integer_right_triangles(60), [(10, 24, 26), (15, 20, 25)])

In [ ]:
# (3 points)
import unittest
tc = unittest.TestCase()
tc.assertEqual(integer_right_triangles(100), [])
tc.assertEqual(integer_right_triangles(180), [(18, 80, 82), (30, 72, 78), (45, 60, 75)])
tc.assertEqual(integer_right_triangles(840),
[(40, 399, 401),
(56, 390, 394),
(105, 360, 375),
(120, 350, 370),
(140, 336, 364),
(168, 315, 357),
(210, 280, 350),
(240, 252, 348)])


## Exercise 4: Simple ASCII Art¶

For this next exercise, you'll need to complete the function gen_pattern, which, when called with a string of length $\ge$ 1, will generate an ASCII art pattern of concentric diamonds using those characters. The following are examples of patterns returned by the function:

> print(gen_pattern('X'))

X

> print(gen_pattern('XY'))

..Y..
Y.X.Y
..Y..

> print(gen_pattern('WXYZ'))

......Z......
....Z.Y.Z....
..Z.Y.X.Y.Z..
Z.Y.X.W.X.Y.Z
..Z.Y.X.Y.Z..
....Z.Y.Z....
......Z......



Note that the function will return the pattern as a string (as opposed to printing it out), and so each line of the pattern should be separated by a newline, written as '\n' in Python. The second pattern above, as returned by gen_pattern, would be ''..Y..\nY.X.Y\n..Y..'.

You ought to find the string join and center methods helpful in your implementation. They are demonstrated here:

> '*'.join(['one', 'two', 'three'])

'one*two*three'

> '*'.join('abcde')

'a*b*c*d*e'

> 'hello'.center(11, '*')

'***hello***'



Complete the gen_pattern function, below:

In [ ]:
def gen_pattern(chars):
raise NotImplementedError()

In [ ]:
# (2 points)
import unittest
tc = unittest.TestCase()
tc.assertEqual(gen_pattern('@'), '@')
tc.assertEqual(gen_pattern('@%'),
'''..%..
%.@.%
..%..''')

In [ ]:
# (2 points)
import unittest
tc = unittest.TestCase()
tc.assertEqual(gen_pattern('ABC'),
'''....C....
..C.B.C..
C.B.A.B.C
..C.B.C..
....C....''')
tc.assertEqual(gen_pattern('#####'),
'''........#........
......#.#.#......
....#.#.#.#.#....
..#.#.#.#.#.#.#..
#.#.#.#.#.#.#.#.#
..#.#.#.#.#.#.#..
....#.#.#.#.#....
......#.#.#......
........#........''')

In [ ]:
# (2 points)
import unittest
tc = unittest.TestCase()
tc.assertEqual(gen_pattern('abcdefghijklmnop'),
'''..............................p..............................
............................p.o.p............................
..........................p.o.n.o.p..........................
........................p.o.n.m.n.o.p........................
......................p.o.n.m.l.m.n.o.p......................
....................p.o.n.m.l.k.l.m.n.o.p....................
..................p.o.n.m.l.k.j.k.l.m.n.o.p..................
................p.o.n.m.l.k.j.i.j.k.l.m.n.o.p................
..............p.o.n.m.l.k.j.i.h.i.j.k.l.m.n.o.p..............
............p.o.n.m.l.k.j.i.h.g.h.i.j.k.l.m.n.o.p............
..........p.o.n.m.l.k.j.i.h.g.f.g.h.i.j.k.l.m.n.o.p..........
........p.o.n.m.l.k.j.i.h.g.f.e.f.g.h.i.j.k.l.m.n.o.p........
......p.o.n.m.l.k.j.i.h.g.f.e.d.e.f.g.h.i.j.k.l.m.n.o.p......
....p.o.n.m.l.k.j.i.h.g.f.e.d.c.d.e.f.g.h.i.j.k.l.m.n.o.p....
..p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p..
p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p
..p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p..
....p.o.n.m.l.k.j.i.h.g.f.e.d.c.d.e.f.g.h.i.j.k.l.m.n.o.p....
......p.o.n.m.l.k.j.i.h.g.f.e.d.e.f.g.h.i.j.k.l.m.n.o.p......
........p.o.n.m.l.k.j.i.h.g.f.e.f.g.h.i.j.k.l.m.n.o.p........
..........p.o.n.m.l.k.j.i.h.g.f.g.h.i.j.k.l.m.n.o.p..........
............p.o.n.m.l.k.j.i.h.g.h.i.j.k.l.m.n.o.p............
..............p.o.n.m.l.k.j.i.h.i.j.k.l.m.n.o.p..............
................p.o.n.m.l.k.j.i.j.k.l.m.n.o.p................
..................p.o.n.m.l.k.j.k.l.m.n.o.p..................
....................p.o.n.m.l.k.l.m.n.o.p....................
......................p.o.n.m.l.m.n.o.p......................
........................p.o.n.m.n.o.p........................
..........................p.o.n.o.p..........................
............................p.o.p............................
..............................p..............................''')


## Submission¶

When you're ready to submit your work, make sure it's saved (you can click the disk icon in the menu bar), then go back to the "Assignments" tab and click "Submit" next to this assignment in the "Downloaded assignments" area. You can submit as many times as you like before the due date -- you'll see your submissions listed in the "Submitted assignments" area.

That's it for now!