# A Tiny Challenge

#Basic

Let's do a tiny coding challenge that requires not only the bits and pieces we have learnt but also some research on new function/module.

# Assignment 14

Create a Python script named dice_rolling.py that prompts the user for the number of times to roll the two dices. Calculate the sum of the two dice values and count the percentage of occurrence for each sum value. The script then prints the result in a tabular format and saves it in a text file. Compare your actual results with the expectation.

A sample run looks like the following.

python dice_rolling.py
Enter Number of Times to Roll the Dices: 200
       Sum            Actual %          Expected %
         2                3.50                2.78
         3                7.50                5.56
         4                6.00                8.33
         5               11.00               11.11
         6               14.00               13.89
         7               16.00               16.67
         8               14.00               13.89
         9                8.50               11.11
        10               12.00                8.33
        11                4.00                5.56
        12                3.50                2.78
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Finally, create a public repository named dice_rolling in your GitHub account and push the dice_rolling.py script in it.

Here's a list of resources that may be helpful to you.

What happens if roll the dice many more times, say 1 million times?

Sample Solution
from collections import Counter
from itertools import product
from random import randint


def get_two_dices():
    num1 = randint(1, 6)
    num2 = randint(1, 6)
    return (num1, num2)


def summarize(rolls):
    result = Counter()
    for num1, num2 in rolls:
        result[num1 + num2] += 1

    return result


number_of_rolls = int(input("Enter Number of Times to Roll the Dices: "))
dice_numbers = range(1, 7)
actual = summarize([get_two_dices() for _ in range(number_of_rolls)])
expected = summarize(product(dice_numbers, dice_numbers))


outputs = []

outputs.append(f"{'Sum':>10}{'Actual %':>20}{'Expected %':>20}")
for num in range(2, 13):
    actual_percent = 100 * actual[num] / number_of_rolls
    expected_percent = 100 * expected[num] / 36
    outputs.append(f"{num:10.0f}{actual_percent:20.2f}{expected_percent:20.2f}")


print("\n".join(outputs))
with open("result.txt", "w") as f:
    f.write("\n".join(outputs))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# A generic counter

If you are given a list of numbers and told to count the number of appearances for each unique value, what would you do?

Sometimes you may know all the possible values beforehand. For example, you are told that the numbers are integers from 1 to 4 inclusively. It's very tempting to create some counter variables to represent the number of appearances.

Say, the numbers are stored in a list some_numbers, you may start with creating the following variables

number_of_ones = 0
number_of_twos = 0
number_of_threes = 0
number_of_fours = 0
1
2
3
4

then, iterate some_numbers to determine the count for each value

for number in some_numbers:
    if number == 1:
        number_of_ones += 1
    if number == 2:
        number_of_twos += 1
    if number == 3:
        number_of_threes += 1
    if number == 4:
        number_of_fours += 1
1
2
3
4
5
6
7
8
9

The logic sounds Okay but you MUST know all the values and hopefully there are NOT a lot of values. What if there are one thousand or one million possible values in the list? The code would become a nightmare to maintain.

Now let's step back and distill the core logic behind the counting exercise. It's simply doing one thing, which is to increment the counter value by one if that number appears.

One edge case you would have to handle is when that number appears for the first time. In this case, you can set the counter value to 1.

And since the outcome keeps track of a count for each number, we can use dictionary as the data type to store the information. Remind ourselves that a dictionary is a collection of key/value pairs. In the counting use case, we can use a key to represent the unique number and the associated value to represent the count.

To put the idea in code, you may have



 

 


result = {}
for number in some_numbers:
    if number not in result:
        result[number] = 1
    else:
        result[number] += 1
1
2
3
4
5
6

or, you can consider initializing the value to 0 then increasing by 1



 
 
 

result = {}
for number in some_numbers:
    if number not in result:
        result[number] = 0
    result[number] += 1
1
2
3
4
5

In this way, the code is a lot shorter and works in general, with or without the knowledge about what values are possible.

And counting items is a very common action, Python provides a class in the standard library for such purpose.

from collections import Counter

result = Counter(some_numbers)
1
2
3

# Formatting with f-string

We can use f-string to naturally construct message.

name = "Jack"
age = 20

print (f'My name is {name} and I am {age} years old.')
1
2
3
4

It also works with functions.

def greeting(name):
    return f"Hello, I'm {name}"

print(f"{greeting('Jill')}")
print(f"{name.lower()}")
1
2
3
4
5

Or simply values.

print(f"{2**10}")
print(f"{'Hi there'}")
1
2

We can apply specifiers to better format a string.

  1. Length of output and alignment
print(f"{'a':10} **")
1
print(f"{'a':>10} **")
1
print(f"{'a':^10} **")
1
print(f"{100:10} **")
1
print(f"{100:<10} **")
1
print(f"{100:^10} **")
1
  1. Decimal points
import math

print(f"{math.pi}")
print(f"{math.pi:.3f}")
print(f"{math.pi:.6f}")
1
2
3
4
5
  1. Using exponent notation
print(f"{math.pi:e}")
print(f"{2**100:.3e}")
1
2
  1. Percentage
print(f"{3/8:%}")
print(f"{1/8:.3%}")
1
2

# Working with files

We have done a lot print() statement to write values in the console. Let's see how we can save the results in a textual file.

To do so, we need a file object by using the open() function. "result.txt" is the name of file we are going to write some content into while "w" specifies the mode to be write for us to perform writing. The mode is by default "r" which only supports read.

f = open("result.txt", "w")
f.write("Hello World!")
f.close()
1
2
3

TIP

It's always a good practice to close any file object you open.

We can also use a context manager to automatically close the file object.

with open("result.txt", "w") as f:
    f.write("Hello World!")
1
2

Notice that we don't need to manually call close() function anymore since the context manager would handle for us.

We can also gather information from a textual file, instead of depending on user input from terminal.

with open("result.txt") as f:
    content = f.read()
1
2

The read() function would everything into a string. If we need to breakdown the reading per line, we can use readlines().

with open("result.txt") as f:
    content = f.readlines()
1
2

Also note that the file object f can be iterated.

with open("result.txt") as f:
    for line in f:
        print(line)
1
2
3