Modified a part of the code of https://github.com/rlvaugh/Impractical_Python_Projects to work with Colab

Removed some docstrings and variables or changed them to Japanese

Chap1

In [1]:
import sys
VOWELS = 'aeiouy'
# word = input('なんか単語入れる')
word = 'ixnay on the ottenray'
if word[0] in VOWELS:
    pig_Latin = word + 'way'
else:
    pig_Latin = word[1:] + word[0] + 'ay'
print()
print("{}".format(pig_Latin), file=sys.stderr)

ixnay on the ottenrayway
In [2]:
import sys
import pprint
from collections import defaultdict
import string
text = 'Take the first step in faith. You don’t have to see the whole staircase, just take the first step.'
ALPHABET = string.ascii_lowercase

d = defaultdict(list)
for character in text:
    c = character.lower()
    if c in ALPHABET:
        d[c].append(c)
pprint.pprint(d, width=110)
defaultdict(<class 'list'>,
            {'a': ['a', 'a', 'a', 'a', 'a', 'a'],
             'c': ['c'],
             'd': ['d'],
             'e': ['e', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'e', 'e'],
             'f': ['f', 'f', 'f'],
             'h': ['h', 'h', 'h', 'h', 'h', 'h'],
             'i': ['i', 'i', 'i', 'i', 'i'],
             'j': ['j'],
             'k': ['k', 'k'],
             'l': ['l'],
             'n': ['n', 'n'],
             'o': ['o', 'o', 'o', 'o'],
             'p': ['p', 'p'],
             'r': ['r', 'r', 'r'],
             's': ['s', 's', 's', 's', 's', 's', 's', 's'],
             't': ['t', 't', 't', 't', 't', 't', 't', 't', 't', 't', 't', 't', 't', 't'],
             'u': ['u', 'u'],
             'v': ['v'],
             'w': ['w'],
             'y': ['y']})

Chap2

In [3]:
# aとi以外を取り除く
word_list = ['my', 'pet', 'is', 'a', 'dog', 'b', 'c']
clean = []
ok = ('a', 'i')
for w in word_list:
    if len(w) > 1:
        clean.append(w)
    elif len(w) == 1 and w in ok:
        clean.append(w)
    else:
        continue

print(clean)
['my', 'pet', 'is', 'a', 'dog']

Chap3

In [4]:
# 必要なファイルをダウンロードする
!wget https://raw.githubusercontent.com/en-wl/wordlist/master/alt12dicts/2of4brif.txt
--2020-08-20 10:44:17--  https://raw.githubusercontent.com/en-wl/wordlist/master/alt12dicts/2of4brif.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 563527 (550K) [text/plain]
Saving to: ‘2of4brif.txt’

2of4brif.txt        100%[===================>] 550.32K  --.-KB/s    in 0.07s   

2020-08-20 10:44:17 (7.86 MB/s) - ‘2of4brif.txt’ saved [563527/563527]

In [5]:
import sys
import re
from collections import defaultdict
from itertools import permutations

def load(file):
    with open(file) as f:
        txt = f.read().strip().split('\n')
        txt = [x.lower() for x in txt]
        return txt

word_list = load('2of4brif.txt')

name = 'Voldemort'  #(tmvoordle)
name = name.lower()

# generate unique letter pairs from name
digrams = set()
perms = {''.join(i) for i in permutations(name)}
for perm in perms:
    for i in range(0, len(perm) - 1):
        digrams.add(perm[i] + perm[i + 1])
print(*digrams, sep='\n')
print("\nNumber of digrams = {}\n".format(len(digrams)))

# use regular expressions to find repeating digrams in a word
mapped = defaultdict(int)
for word in word_list:
    word = word.lower()
    for digram in digrams:
        for m in re.finditer(digram, word):
            mapped[digram] += 1

print("digram frequency count:")
count = 0
for k in mapped:
    print("{} {}".format(k, mapped[k]))
rv
em
dv
or
mo
ol
lm
oo
dl
ve
mt
to
rd
lt
dr
et
tr
dm
md
vr
lr
me
ev
te
ed
ld
ov
de
rm
ot
vo
vl
el
od
dt
ro
vd
mv
er
lv
tl
vm
vt
mr
le
eo
tm
rl
om
rt
lo
re
do
oe
td
tv
ml

Number of digrams = 57

digram frequency count:
dv 78
rd 955
lo 2312
do 928
ed 7287
me 2460
em 1571
te 6856
to 2022
ot 1335
ev 648
re 6650
om 1773
or 3970
er 9875
et 2240
de 3861
tl 656
le 4935
rm 812
od 809
ol 2070
rt 1474
ve 2755
ov 796
el 2591
ro 3168
lv 138
tr 2586
dl 547
mo 1531
dr 601
tm 136
dm 100
lt 500
oo 1474
eo 365
vo 419
rl 394
lm 156
ml 58
ld 457
oe 267
lr 29
mr 16
dt 22
rv 287
vr 18
mv 7
td 27
mt 4
md 5
tv 4
vl 2

Chap4

In [6]:
from math import factorial
from itertools import permutations, product
# nの設定
pattern_num= 4
p = [x for x in range(1, pattern_num+1)]
print("pattern = {}".format(c))

# 負の順列も考慮するため
def perms(columns):
    results = []
    for perm in permutations(columns):
        for signs in product([-1, 1], repeat=len(columns)):
            results.append([i*sign for i, sign in zip(perm, signs)])
    return results

comb = perms(p)
print("pattern数 = {}".format(len(comb)))
print(*comb, sep="\n")  # comment-out for num_cols > 4!
pattern = .
pattern数 = 384
[-1, -2, -3, -4]
[-1, -2, -3, 4]
[-1, -2, 3, -4]
[-1, -2, 3, 4]
[-1, 2, -3, -4]
[-1, 2, -3, 4]
[-1, 2, 3, -4]
[-1, 2, 3, 4]
[1, -2, -3, -4]
[1, -2, -3, 4]
[1, -2, 3, -4]
[1, -2, 3, 4]
[1, 2, -3, -4]
[1, 2, -3, 4]
[1, 2, 3, -4]
[1, 2, 3, 4]
[-1, -2, -4, -3]
[-1, -2, -4, 3]
[-1, -2, 4, -3]
[-1, -2, 4, 3]
[-1, 2, -4, -3]
[-1, 2, -4, 3]
[-1, 2, 4, -3]
[-1, 2, 4, 3]
[1, -2, -4, -3]
[1, -2, -4, 3]
[1, -2, 4, -3]
[1, -2, 4, 3]
[1, 2, -4, -3]
[1, 2, -4, 3]
[1, 2, 4, -3]
[1, 2, 4, 3]
[-1, -3, -2, -4]
[-1, -3, -2, 4]
[-1, -3, 2, -4]
[-1, -3, 2, 4]
[-1, 3, -2, -4]
[-1, 3, -2, 4]
[-1, 3, 2, -4]
[-1, 3, 2, 4]
[1, -3, -2, -4]
[1, -3, -2, 4]
[1, -3, 2, -4]
[1, -3, 2, 4]
[1, 3, -2, -4]
[1, 3, -2, 4]
[1, 3, 2, -4]
[1, 3, 2, 4]
[-1, -3, -4, -2]
[-1, -3, -4, 2]
[-1, -3, 4, -2]
[-1, -3, 4, 2]
[-1, 3, -4, -2]
[-1, 3, -4, 2]
[-1, 3, 4, -2]
[-1, 3, 4, 2]
[1, -3, -4, -2]
[1, -3, -4, 2]
[1, -3, 4, -2]
[1, -3, 4, 2]
[1, 3, -4, -2]
[1, 3, -4, 2]
[1, 3, 4, -2]
[1, 3, 4, 2]
[-1, -4, -2, -3]
[-1, -4, -2, 3]
[-1, -4, 2, -3]
[-1, -4, 2, 3]
[-1, 4, -2, -3]
[-1, 4, -2, 3]
[-1, 4, 2, -3]
[-1, 4, 2, 3]
[1, -4, -2, -3]
[1, -4, -2, 3]
[1, -4, 2, -3]
[1, -4, 2, 3]
[1, 4, -2, -3]
[1, 4, -2, 3]
[1, 4, 2, -3]
[1, 4, 2, 3]
[-1, -4, -3, -2]
[-1, -4, -3, 2]
[-1, -4, 3, -2]
[-1, -4, 3, 2]
[-1, 4, -3, -2]
[-1, 4, -3, 2]
[-1, 4, 3, -2]
[-1, 4, 3, 2]
[1, -4, -3, -2]
[1, -4, -3, 2]
[1, -4, 3, -2]
[1, -4, 3, 2]
[1, 4, -3, -2]
[1, 4, -3, 2]
[1, 4, 3, -2]
[1, 4, 3, 2]
[-2, -1, -3, -4]
[-2, -1, -3, 4]
[-2, -1, 3, -4]
[-2, -1, 3, 4]
[-2, 1, -3, -4]
[-2, 1, -3, 4]
[-2, 1, 3, -4]
[-2, 1, 3, 4]
[2, -1, -3, -4]
[2, -1, -3, 4]
[2, -1, 3, -4]
[2, -1, 3, 4]
[2, 1, -3, -4]
[2, 1, -3, 4]
[2, 1, 3, -4]
[2, 1, 3, 4]
[-2, -1, -4, -3]
[-2, -1, -4, 3]
[-2, -1, 4, -3]
[-2, -1, 4, 3]
[-2, 1, -4, -3]
[-2, 1, -4, 3]
[-2, 1, 4, -3]
[-2, 1, 4, 3]
[2, -1, -4, -3]
[2, -1, -4, 3]
[2, -1, 4, -3]
[2, -1, 4, 3]
[2, 1, -4, -3]
[2, 1, -4, 3]
[2, 1, 4, -3]
[2, 1, 4, 3]
[-2, -3, -1, -4]
[-2, -3, -1, 4]
[-2, -3, 1, -4]
[-2, -3, 1, 4]
[-2, 3, -1, -4]
[-2, 3, -1, 4]
[-2, 3, 1, -4]
[-2, 3, 1, 4]
[2, -3, -1, -4]
[2, -3, -1, 4]
[2, -3, 1, -4]
[2, -3, 1, 4]
[2, 3, -1, -4]
[2, 3, -1, 4]
[2, 3, 1, -4]
[2, 3, 1, 4]
[-2, -3, -4, -1]
[-2, -3, -4, 1]
[-2, -3, 4, -1]
[-2, -3, 4, 1]
[-2, 3, -4, -1]
[-2, 3, -4, 1]
[-2, 3, 4, -1]
[-2, 3, 4, 1]
[2, -3, -4, -1]
[2, -3, -4, 1]
[2, -3, 4, -1]
[2, -3, 4, 1]
[2, 3, -4, -1]
[2, 3, -4, 1]
[2, 3, 4, -1]
[2, 3, 4, 1]
[-2, -4, -1, -3]
[-2, -4, -1, 3]
[-2, -4, 1, -3]
[-2, -4, 1, 3]
[-2, 4, -1, -3]
[-2, 4, -1, 3]
[-2, 4, 1, -3]
[-2, 4, 1, 3]
[2, -4, -1, -3]
[2, -4, -1, 3]
[2, -4, 1, -3]
[2, -4, 1, 3]
[2, 4, -1, -3]
[2, 4, -1, 3]
[2, 4, 1, -3]
[2, 4, 1, 3]
[-2, -4, -3, -1]
[-2, -4, -3, 1]
[-2, -4, 3, -1]
[-2, -4, 3, 1]
[-2, 4, -3, -1]
[-2, 4, -3, 1]
[-2, 4, 3, -1]
[-2, 4, 3, 1]
[2, -4, -3, -1]
[2, -4, -3, 1]
[2, -4, 3, -1]
[2, -4, 3, 1]
[2, 4, -3, -1]
[2, 4, -3, 1]
[2, 4, 3, -1]
[2, 4, 3, 1]
[-3, -1, -2, -4]
[-3, -1, -2, 4]
[-3, -1, 2, -4]
[-3, -1, 2, 4]
[-3, 1, -2, -4]
[-3, 1, -2, 4]
[-3, 1, 2, -4]
[-3, 1, 2, 4]
[3, -1, -2, -4]
[3, -1, -2, 4]
[3, -1, 2, -4]
[3, -1, 2, 4]
[3, 1, -2, -4]
[3, 1, -2, 4]
[3, 1, 2, -4]
[3, 1, 2, 4]
[-3, -1, -4, -2]
[-3, -1, -4, 2]
[-3, -1, 4, -2]
[-3, -1, 4, 2]
[-3, 1, -4, -2]
[-3, 1, -4, 2]
[-3, 1, 4, -2]
[-3, 1, 4, 2]
[3, -1, -4, -2]
[3, -1, -4, 2]
[3, -1, 4, -2]
[3, -1, 4, 2]
[3, 1, -4, -2]
[3, 1, -4, 2]
[3, 1, 4, -2]
[3, 1, 4, 2]
[-3, -2, -1, -4]
[-3, -2, -1, 4]
[-3, -2, 1, -4]
[-3, -2, 1, 4]
[-3, 2, -1, -4]
[-3, 2, -1, 4]
[-3, 2, 1, -4]
[-3, 2, 1, 4]
[3, -2, -1, -4]
[3, -2, -1, 4]
[3, -2, 1, -4]
[3, -2, 1, 4]
[3, 2, -1, -4]
[3, 2, -1, 4]
[3, 2, 1, -4]
[3, 2, 1, 4]
[-3, -2, -4, -1]
[-3, -2, -4, 1]
[-3, -2, 4, -1]
[-3, -2, 4, 1]
[-3, 2, -4, -1]
[-3, 2, -4, 1]
[-3, 2, 4, -1]
[-3, 2, 4, 1]
[3, -2, -4, -1]
[3, -2, -4, 1]
[3, -2, 4, -1]
[3, -2, 4, 1]
[3, 2, -4, -1]
[3, 2, -4, 1]
[3, 2, 4, -1]
[3, 2, 4, 1]
[-3, -4, -1, -2]
[-3, -4, -1, 2]
[-3, -4, 1, -2]
[-3, -4, 1, 2]
[-3, 4, -1, -2]
[-3, 4, -1, 2]
[-3, 4, 1, -2]
[-3, 4, 1, 2]
[3, -4, -1, -2]
[3, -4, -1, 2]
[3, -4, 1, -2]
[3, -4, 1, 2]
[3, 4, -1, -2]
[3, 4, -1, 2]
[3, 4, 1, -2]
[3, 4, 1, 2]
[-3, -4, -2, -1]
[-3, -4, -2, 1]
[-3, -4, 2, -1]
[-3, -4, 2, 1]
[-3, 4, -2, -1]
[-3, 4, -2, 1]
[-3, 4, 2, -1]
[-3, 4, 2, 1]
[3, -4, -2, -1]
[3, -4, -2, 1]
[3, -4, 2, -1]
[3, -4, 2, 1]
[3, 4, -2, -1]
[3, 4, -2, 1]
[3, 4, 2, -1]
[3, 4, 2, 1]
[-4, -1, -2, -3]
[-4, -1, -2, 3]
[-4, -1, 2, -3]
[-4, -1, 2, 3]
[-4, 1, -2, -3]
[-4, 1, -2, 3]
[-4, 1, 2, -3]
[-4, 1, 2, 3]
[4, -1, -2, -3]
[4, -1, -2, 3]
[4, -1, 2, -3]
[4, -1, 2, 3]
[4, 1, -2, -3]
[4, 1, -2, 3]
[4, 1, 2, -3]
[4, 1, 2, 3]
[-4, -1, -3, -2]
[-4, -1, -3, 2]
[-4, -1, 3, -2]
[-4, -1, 3, 2]
[-4, 1, -3, -2]
[-4, 1, -3, 2]
[-4, 1, 3, -2]
[-4, 1, 3, 2]
[4, -1, -3, -2]
[4, -1, -3, 2]
[4, -1, 3, -2]
[4, -1, 3, 2]
[4, 1, -3, -2]
[4, 1, -3, 2]
[4, 1, 3, -2]
[4, 1, 3, 2]
[-4, -2, -1, -3]
[-4, -2, -1, 3]
[-4, -2, 1, -3]
[-4, -2, 1, 3]
[-4, 2, -1, -3]
[-4, 2, -1, 3]
[-4, 2, 1, -3]
[-4, 2, 1, 3]
[4, -2, -1, -3]
[4, -2, -1, 3]
[4, -2, 1, -3]
[4, -2, 1, 3]
[4, 2, -1, -3]
[4, 2, -1, 3]
[4, 2, 1, -3]
[4, 2, 1, 3]
[-4, -2, -3, -1]
[-4, -2, -3, 1]
[-4, -2, 3, -1]
[-4, -2, 3, 1]
[-4, 2, -3, -1]
[-4, 2, -3, 1]
[-4, 2, 3, -1]
[-4, 2, 3, 1]
[4, -2, -3, -1]
[4, -2, -3, 1]
[4, -2, 3, -1]
[4, -2, 3, 1]
[4, 2, -3, -1]
[4, 2, -3, 1]
[4, 2, 3, -1]
[4, 2, 3, 1]
[-4, -3, -1, -2]
[-4, -3, -1, 2]
[-4, -3, 1, -2]
[-4, -3, 1, 2]
[-4, 3, -1, -2]
[-4, 3, -1, 2]
[-4, 3, 1, -2]
[-4, 3, 1, 2]
[4, -3, -1, -2]
[4, -3, -1, 2]
[4, -3, 1, -2]
[4, -3, 1, 2]
[4, 3, -1, -2]
[4, 3, -1, 2]
[4, 3, 1, -2]
[4, 3, 1, 2]
[-4, -3, -2, -1]
[-4, -3, -2, 1]
[-4, -3, 2, -1]
[-4, -3, 2, 1]
[-4, 3, -2, -1]
[-4, 3, -2, 1]
[-4, 3, 2, -1]
[-4, 3, 2, 1]
[4, -3, -2, -1]
[4, -3, -2, 1]
[4, -3, 2, -1]
[4, -3, 2, 1]
[4, 3, -2, -1]
[4, 3, -2, 1]
[4, 3, 2, -1]
[4, 3, 2, 1]

Chap5

In [7]:
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_5/colchester_message.txt
--2020-08-20 10:44:29--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_5/colchester_message.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 224 [text/plain]
Saving to: ‘colchester_message.txt’

colchester_message. 100%[===================>]     224  --.-KB/s    in 0s      

2020-08-20 10:44:29 (16.0 MB/s) - ‘colchester_message.txt’ saved [224/224]

In [8]:
import sys

def load(file):
    with open(file) as f:
        return f.read().strip()

# filename = input()
message = load('colchester_message.txt')

# check loaded message & # of lines
print("\nORIGINAL MESSAGE = {}\n".format(message))

# convert message to list and get length
message = message.split()
end = len(message)
# increment = int(input())
increment = 3  
for i in range(1, increment + 1):
    msg = list() 
    print('{}単語目の{}文字目'.format(i, i))
    count = i - 1
    location = i - 1
    for index, word in enumerate(message):
        if index == count:
            if location < len(word):
                msg.append(word[location])
                count += i
            else:
                print("Interval doesn't work", file=sys.stderr)
    
    print(*msg, sep='')
        
ORIGINAL MESSAGE = Sir John:  Odd and too hard, your lot.  Still, we will band together and, like you, persevere. 
Who else could love their enemies, stand firm when all others fail, hate and despair? 
While we all can, let us feel hope. -R.T.

1単語目の1文字目
SJOathylSwwbtalypWecltesfwaofhadWwaclufh-
2単語目の2文字目
onaoeanohohthtaeeaso
3単語目の3文字目
drinkovaltine

Chap6

In [9]:
!wget https://github.com/rlvaugh/Impractical_Python_Projects/raw/master/Chapter_6/realMessageChallenge.docx
--2020-08-20 10:44:37--  https://github.com/rlvaugh/Impractical_Python_Projects/raw/master/Chapter_6/realMessageChallenge.docx
Resolving github.com (github.com)... 140.82.114.3
Connecting to github.com (github.com)|140.82.114.3|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_6/realMessageChallenge.docx [following]
--2020-08-20 10:44:37--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_6/realMessageChallenge.docx
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 13448 (13K) [application/octet-stream]
Saving to: ‘realMessageChallenge.docx’

realMessageChalleng 100%[===================>]  13.13K  --.-KB/s    in 0.01s   

2020-08-20 10:44:37 (1.06 MB/s) - ‘realMessageChallenge.docx’ saved [13448/13448]

In [10]:
!wget https://github.com/rlvaugh/Impractical_Python_Projects/raw/master/Chapter_6/fakeMessage.docx
--2020-08-20 10:44:40--  https://github.com/rlvaugh/Impractical_Python_Projects/raw/master/Chapter_6/fakeMessage.docx
Resolving github.com (github.com)... 140.82.112.4
Connecting to github.com (github.com)|140.82.112.4|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_6/fakeMessage.docx [following]
--2020-08-20 10:44:40--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_6/fakeMessage.docx
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 12324 (12K) [application/octet-stream]
Saving to: ‘fakeMessage.docx’

fakeMessage.docx    100%[===================>]  12.04K  --.-KB/s    in 0s      

2020-08-20 10:44:40 (105 MB/s) - ‘fakeMessage.docx’ saved [12324/12324]

In [11]:
!pip install python-docx
Collecting python-docx
  Downloading https://files.pythonhosted.org/packages/e4/83/c66a1934ed5ed8ab1dbb9931f1779079f8bca0f6bbc5793c06c4b5e7d671/python-docx-0.8.10.tar.gz (5.5MB)
     |████████████████████████████████| 5.5MB 2.8MB/s 
Requirement already satisfied: lxml>=2.3.2 in /usr/local/lib/python3.6/dist-packages (from python-docx) (4.2.6)
Building wheels for collected packages: python-docx
  Building wheel for python-docx (setup.py) ... done
  Created wheel for python-docx: filename=python_docx-0.8.10-cp36-none-any.whl size=184491 sha256=8f5cb487734e318edc8a42f9a1bdc9603bbae74335564c9515995440f839270b
  Stored in directory: /root/.cache/pip/wheels/18/0b/a0/1dd62ff812c857c9e487f27d80d53d2b40531bec1acecfa47b
Successfully built python-docx
Installing collected packages: python-docx
Successfully installed python-docx-0.8.10
In [12]:
import sys
import docx
from docx.shared import RGBColor, Pt

fake_text = docx.Document('fakeMessage.docx')
fake_list = []
for paragraph in fake_text.paragraphs:
    fake_list.append(paragraph.text)

real_text = docx.Document('realMessageChallenge.docx')
real_list = []
for paragraph in real_text.paragraphs:
    if len(paragraph.text) != 0:
        real_list.append(paragraph.text)

def line_limit(fake, real):
    num_blanks = 0
    num_real = 0
    for line in fake:
        if line == '':
            num_blanks += 1
    num_real = len(real)
    diff = num_real - num_blanks
    print("\nNumber of blank lines in fake message = {}".format(num_blanks))
    print("Number of lines in real message = {}\n".format(num_real))
    if num_real > num_blanks:
        print("Fake message needs {} more blank lines."
              .format(diff), file=sys.stderr)
        sys.exit()

line_limit(fake_list, real_list)
    
# load template that sets style, font, margins, etc.
doc = docx.Document('template.docx')

# add letterhead
doc.add_heading('Morland Holmes', 0)
subtitle = doc.add_heading('Global Consultanting & Negotiations', 1)
subtitle.alignment = 1 
doc.add_heading('', 1)
doc.add_paragraph('December 17, 2015')
doc.add_paragraph('')

def set_spacing(paragraph):
    """Use docx to set line spacing between paragraphs."""
    paragraph_format = paragraph.paragraph_format
    paragraph_format.space_before = Pt(0)
    paragraph_format.space_after = Pt(0)

length_real = len(real_list)
count_real = 0  # index of current line in real (hidden) message

# interleave real and fake message lines
for line in fake_list:
    if count_real < length_real and line == "":
        paragraph = doc.add_paragraph(real_list[count_real])
        paragraph_index = len(doc.paragraphs) - 1
        
        # set real message color to white
        run = doc.paragraphs[paragraph_index].runs[0]   
        font = run.font
        font.color.rgb = RGBColor(255, 255, 255)  # make it red to test
        count_real += 1
        
    else:
        paragraph = doc.add_paragraph(line)
        
    set_spacing(paragraph)

doc.save('ciphertext_message_letterhead.docx')

print("Done")
Number of blank lines in fake message = 8
Number of lines in real message = 24

Fake message needs 16 more blank lines.
An exception has occurred, use %tb to see the full traceback.

SystemExit
/usr/local/lib/python3.6/dist-packages/IPython/core/interactiveshell.py:2890: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
  warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)

Chap7

In [13]:
import time
import random 
import statistics

# 50000g
GOAL = 50000
NUM_RATS = 20
INITIAL_MIN_WT = 200
INITIAL_MAX_WT = 600
INITIAL_MODE_WT = 300
MUTATE_ODDS = 0.01
MUTATE_MIN = 0.5
MUTATE_MAX = 1.2
LITTER_SIZE = 8
LITTERS_PER_YEAR = 10
GENERATION_LIMIT = 500

# 前処理
if NUM_RATS % 2 != 0:
    NUM_RATS += 1

def populate(num_rats, min_wt, max_wt, mode_wt):
    # 母集団の体重の初期化(triangular)
    return [int(random.triangular(min_wt, max_wt, mode_wt))\
            for i in range(num_rats)]

def fitness(population, goal):
    ave = statistics.mean(population)
    return ave / goal

def select(population, to_retain):
    # どれを残すか
    sorted_population = sorted(population)
    to_retain_by_sex = to_retain//2
    members_per_sex = len(sorted_population)//2
    females = sorted_population[:members_per_sex]
    males = sorted_population[members_per_sex:]
    selected_females = females[-to_retain_by_sex:]
    selected_males = males[-to_retain_by_sex:]
    return selected_males, selected_females

def breed(males, females, litter_size):
    # 交配
    random.shuffle(males)
    random.shuffle(females)
    children = []
    for male, female in zip(males, females):
        for child in range(litter_size):
            child = random.randint(female, male)
            children.append(child)
    return children

def mutate(children, mutate_odds, mutate_min, mutate_max):
    # 変異    
    for index, rat in enumerate(children):
        if mutate_odds >= random.random():
            children[index] = round(rat * random.uniform(mutate_min,
                                                         mutate_max))
    return children

ave_wt = []
def main():
    """Initialize population, select, breed, and mutate, display results."""
    generations = 0

    parents = populate(NUM_RATS, INITIAL_MIN_WT, INITIAL_MAX_WT,
                       INITIAL_MODE_WT)
    print("initial population weights = {}".format(parents))
    popl_fitness = fitness(parents, GOAL)
    print("initial population fitness = {}".format(popl_fitness))
    print("number to retain = {}".format(NUM_RATS))

    while popl_fitness < 1 and generations < GENERATION_LIMIT:
        selected_males, selected_females = select(parents, NUM_RATS)
        children = breed(selected_males, selected_females, LITTER_SIZE)
        children = mutate(children, MUTATE_ODDS, MUTATE_MIN, MUTATE_MAX)
        parents = selected_males + selected_females + children
        popl_fitness = fitness(parents, GOAL)
        print("Generation {} fitness = {:.4f}".format(generations,
                                                      popl_fitness))
        ave_wt.append(int(statistics.mean(parents)))
        generations += 1

    print("average weight per generation = {}".format(ave_wt))
    print("\nnumber of generations = {}".format(generations))
    print("number of years = {}".format(int(generations / LITTERS_PER_YEAR)))


start_time = time.time()
main()
end_time = time.time()
duration = end_time - start_time
print("\nRuntime for this program was {} seconds.".format(duration))  
initial population weights = [372, 338, 393, 490, 446, 525, 237, 351, 322, 505, 448, 312, 379, 505, 234, 439, 405, 358, 325, 226]
initial population fitness = 0.00761
number to retain = 20
Generation 0 fitness = 0.0076
Generation 1 fitness = 0.0086
Generation 2 fitness = 0.0093
Generation 3 fitness = 0.0097
Generation 4 fitness = 0.0100
Generation 5 fitness = 0.0101
Generation 6 fitness = 0.0103
Generation 7 fitness = 0.0104
Generation 8 fitness = 0.0105
Generation 9 fitness = 0.0104
Generation 10 fitness = 0.0105
Generation 11 fitness = 0.0104
Generation 12 fitness = 0.0105
Generation 13 fitness = 0.0105
Generation 14 fitness = 0.0106
Generation 15 fitness = 0.0107
Generation 16 fitness = 0.0110
Generation 17 fitness = 0.0112
Generation 18 fitness = 0.0114
Generation 19 fitness = 0.0115
Generation 20 fitness = 0.0116
Generation 21 fitness = 0.0116
Generation 22 fitness = 0.0117
Generation 23 fitness = 0.0116
Generation 24 fitness = 0.0117
Generation 25 fitness = 0.0117
Generation 26 fitness = 0.0118
Generation 27 fitness = 0.0122
Generation 28 fitness = 0.0126
Generation 29 fitness = 0.0129
Generation 30 fitness = 0.0131
Generation 31 fitness = 0.0132
Generation 32 fitness = 0.0134
Generation 33 fitness = 0.0134
Generation 34 fitness = 0.0135
Generation 35 fitness = 0.0135
Generation 36 fitness = 0.0135
Generation 37 fitness = 0.0136
Generation 38 fitness = 0.0136
Generation 39 fitness = 0.0136
Generation 40 fitness = 0.0137
Generation 41 fitness = 0.0143
Generation 42 fitness = 0.0148
Generation 43 fitness = 0.0151
Generation 44 fitness = 0.0154
Generation 45 fitness = 0.0156
Generation 46 fitness = 0.0158
Generation 47 fitness = 0.0158
Generation 48 fitness = 0.0159
Generation 49 fitness = 0.0160
Generation 50 fitness = 0.0160
Generation 51 fitness = 0.0160
Generation 52 fitness = 0.0160
Generation 53 fitness = 0.0159
Generation 54 fitness = 0.0160
Generation 55 fitness = 0.0160
Generation 56 fitness = 0.0160
Generation 57 fitness = 0.0160
Generation 58 fitness = 0.0160
Generation 59 fitness = 0.0160
Generation 60 fitness = 0.0160
Generation 61 fitness = 0.0160
Generation 62 fitness = 0.0160
Generation 63 fitness = 0.0160
Generation 64 fitness = 0.0160
Generation 65 fitness = 0.0162
Generation 66 fitness = 0.0168
Generation 67 fitness = 0.0174
Generation 68 fitness = 0.0180
Generation 69 fitness = 0.0183
Generation 70 fitness = 0.0186
Generation 71 fitness = 0.0188
Generation 72 fitness = 0.0191
Generation 73 fitness = 0.0194
Generation 74 fitness = 0.0201
Generation 75 fitness = 0.0206
Generation 76 fitness = 0.0211
Generation 77 fitness = 0.0213
Generation 78 fitness = 0.0215
Generation 79 fitness = 0.0216
Generation 80 fitness = 0.0216
Generation 81 fitness = 0.0217
Generation 82 fitness = 0.0217
Generation 83 fitness = 0.0217
Generation 84 fitness = 0.0216
Generation 85 fitness = 0.0217
Generation 86 fitness = 0.0217
Generation 87 fitness = 0.0217
Generation 88 fitness = 0.0217
Generation 89 fitness = 0.0218
Generation 90 fitness = 0.0223
Generation 91 fitness = 0.0230
Generation 92 fitness = 0.0235
Generation 93 fitness = 0.0239
Generation 94 fitness = 0.0244
Generation 95 fitness = 0.0253
Generation 96 fitness = 0.0260
Generation 97 fitness = 0.0265
Generation 98 fitness = 0.0272
Generation 99 fitness = 0.0277
Generation 100 fitness = 0.0286
Generation 101 fitness = 0.0294
Generation 102 fitness = 0.0301
Generation 103 fitness = 0.0307
Generation 104 fitness = 0.0320
Generation 105 fitness = 0.0331
Generation 106 fitness = 0.0340
Generation 107 fitness = 0.0347
Generation 108 fitness = 0.0350
Generation 109 fitness = 0.0353
Generation 110 fitness = 0.0356
Generation 111 fitness = 0.0360
Generation 112 fitness = 0.0362
Generation 113 fitness = 0.0364
Generation 114 fitness = 0.0367
Generation 115 fitness = 0.0372
Generation 116 fitness = 0.0378
Generation 117 fitness = 0.0388
Generation 118 fitness = 0.0395
Generation 119 fitness = 0.0403
Generation 120 fitness = 0.0410
Generation 121 fitness = 0.0414
Generation 122 fitness = 0.0415
Generation 123 fitness = 0.0418
Generation 124 fitness = 0.0421
Generation 125 fitness = 0.0422
Generation 126 fitness = 0.0424
Generation 127 fitness = 0.0428
Generation 128 fitness = 0.0445
Generation 129 fitness = 0.0460
Generation 130 fitness = 0.0470
Generation 131 fitness = 0.0482
Generation 132 fitness = 0.0499
Generation 133 fitness = 0.0523
Generation 134 fitness = 0.0535
Generation 135 fitness = 0.0547
Generation 136 fitness = 0.0552
Generation 137 fitness = 0.0570
Generation 138 fitness = 0.0583
Generation 139 fitness = 0.0597
Generation 140 fitness = 0.0602
Generation 141 fitness = 0.0613
Generation 142 fitness = 0.0616
Generation 143 fitness = 0.0624
Generation 144 fitness = 0.0641
Generation 145 fitness = 0.0663
Generation 146 fitness = 0.0683
Generation 147 fitness = 0.0696
Generation 148 fitness = 0.0701
Generation 149 fitness = 0.0707
Generation 150 fitness = 0.0707
Generation 151 fitness = 0.0709
Generation 152 fitness = 0.0712
Generation 153 fitness = 0.0713
Generation 154 fitness = 0.0711
Generation 155 fitness = 0.0714
Generation 156 fitness = 0.0716
Generation 157 fitness = 0.0717
Generation 158 fitness = 0.0732
Generation 159 fitness = 0.0751
Generation 160 fitness = 0.0768
Generation 161 fitness = 0.0781
Generation 162 fitness = 0.0789
Generation 163 fitness = 0.0801
Generation 164 fitness = 0.0806
Generation 165 fitness = 0.0809
Generation 166 fitness = 0.0811
Generation 167 fitness = 0.0812
Generation 168 fitness = 0.0814
Generation 169 fitness = 0.0818
Generation 170 fitness = 0.0826
Generation 171 fitness = 0.0832
Generation 172 fitness = 0.0855
Generation 173 fitness = 0.0875
Generation 174 fitness = 0.0895
Generation 175 fitness = 0.0908
Generation 176 fitness = 0.0919
Generation 177 fitness = 0.0926
Generation 178 fitness = 0.0936
Generation 179 fitness = 0.0959
Generation 180 fitness = 0.0992
Generation 181 fitness = 0.1021
Generation 182 fitness = 0.1040
Generation 183 fitness = 0.1060
Generation 184 fitness = 0.1071
Generation 185 fitness = 0.1077
Generation 186 fitness = 0.1081
Generation 187 fitness = 0.1085
Generation 188 fitness = 0.1092
Generation 189 fitness = 0.1102
Generation 190 fitness = 0.1109
Generation 191 fitness = 0.1115
Generation 192 fitness = 0.1114
Generation 193 fitness = 0.1122
Generation 194 fitness = 0.1117
Generation 195 fitness = 0.1119
Generation 196 fitness = 0.1124
Generation 197 fitness = 0.1127
Generation 198 fitness = 0.1133
Generation 199 fitness = 0.1162
Generation 200 fitness = 0.1199
Generation 201 fitness = 0.1232
Generation 202 fitness = 0.1249
Generation 203 fitness = 0.1263
Generation 204 fitness = 0.1283
Generation 205 fitness = 0.1297
Generation 206 fitness = 0.1346
Generation 207 fitness = 0.1388
Generation 208 fitness = 0.1439
Generation 209 fitness = 0.1464
Generation 210 fitness = 0.1484
Generation 211 fitness = 0.1496
Generation 212 fitness = 0.1503
Generation 213 fitness = 0.1509
Generation 214 fitness = 0.1512
Generation 215 fitness = 0.1507
Generation 216 fitness = 0.1515
Generation 217 fitness = 0.1517
Generation 218 fitness = 0.1522
Generation 219 fitness = 0.1562
Generation 220 fitness = 0.1608
Generation 221 fitness = 0.1643
Generation 222 fitness = 0.1681
Generation 223 fitness = 0.1712
Generation 224 fitness = 0.1723
Generation 225 fitness = 0.1746
Generation 226 fitness = 0.1749
Generation 227 fitness = 0.1765
Generation 228 fitness = 0.1774
Generation 229 fitness = 0.1795
Generation 230 fitness = 0.1862
Generation 231 fitness = 0.1984
Generation 232 fitness = 0.2150
Generation 233 fitness = 0.2272
Generation 234 fitness = 0.2324
Generation 235 fitness = 0.2362
Generation 236 fitness = 0.2387
Generation 237 fitness = 0.2401
Generation 238 fitness = 0.2403
Generation 239 fitness = 0.2411
Generation 240 fitness = 0.2427
Generation 241 fitness = 0.2431
Generation 242 fitness = 0.2424
Generation 243 fitness = 0.2417
Generation 244 fitness = 0.2437
Generation 245 fitness = 0.2438
Generation 246 fitness = 0.2420
Generation 247 fitness = 0.2439
Generation 248 fitness = 0.2424
Generation 249 fitness = 0.2430
Generation 250 fitness = 0.2441
Generation 251 fitness = 0.2452
Generation 252 fitness = 0.2456
Generation 253 fitness = 0.2481
Generation 254 fitness = 0.2572
Generation 255 fitness = 0.2652
Generation 256 fitness = 0.2752
Generation 257 fitness = 0.2815
Generation 258 fitness = 0.2853
Generation 259 fitness = 0.2884
Generation 260 fitness = 0.2916
Generation 261 fitness = 0.2930
Generation 262 fitness = 0.2931
Generation 263 fitness = 0.2941
Generation 264 fitness = 0.2946
Generation 265 fitness = 0.2948
Generation 266 fitness = 0.2949
Generation 267 fitness = 0.2939
Generation 268 fitness = 0.2951
Generation 269 fitness = 0.2952
Generation 270 fitness = 0.2954
Generation 271 fitness = 0.2963
Generation 272 fitness = 0.2979
Generation 273 fitness = 0.2990
Generation 274 fitness = 0.2984
Generation 275 fitness = 0.2993
Generation 276 fitness = 0.3002
Generation 277 fitness = 0.2991
Generation 278 fitness = 0.3005
Generation 279 fitness = 0.3000
Generation 280 fitness = 0.3007
Generation 281 fitness = 0.3007
Generation 282 fitness = 0.3007
Generation 283 fitness = 0.3007
Generation 284 fitness = 0.3007
Generation 285 fitness = 0.3002
Generation 286 fitness = 0.3008
Generation 287 fitness = 0.3013
Generation 288 fitness = 0.3034
Generation 289 fitness = 0.3125
Generation 290 fitness = 0.3241
Generation 291 fitness = 0.3354
Generation 292 fitness = 0.3436
Generation 293 fitness = 0.3535
Generation 294 fitness = 0.3621
Generation 295 fitness = 0.3691
Generation 296 fitness = 0.3736
Generation 297 fitness = 0.3766
Generation 298 fitness = 0.3791
Generation 299 fitness = 0.3802
Generation 300 fitness = 0.3828
Generation 301 fitness = 0.3871
Generation 302 fitness = 0.3992
Generation 303 fitness = 0.4133
Generation 304 fitness = 0.4202
Generation 305 fitness = 0.4272
Generation 306 fitness = 0.4303
Generation 307 fitness = 0.4336
Generation 308 fitness = 0.4363
Generation 309 fitness = 0.4379
Generation 310 fitness = 0.4373
Generation 311 fitness = 0.4389
Generation 312 fitness = 0.4394
Generation 313 fitness = 0.4399
Generation 314 fitness = 0.4402
Generation 315 fitness = 0.4410
Generation 316 fitness = 0.4407
Generation 317 fitness = 0.4555
Generation 318 fitness = 0.4700
Generation 319 fitness = 0.4796
Generation 320 fitness = 0.4862
Generation 321 fitness = 0.4901
Generation 322 fitness = 0.4925
Generation 323 fitness = 0.4940
Generation 324 fitness = 0.4950
Generation 325 fitness = 0.4956
Generation 326 fitness = 0.4943
Generation 327 fitness = 0.4961
Generation 328 fitness = 0.4963
Generation 329 fitness = 0.4942
Generation 330 fitness = 0.4955
Generation 331 fitness = 0.4979
Generation 332 fitness = 0.5034
Generation 333 fitness = 0.5050
Generation 334 fitness = 0.5135
Generation 335 fitness = 0.5236
Generation 336 fitness = 0.5382
Generation 337 fitness = 0.5517
Generation 338 fitness = 0.5637
Generation 339 fitness = 0.5745
Generation 340 fitness = 0.5852
Generation 341 fitness = 0.5967
Generation 342 fitness = 0.6078
Generation 343 fitness = 0.6164
Generation 344 fitness = 0.6202
Generation 345 fitness = 0.6240
Generation 346 fitness = 0.6236
Generation 347 fitness = 0.6272
Generation 348 fitness = 0.6287
Generation 349 fitness = 0.6318
Generation 350 fitness = 0.6426
Generation 351 fitness = 0.6588
Generation 352 fitness = 0.6658
Generation 353 fitness = 0.6649
Generation 354 fitness = 0.6751
Generation 355 fitness = 0.6825
Generation 356 fitness = 0.7073
Generation 357 fitness = 0.7381
Generation 358 fitness = 0.7609
Generation 359 fitness = 0.7684
Generation 360 fitness = 0.7825
Generation 361 fitness = 0.7987
Generation 362 fitness = 0.8150
Generation 363 fitness = 0.8387
Generation 364 fitness = 0.8509
Generation 365 fitness = 0.8563
Generation 366 fitness = 0.8701
Generation 367 fitness = 0.8788
Generation 368 fitness = 0.8842
Generation 369 fitness = 0.8873
Generation 370 fitness = 0.8855
Generation 371 fitness = 0.8934
Generation 372 fitness = 0.9052
Generation 373 fitness = 0.9193
Generation 374 fitness = 0.9299
Generation 375 fitness = 0.9403
Generation 376 fitness = 0.9450
Generation 377 fitness = 0.9471
Generation 378 fitness = 0.9505
Generation 379 fitness = 0.9492
Generation 380 fitness = 0.9529
Generation 381 fitness = 0.9522
Generation 382 fitness = 0.9539
Generation 383 fitness = 0.9503
Generation 384 fitness = 0.9543
Generation 385 fitness = 0.9540
Generation 386 fitness = 0.9563
Generation 387 fitness = 0.9604
Generation 388 fitness = 1.0058
average weight per generation = [379, 431, 462, 486, 500, 507, 516, 518, 522, 521, 524, 522, 525, 525, 527, 535, 550, 561, 567, 573, 579, 582, 583, 582, 585, 586, 590, 610, 630, 644, 654, 662, 668, 671, 674, 674, 674, 678, 678, 679, 686, 712, 738, 756, 770, 781, 788, 792, 795, 797, 799, 799, 800, 797, 800, 800, 797, 801, 800, 797, 801, 801, 800, 799, 802, 808, 840, 868, 898, 913, 927, 941, 953, 970, 1004, 1031, 1054, 1063, 1074, 1079, 1082, 1083, 1084, 1085, 1081, 1086, 1084, 1083, 1087, 1089, 1113, 1147, 1175, 1194, 1222, 1266, 1301, 1326, 1359, 1386, 1431, 1472, 1505, 1535, 1600, 1656, 1698, 1733, 1751, 1765, 1780, 1798, 1811, 1821, 1833, 1862, 1888, 1937, 1975, 2015, 2048, 2071, 2075, 2091, 2105, 2108, 2118, 2138, 2224, 2299, 2349, 2412, 2496, 2613, 2675, 2735, 2762, 2852, 2917, 2985, 3012, 3063, 3077, 3120, 3206, 3316, 3415, 3478, 3505, 3537, 3536, 3545, 3561, 3566, 3555, 3571, 3577, 3584, 3658, 3754, 3838, 3906, 3944, 4002, 4028, 4045, 4054, 4061, 4070, 4090, 4129, 4162, 4273, 4377, 4477, 4541, 4595, 4631, 4682, 4792, 4958, 5104, 5202, 5300, 5354, 5384, 5405, 5422, 5462, 5511, 5545, 5574, 5567, 5607, 5583, 5592, 5622, 5632, 5663, 5811, 5993, 6159, 6246, 6316, 6415, 6484, 6728, 6942, 7195, 7318, 7417, 7477, 7516, 7543, 7557, 7532, 7573, 7585, 7610, 7811, 8040, 8212, 8407, 8561, 8614, 8730, 8747, 8827, 8870, 8976, 9311, 9918, 10749, 11359, 11619, 11809, 11935, 12004, 12013, 12052, 12133, 12156, 12118, 12084, 12185, 12190, 12102, 12193, 12119, 12150, 12203, 12258, 12278, 12403, 12860, 13260, 13759, 14076, 14266, 14421, 14581, 14651, 14653, 14707, 14727, 14738, 14746, 14697, 14754, 14758, 14768, 14817, 14895, 14948, 14917, 14967, 15008, 14952, 15026, 15000, 15032, 15034, 15035, 15036, 15037, 15007, 15037, 15066, 15168, 15626, 16205, 16768, 17179, 17673, 18106, 18454, 18680, 18829, 18957, 19010, 19138, 19352, 19957, 20666, 21012, 21358, 21514, 21680, 21815, 21893, 21863, 21944, 21972, 21995, 22010, 22049, 22033, 22774, 23502, 23979, 24311, 24504, 24624, 24698, 24748, 24781, 24714, 24806, 24813, 24710, 24776, 24894, 25168, 25250, 25674, 26179, 26911, 27584, 28186, 28725, 29260, 29834, 30390, 30819, 31010, 31199, 31181, 31362, 31435, 31589, 32129, 32938, 33291, 33243, 33753, 34123, 35364, 36903, 38044, 38419, 39126, 39936, 40748, 41934, 42545, 42813, 43507, 43941, 44209, 44363, 44277, 44672, 45262, 45963, 46493, 47013, 47250, 47355, 47526, 47460, 47644, 47611, 47693, 47514, 47715, 47697, 47812, 48019, 50288]

number of generations = 389
number of years = 38

Runtime for this program was 0.13222432136535645 seconds.
In [14]:
import matplotlib.pyplot as plt

plt.plot(ave_wt)
plt.show()
In [15]:
import time
from random import randint, randrange

def fitness(cmb, atm):
    g = 0
    for i, j in zip(cmb, atm):
        if i == j:
            g += 1
    return g

def main():
    combination = '6822858902'
    print("Combination = {}".format(combination))
    combo = [int(i) for i in combination]
    best_a = [0] * len(combo)
    best_a_g = fitness(combo, best_a)
    count = 0
    # evolve guess           
    while best_a != combo:
        # crossover
        next_try = best_a[:]
        # mutate
        lock_wheel = randrange(0, len(combo))
        next_try[lock_wheel] = randint(0, 9)
        # grade & select
        next_try_g = fitness(combo, next_try)
        if next_try_g > best_a_g:
            best_a = next_try[:]
            best_a_g = next_try_g
        print(next_try, best_a)
        count += 1

    print("Cracked! {}".format(best_a), end=' ')
    print("in {} tries!".format(count))

 
start_time = time.time()
main()
end_time = time.time()
duration = end_time - start_time
print("\n{:.5f} seconds.".format(duration))      
Combination = 6822858902
[8, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 3] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 4, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 4, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 5, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 6] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 2, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 1] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 8, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 5, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 1] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 3, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 2, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 9, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 7, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 4, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 7, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 4] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 3, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 6, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 7, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 7, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 4, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 6, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 5, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 8, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 1] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 8, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 6, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 4, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 3, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 3, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 6, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[5, 0, 0, 0, 0, 5, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 3, 0, 0, 0, 0] [0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 8, 5, 0, 0, 0, 0] [0, 0, 0, 0, 8, 5, 0, 0, 0, 0]
[0, 0, 7, 0, 8, 5, 0, 0, 0, 0] [0, 0, 0, 0, 8, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 8, 5, 0, 0, 3, 0] [0, 0, 0, 0, 8, 5, 0, 0, 0, 0]
[0, 0, 0, 0, 8, 5, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 6, 0, 8, 5, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 0, 0, 8, 5, 2, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 0, 0, 8, 3, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[5, 0, 0, 0, 8, 5, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 5, 0, 8, 5, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 0, 6, 8, 5, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 0, 0, 8, 1, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 0, 0, 8, 3, 8, 0, 0, 0] [0, 0, 0, 0, 8, 5, 8, 0, 0, 0]
[0, 0, 0, 0, 8, 5, 8, 9, 0, 0] [0, 0, 0, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 0, 0, 4, 5, 8, 9, 0, 0] [0, 0, 0, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 7, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 7, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 7, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 8, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 7, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 0, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 6, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 1, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[9, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 7, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 5, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 3, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[5, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 5, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 0, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 2, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 3, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 9, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 6, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 9, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 1, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 4, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 8, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 2, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 1, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 4, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 6, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 1, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 3, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 4, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 1, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 1, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 2, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[8, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 3, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 2, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 0, 7] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 6, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 2, 2, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 1, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 4, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 8, 5, 8, 9, 1, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 0, 0, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 5, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 5, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 6, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 2, 8, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 0, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 0, 7, 0, 8, 5, 8, 9, 0, 0] [0, 0, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 8, 2, 0, 8, 5, 8, 9, 0, 0] [0, 8, 2, 0, 8, 5, 8, 9, 0, 0]
[0, 8, 2, 0, 8, 5, 8, 9, 0, 2] [0, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[8, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 0, 0] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 7, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 0, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 6, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 4, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 0, 9] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 4, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 0, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 0, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[1, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 1, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 5, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 9, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 0, 9] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 6, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 1, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 6, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 3, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 2, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 9, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 1, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 1, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 2, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 0, 6] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 3, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[8, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 2, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 8, 9, 7, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 0, 8, 5, 2, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 4, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[5, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 4, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 9, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[9, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 9, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[7, 8, 2, 0, 8, 5, 8, 9, 0, 2] [6, 8, 2, 0, 8, 5, 8, 9, 0, 2]
[6, 8, 2, 2, 8, 5, 8, 9, 0, 2] [6, 8, 2, 2, 8, 5, 8, 9, 0, 2]
Cracked! [6, 8, 2, 2, 8, 5, 8, 9, 0, 2] in 158 tries!

0.01494 seconds.

Chap8

In [16]:
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_8/missing_words.json
--2020-08-20 10:45:14--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_8/missing_words.json
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 894 [text/plain]
Saving to: ‘missing_words.json’

missing_words.json  100%[===================>]     894  --.-KB/s    in 0s      

2020-08-20 10:45:15 (52.4 MB/s) - ‘missing_words.json’ saved [894/894]

In [17]:
!pip install nltk
Requirement already satisfied: nltk in /usr/local/lib/python3.6/dist-packages (3.2.5)
Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from nltk) (1.15.0)
In [18]:
import sys
from string import punctuation
import json
from nltk.corpus import cmudict
import nltk 
nltk.download('cmudict')

with open('missing_words.json') as f:
    missing_words = json.load(f)

cmudict = cmudict.dict()

def count_syllables(words):
    words = words.replace('-', ' ')
    words = words.lower().split()
    num_sylls = 0
    for word in words:
        word = word.strip(punctuation)
        if word.endswith("'s")or word.endswith("’s"):
            word = word[:-2]
        if word in missing_words:
            num_sylls += missing_words[word]
        else:
            for phonemes in cmudict[word][0]:
                for phoneme in phonemes:
                    if phoneme[-1].isdigit():
                        num_sylls += 1
    return num_sylls
[nltk_data] Downloading package cmudict to /root/nltk_data...
[nltk_data]   Unzipping corpora/cmudict.zip.
In [19]:
import sys
import random

def load(file):
    with open(file) as in_file:
        txt = in_file.read().strip().split('\n')
        txt = [x.lower() for x in txt]
        return txt

word_list = load('2of4brif.txt')
test_data = []
num_words = 100
test_data.extend(random.sample(word_list, num_words))

for word in test_data:
    try:
        num_syllables = count_syllables(word)
        print(word, num_syllables, end='\n')
    except KeyError:
        print(word, end='')
        # print(" not found", file=sys.stderr)
bolted 2
classiestchew 1
pondering 3
supplements 3
hellish 2
monstrous 2
assistant 3
magnifies 3
automate 3
deliberative 5
blindsided 3
rites 1
coverletsstockpiles 2
immigrants 3
insubordinate 5
reaffirms 3
initiate 4
typographicsearchlight 2
overboard 3
presenting 3
cannonadesperpetrate 3
vetchcobbled 2
retorted 3
plagiaristsnewspaper 3
accessorize 4
misdeed 2
scripts 1
vigourovertaxed 3
incident 3
intimation 4
marauder 3
supernova 4
sensitisesquadrant 2
misjudged 2
clinkspredecessors 4
dungareesfavouredconsciousness 3
response 2
gallon 2
configuration 5
deemingcavity 3
pulletsinterdicting 4
places 2
hoarieroddballs 2
secure 2
headstrong 2
fireguardsrefutes 2
faggeddistressingly 4
offensivenesssnuff 1
daunt 1
vindicates 3
friendship 2
traveller 3
unnoticed 3
liveried 2
snootinessprominent 3
selfishness 3
tuner 2
vacationers 4
demotion 3
pancreas 3
coltishpolluting 3
crevice 2
attractively 4
attestationstopgap 2
auctioneers 3
sized 1
weeks 1
arightseamedflagonsidoliseyouthful 2
portables 3
awokenad 1
upheavals 3
supplies 2
haystacks 2
utilizablemalign 2

Chap9

In [20]:
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_9/train.txt
--2020-08-20 10:45:28--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_9/train.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 368928 (360K) [text/plain]
Saving to: ‘train.txt’

train.txt           100%[===================>] 360.28K  --.-KB/s    in 0.07s   

2020-08-20 10:45:28 (5.34 MB/s) - ‘train.txt’ saved [368928/368928]

In [21]:
"""Produce new haiku from training corpus of existing haiku."""
import sys
import logging
import random
from collections import defaultdict

logging.disable(logging.CRITICAL)  # comment-out to enable debugging messages
logging.basicConfig(level=logging.DEBUG, format='%(message)s')

def load_training_file(file):
    """Return a text file as a string."""
    with open(file) as f:
        raw_haiku = f.read()
        return raw_haiku

def prep_training(raw_haiku):
    """Load string, remove newline, split words on spaces, and return list."""
    corpus = raw_haiku.replace('\n', ' ').split()
    return corpus

def map_word_to_word(corpus):
    """Load list & use dictionary to map word to word that follows."""
    limit = len(corpus)-1
    dict1_to_1 = defaultdict(list)
    for index, word in enumerate(corpus):
        if index < limit:
            suffix = corpus[index + 1]
            dict1_to_1[word].append(suffix)
    logging.debug("map_word_to_word results for \"sake\" = %s\n", 
                  dict1_to_1['sake'])
    return dict1_to_1

def map_2_words_to_word(corpus):
    """Load list & use dictionary to map word-pair to trailing word."""
    limit = len(corpus)-2
    dict2_to_1 = defaultdict(list)
    for index, word in enumerate(corpus):
        if index < limit:
            key = word + ' ' + corpus[index + 1]
            suffix = corpus[index + 2]
            dict2_to_1[key].append(suffix)
    logging.debug("map_2_words_to_word results for \"sake jug\" = %s\n",
                  dict2_to_1['sake jug'])
    return dict2_to_1

def random_word(corpus):
    """Return random word and syllable count from training corpus."""
    word = random.choice(corpus)
    num_syls = count_syllables(word)
    if num_syls > 4:
        random_word(corpus)
    else:
        logging.debug("random word & syllables = %s %s\n", word, num_syls)
        return (word, num_syls)

def word_after_single(prefix, suffix_map_1, current_syls, target_syls):
    """Return all acceptable words in a corpus that follow a single word."""
    accepted_words = []
    suffixes = suffix_map_1.get(prefix)
    if suffixes != None:
        for candidate in suffixes:
            num_syls = count_syllables(candidate)
            if current_syls + num_syls <= target_syls:
                accepted_words.append(candidate)
    logging.debug("accepted words after \"%s\" = %s\n",
                  prefix, set(accepted_words))
    return accepted_words


def word_after_double(prefix, suffix_map_2, current_syls, target_syls):
    """Return all acceptable words in a corpus that follow a word pair."""
    accepted_words = []
    suffixes = suffix_map_2.get(prefix)
    if suffixes != None:
        for candidate in suffixes:
            num_syls = count_syllables(candidate)
            if current_syls + num_syls <= target_syls:
                accepted_words.append(candidate)
    logging.debug("accepted words after \"%s\" = %s\n",
                  prefix, set(accepted_words))
    return accepted_words

def haiku_line(suffix_map_1, suffix_map_2, corpus, end_prev_line, target_syls):
    """Build a haiku line from a training corpus and return it."""
    line = '2/3'
    line_syls = 0
    current_line = []

    if len(end_prev_line) == 0:  # build first line
        line = '1'
        word, num_syls = random_word(corpus)
        current_line.append(word)
        line_syls += num_syls
        word_choices = word_after_single(word, suffix_map_1,
                                         line_syls, target_syls)
        while len(word_choices) == 0:
            prefix = random.choice(corpus)
            logging.debug("new random prefix = %s", prefix)
            word_choices = word_after_single(prefix, suffix_map_1,
                                             line_syls, target_syls)
        word = random.choice(word_choices)
        num_syls = count_syllables(word)
        logging.debug("word & syllables = %s %s", word, num_syls)
        line_syls += num_syls
        current_line.append(word)
        if line_syls == target_syls:
            end_prev_line.extend(current_line[-2:])
            return current_line, end_prev_line

    else:  # build lines 2 & 3
        current_line.extend(end_prev_line)

    while True:
        logging.debug("line = %s\n", line)
        prefix = current_line[-2] + ' ' + current_line[-1]
        word_choices = word_after_double(prefix, suffix_map_2,
                                         line_syls, target_syls)
        while len(word_choices) == 0:
            index = random.randint(0, len(corpus) - 2)
            prefix = corpus[index] + ' ' + corpus[index + 1]
            logging.debug("new random prefix = %s", prefix)
            word_choices = word_after_double(prefix, suffix_map_2,
                                             line_syls, target_syls)
        word = random.choice(word_choices)
        num_syls = count_syllables(word)
        logging.debug("word & syllables = %s %s", word, num_syls)
        
        if line_syls + num_syls > target_syls:
            continue
        elif line_syls + num_syls < target_syls:
            current_line.append(word)
            line_syls += num_syls
        elif line_syls + num_syls == target_syls:
            current_line.append(word)
            break

    end_prev_line = []
    end_prev_line.extend(current_line[-2:])

    if line == '1':
        final_line = current_line[:]
    else:
        final_line = current_line[2:]

    return final_line, end_prev_line


def main():
    """Give user choice of building a haiku or modifying an existing haiku."""
    intro = """\n
    A thousand monkeys at a thousand typewriters...
    or one computer...can sometimes produce a haiku.\n"""
    print("{}".format(intro))

    raw_haiku = load_training_file("train.txt")
    corpus = prep_training(raw_haiku)
    suffix_map_1 = map_word_to_word(corpus)
    suffix_map_2 = map_2_words_to_word(corpus)
    final = []

    choice = None
    while choice != "0":

        print(
            """
            Japanese Haiku Generator
            0 - Quit
            1 - Generate a Haiku poem
            2 - Regenerate Line 2
            3 - Regenerate Line 3
            """
            )

        choice = input("Choice: ")
        print()

        # exit
        if choice == "0":
            print("Sayonara.")
            sys.exit()

        # generate a full haiku
        elif choice == "1":
            final = []
            end_prev_line = []
            first_line, end_prev_line1 = haiku_line(suffix_map_1, suffix_map_2,
                                                    corpus, end_prev_line, 5)
            final.append(first_line)
            line, end_prev_line2 = haiku_line(suffix_map_1, suffix_map_2,
                                              corpus, end_prev_line1, 7)
            final.append(line)
            line, end_prev_line3 = haiku_line(suffix_map_1, suffix_map_2,
                                              corpus, end_prev_line2, 5)
            final.append(line)

        # regenerate line 2
        elif choice == "2":
            if not final:
                print("Please generate a full haiku first (Option 1).")
                continue
            else:
                line, end_prev_line2 = haiku_line(suffix_map_1, suffix_map_2,
                                                  corpus, end_prev_line1, 7)
                final[1] = line

        # regenerate line 3
        elif choice == "3":
            if not final:
                print("Please generate a full haiku first (Option 1).")
                continue
            else:
                line, end_prev_line3 = haiku_line(suffix_map_1, suffix_map_2,
                                                  corpus, end_prev_line2, 5)
                final[2] = line

        # some unknown choice
        else:
            print("\nSorry, but that isn't a valid choice.", file=sys.stderr)
            continue

        # display results
        print()
        print("First line = ", end="")
        print(' '.join(final[0]), file=sys.stderr)
        print("Second line = ", end="")
        print(" ".join(final[1]), file=sys.stderr)
        print("Third line = ", end="")
        print(" ".join(final[2]), file=sys.stderr)
        print()

    input("\n\nPress the Enter key to exit.")


main()
    A thousand monkeys at a thousand typewriters...
    or one computer...can sometimes produce a haiku.


            Japanese Haiku Generator
            0 - Quit
            1 - Generate a Haiku poem
            2 - Regenerate Line 2
            3 - Regenerate Line 3
            
Choice: 1
dark hands of life the
fragrance of plums: carrying
me back to earth a
First line = Second line = Third line = 

            Japanese Haiku Generator
            0 - Quit
            1 - Generate a Haiku poem
            2 - Regenerate Line 2
            3 - Regenerate Line 3
            
Choice: 2
dark hands of life the
fragrance of plums: carrying
me back to earth a
First line = Second line = Third line = 

            Japanese Haiku Generator
            0 - Quit
            1 - Generate a Haiku poem
            2 - Regenerate Line 2
            3 - Regenerate Line 3
            
Choice: 1
a day in spring oh
sorry tom cat bigger thrust
the half-ends of worms
First line = Second line = Third line = 

            Japanese Haiku Generator
            0 - Quit
            1 - Generate a Haiku poem
            2 - Regenerate Line 2
            3 - Regenerate Line 3
            
Choice: 3
a day in spring oh
sorry tom cat bigger thrust
white before blue night
First line = Second line = Third line = 

            Japanese Haiku Generator
            0 - Quit
            1 - Generate a Haiku poem
            2 - Regenerate Line 2
            3 - Regenerate Line 3
            
Choice: 0

Sayonara.
An exception has occurred, use %tb to see the full traceback.

SystemExit
/usr/local/lib/python3.6/dist-packages/IPython/core/interactiveshell.py:2890: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
  warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)

Chap10

In [22]:
import math
from random import randint
import tkinter
from PIL import Image, ImageDraw

width = 1000
height = 1000
bg='black'

# root = tkinter.Tk()
# root.title("Galaxy BR549")
# cv = tkinter.Canvas(root, width=width, height=height, bg=bg)
image1 = Image.new("RGB", (width, height), bg)
draw = ImageDraw.Draw(image1)

# cv.grid()
# cv.configure(scrollregion=(-500, -400, 500, 400))
x_add = 500
y_add = 500
oval_size = 0

# build spiral arms
num_spiral_stars = 500
angle = 3.5
core_diameter = 120
spiral_stars = []
for i in range(num_spiral_stars):
    theta = i * angle
    r = math.sqrt(i) / math.sqrt(num_spiral_stars)
    spiral_stars.append((r * math.cos(theta), r * math.sin(theta)))
for x, y in spiral_stars:
    x = x * 350 + randint(-5, 3)
    y = y * 350 + randint(-5, 3)
    oval_size = randint(1, 3)
#    cv.create_oval(x-oval_size, y-oval_size, x+oval_size, y+oval_size,
#                  fill='white', outline='')
    draw.ellipse([x-oval_size+x_add, y-oval_size+y_add, 
                  x+oval_size+x_add, y+oval_size+y_add], 'white')
        
# build wisps
wisps = []
for i in range(2000):
    theta = i * angle
    # divide by num_spiral_stars for better dust lanes
    r = math.sqrt(i) / math.sqrt(num_spiral_stars)
    spiral_stars.append((r * math.cos(theta), r * math.sin(theta)))
for x, y in spiral_stars:
    x = x * 330 + randint(-15, 10)
    y = y * 330 + randint(-15, 10)
    h = math.sqrt(x**2 + y**2)
    if h < 350:
        wisps.append((x, y))
#         cv.create_oval(x-1, y-1, x+1, y+1, fill='white', outline='')  
        draw.ellipse([x-1+x_add, y-1+y_add, x+1+y_add, y+1+y_add], 'white')        
    
# build galactic core 
core = []
for i in range(900):
    x = randint(-core_diameter, core_diameter)
    y = randint(-core_diameter, core_diameter)
    h = math.sqrt(x**2 + y**2)
    if h < core_diameter - 70:
        core.append((x, y))
        oval_size = randint(2, 4)
        # cv.create_oval(x-oval_size, y-oval_size, x+oval_size, y+oval_size,
        #               fill='white', outline='')
        draw.ellipse([x-oval_size+x_add, y-oval_size+y_add, 
                      x+oval_size+x_add, y+oval_size+y_add], 'white') 
    elif h < core_diameter:
        core.append((x, y))
        oval_size = randint(0, 2)
        # cv.create_oval(x-oval_size, y-oval_size, x+oval_size, y+oval_size,
        #               fill='white', outline='')
        draw.ellipse([x-oval_size+x_add, y-oval_size+y_add, 
                      x+oval_size+x_add, y+oval_size+y_add], 'white')
# cv.pack()
# root.mainloop()

# cv.update()
# cv.postscript(file="file_name.ps", colormode='color')

# root.mainloop()
image1.save('./galaxy_practice.jpg')
image1
Out[22]:

Chap11

クラスに同じ誕生日の人がいる確率は70%くらいなんだよっていうものを実装

In [23]:
import random

max_people = 50
num_runs = 2000

print('2人以上が同じ誕生日である確率')

for people in range(2, max_people + 1):
    found_shared = 0
    for run in range(num_runs):
        bdays = []
        for i in range(0, people):
            bday = random.randrange(0, 364)
            bdays.append(bday)               
        set_of_bdays = set(bdays)
        if len(set_of_bdays) < len(bdays):
            found_shared += 1  
    prob = found_shared/num_runs
    print('部屋に{}人しかいないときの確率は{:.4f}'.format(people, prob))
2人以上が同じ誕生日である確率
部屋に2人しかいないときの確率は0.0025
部屋に3人しかいないときの確率は0.0070
部屋に4人しかいないときの確率は0.0180
部屋に5人しかいないときの確率は0.0295
部屋に6人しかいないときの確率は0.0415
部屋に7人しかいないときの確率は0.0625
部屋に8人しかいないときの確率は0.0750
部屋に9人しかいないときの確率は0.1025
部屋に10人しかいないときの確率は0.1285
部屋に11人しかいないときの確率は0.1535
部屋に12人しかいないときの確率は0.1785
部屋に13人しかいないときの確率は0.1880
部屋に14人しかいないときの確率は0.2530
部屋に15人しかいないときの確率は0.2600
部屋に16人しかいないときの確率は0.2990
部屋に17人しかいないときの確率は0.3185
部屋に18人しかいないときの確率は0.3545
部屋に19人しかいないときの確率は0.3760
部屋に20人しかいないときの確率は0.4250
部屋に21人しかいないときの確率は0.4590
部屋に22人しかいないときの確率は0.4675
部屋に23人しかいないときの確率は0.5140
部屋に24人しかいないときの確率は0.5370
部屋に25人しかいないときの確率は0.5620
部屋に26人しかいないときの確率は0.6120
部屋に27人しかいないときの確率は0.6335
部屋に28人しかいないときの確率は0.6650
部屋に29人しかいないときの確率は0.6690
部屋に30人しかいないときの確率は0.7110
部屋に31人しかいないときの確率は0.7425
部屋に32人しかいないときの確率は0.7545
部屋に33人しかいないときの確率は0.7725
部屋に34人しかいないときの確率は0.8005
部屋に35人しかいないときの確率は0.8215
部屋に36人しかいないときの確率は0.8320
部屋に37人しかいないときの確率は0.8545
部屋に38人しかいないときの確率は0.8555
部屋に39人しかいないときの確率は0.8850
部屋に40人しかいないときの確率は0.9005
部屋に41人しかいないときの確率は0.9120
部屋に42人しかいないときの確率は0.9175
部屋に43人しかいないときの確率は0.9265
部屋に44人しかいないときの確率は0.9225
部屋に45人しかいないときの確率は0.9390
部屋に46人しかいないときの確率は0.9520
部屋に47人しかいないときの確率は0.9505
部屋に48人しかいないときの確率は0.9610
部屋に49人しかいないときの確率は0.9615
部屋に50人しかいないときの確率は0.9705

Chap12

In [24]:
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/10-yr_TBond_returns_1926-2013_pct.txt
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/SP500_returns_1926-2013_pct.txt
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/3_mo_TBill_rate_1926-2013_pct.txt
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/S-B-C_blend_1926-2013_pct.txt
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/S-B_blend_1926-2013_pct.txt
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/annual_infl_rate_1926-2013_pct.txt
--2020-08-20 10:46:30--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/10-yr_TBond_returns_1926-2013_pct.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 650 [text/plain]
Saving to: ‘10-yr_TBond_returns_1926-2013_pct.txt’

10-yr_TBond_returns 100%[===================>]     650  --.-KB/s    in 0s      

2020-08-20 10:46:30 (34.4 MB/s) - ‘10-yr_TBond_returns_1926-2013_pct.txt’ saved [650/650]

--2020-08-20 10:46:31--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/SP500_returns_1926-2013_pct.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 438 [text/plain]
Saving to: ‘SP500_returns_1926-2013_pct.txt’

SP500_returns_1926- 100%[===================>]     438  --.-KB/s    in 0s      

2020-08-20 10:46:32 (23.0 MB/s) - ‘SP500_returns_1926-2013_pct.txt’ saved [438/438]

--2020-08-20 10:46:33--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/3_mo_TBill_rate_1926-2013_pct.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 619 [text/plain]
Saving to: ‘3_mo_TBill_rate_1926-2013_pct.txt’

3_mo_TBill_rate_192 100%[===================>]     619  --.-KB/s    in 0s      

2020-08-20 10:46:33 (35.3 MB/s) - ‘3_mo_TBill_rate_1926-2013_pct.txt’ saved [619/619]

--2020-08-20 10:46:34--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/S-B-C_blend_1926-2013_pct.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 670 [text/plain]
Saving to: ‘S-B-C_blend_1926-2013_pct.txt’

S-B-C_blend_1926-20 100%[===================>]     670  --.-KB/s    in 0s      

2020-08-20 10:46:34 (39.7 MB/s) - ‘S-B-C_blend_1926-2013_pct.txt’ saved [670/670]

--2020-08-20 10:46:35--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/S-B_blend_1926-2013_pct.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 676 [text/plain]
Saving to: ‘S-B_blend_1926-2013_pct.txt’

S-B_blend_1926-2013 100%[===================>]     676  --.-KB/s    in 0s      

2020-08-20 10:46:36 (37.2 MB/s) - ‘S-B_blend_1926-2013_pct.txt’ saved [676/676]

--2020-08-20 10:46:40--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_12/annual_infl_rate_1926-2013_pct.txt
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 444 [text/plain]
Saving to: ‘annual_infl_rate_1926-2013_pct.txt’

annual_infl_rate_19 100%[===================>]     444  --.-KB/s    in 0s      

2020-08-20 10:46:40 (22.4 MB/s) - ‘annual_infl_rate_1926-2013_pct.txt’ saved [444/444]

In [25]:
import sys
import random
import matplotlib.pyplot as plt

def read_to_list(file_name):
    with open(file_name) as in_file:
        lines = [float(line.strip()) for line in in_file]
        decimal = [round(line / 100, 5) for line in lines]
        return decimal

def default_input(prompt, default=None):
    prompt = '{} [{}]: '.format(prompt, default)
    response = input(prompt)
    if not response and default:
        return default
    else:
        return response

# load data files with original data in percent form
print("\nNote: Input data should be in percent, not decimal!\n")
try:
    bonds = read_to_list('10-yr_TBond_returns_1926-2013_pct.txt')
    stocks = read_to_list('SP500_returns_1926-2013_pct.txt')
    blend_40_50_10 = read_to_list('S-B-C_blend_1926-2013_pct.txt')
    blend_50_50 = read_to_list('S-B_blend_1926-2013_pct.txt')
    infl_rate = read_to_list('annual_infl_rate_1926-2013_pct.txt')
except IOError as e:
    print("{}. \nTerminating program.".format(e), file=sys.stderr)
    sys.exit(1)

# get user input; use dictionary for investment-type arguments   
investment_type_args = {'bonds': bonds, 'stocks': stocks,
                        'sb_blend': blend_50_50, 'sbc_blend': blend_40_50_10}

# print input legend for user
print("   stocks = SP500")
print("    bonds = 10-yr Treasury Bond")
print(" sb_blend = 50% SP500/50% TBond")
print("sbc_blend = 40% SP500/50% TBond/10% Cash\n")

print("Press ENTER to take default value shown in [brackets]. \n")

# get user input
invest_type = default_input("Enter investment type: (stocks, bonds, sb_blend,"\
                     " sbc_blend): \n", 'bonds').lower()
while invest_type not in investment_type_args:
    invest_type = input("Invalid investment. Enter investment type " \
                    "as listed in prompt: ")

start_value = default_input("Input starting value of investments: \n", \
                             '2000000')
while not start_value.isdigit():
    start_value = input("Invalid input! Input integer only: ")

withdrawal_1 = default_input("Input annual pre-tax withdrawal for " \
                            "first 5 yrs(today's $): \n", '100000')
while not withdrawal_1.isdigit():
    withdrawal_1 = input("Invalid input! Input integer only: ")

withdrawal_2 = default_input("Input annual pre-tax withdrawal for " \
                            "remainder (today's $): \n", '80000')
while not withdrawal_2.isdigit():
    withdrawal_2 = input("Invalid input! Input integer only: ")

min_years = default_input("Input minimum years in retirement: \n", '18')
while not min_years.isdigit():
    min_years = input("Invalid input! Input integer only: ")

most_likely_years = default_input("Input most-likely years in retirement: \n",
                                  '25')
while not most_likely_years.isdigit():
    most_likely_years = input("Invalid input! Input integer only: ")

max_years = default_input("Input maximum years in retirement: \n", '40')
while not max_years.isdigit():
    max_years = input("Invalid input! Input integer only: ")
    
num_cases = default_input("Input number of cases to run: \n", '50000')
while not num_cases.isdigit():
    num_cases = input("Invalid input! Input integer only: ")

# check for other erroneous input
if not int(min_years) < int(most_likely_years) < int(max_years) \
   or int(max_years) > 99:
    print("\nProblem with input years.", file=sys.stderr)
    print("Requires Min < ML < Max & Max <= 99.", file=sys.stderr)
    sys.exit(1)
   
def montecarlo(returns):
    """Run MCS & return investment value at death & and # of times bankrupt."""
    case_count = 0
    bankrupt_count = 0
    outcome = []

    while case_count < int(num_cases):
        investments = int(start_value)
        start_year = random.randrange(0, len(returns))        
        duration = int(random.triangular(int(min_years), int(max_years),
                                         int(most_likely_years)))       
        end_year = start_year + duration 
        lifespan = [i for i in range(start_year, end_year)]
        bankrupt = 'no'

        # build temporary lists for each case
        lifespan_returns = []
        lifespan_infl = []
        for i in lifespan:
            lifespan_returns.append(returns[i % len(returns)])
            lifespan_infl.append(infl_rate[i % len(infl_rate)])
            
        # loop through each year of retirement for each case run
        for index, i in enumerate(lifespan_returns):
            infl = lifespan_infl[index]

            # don't adjust for inflation the first year
            if index == 0:
                withdraw_infl_adj_1 = int(withdrawal_1)
                withdraw_infl_adj_2 = int(withdrawal_2)
            else:
                withdraw_infl_adj_1 = int(withdraw_infl_adj_1 * (1 + infl))
                withdraw_infl_adj_2 = int(withdraw_infl_adj_2 * (1 + infl))

            if index < 5:
                withdraw_infl_adj = withdraw_infl_adj_1
            else:
                withdraw_infl_adj = withdraw_infl_adj_2

            investments -= withdraw_infl_adj
            investments = int(investments * (1 + i))

            if investments <= 0:
                bankrupt = 'yes'
                break

        if bankrupt == 'yes':
            outcome.append(0)
            bankrupt_count += 1
        else:
            outcome.append(investments)
            
        case_count += 1

    return outcome, bankrupt_count

def bankrupt_prob(outcome, bankrupt_count):
    """Calculate & return chance of running out of money & print statistics."""
    total = len(outcome)
    odds = round(100 * bankrupt_count / total, 1)

    print("\nInvestment type: {}".format(invest_type))
    print("Starting value: ${:,}".format(int(start_value)))
    print("Annual withdrawal first 5 yrs: ${:,}".format(int(withdrawal_1)))
    print("Annual withdrawal after 5 yrs: ${:,}".format(int(withdrawal_2))) 
    print("Years in retirement (min-ml-max): {}-{}-{}"
          .format(min_years, most_likely_years, max_years))
    print("Number of runs: {:,}\n".format(len(outcome)))
    print("Odds of running out of money: {}%\n".format(odds))
    print("Average outcome: ${:,}".format(int(sum(outcome) / total)))
    print("Minimum outcome: ${:,}".format(min(i for i in outcome)))
    print("Maximum outcome: ${:,}".format(max(i for i in outcome)))

    return odds
Note: Input data should be in percent, not decimal!

   stocks = SP500
    bonds = 10-yr Treasury Bond
 sb_blend = 50% SP500/50% TBond
sbc_blend = 40% SP500/50% TBond/10% Cash

Press ENTER to take default value shown in [brackets]. 

Enter investment type: (stocks, bonds, sb_blend, sbc_blend): 
 [bonds]: bonds
Input starting value of investments: 
 [2000000]: 2000000
Input annual pre-tax withdrawal for first 5 yrs(today's $): 
 [100000]: 100000
Input annual pre-tax withdrawal for remainder (today's $): 
 [80000]: 80000
Input minimum years in retirement: 
 [18]: 18
Input most-likely years in retirement: 
 [25]: 25
Input maximum years in retirement: 
 [40]: 40
Input number of cases to run: 
 [50000]: 50000
In [26]:
outcome, bankrupt_count = montecarlo(investment_type_args[invest_type])
odds = bankrupt_prob(outcome, bankrupt_count)

# generate matplotlib bar chart 
plotdata = outcome[:3000]  # only plot first 3000 runs
plt.figure('Outcome by Case (showing first {} runs)'.format(len(plotdata)),
           figsize=(16, 5))  # size is width, height in inches
index = [i + 1 for i in range(len(plotdata))]
plt.bar(index, plotdata, color='black')
plt.xlabel('Simulated Lives', fontsize=18)
plt.ylabel('$ Remaining', fontsize=18)
plt.ticklabel_format(style='plain', axis='y')
ax = plt.gca()
ax.get_yaxis().set_major_formatter(plt.FuncFormatter(lambda x, loc: "{:,}"
                                                     .format(int(x))))
plt.title('Probability of running out of money = {}%'.format(odds),
          fontsize=20, color='red')
plt.show()
Investment type: bonds
Starting value: $2,000,000
Annual withdrawal first 5 yrs: $100,000
Annual withdrawal after 5 yrs: $80,000
Years in retirement (min-ml-max): 18-25-40
Number of runs: 50,000

Odds of running out of money: 42.4%

Average outcome: $1,455,728
Minimum outcome: $0
Maximum outcome: $14,033,611

Chap13

In [27]:
!wget https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_13/tvashtar_plume.gif
--2020-08-20 10:47:28--  https://raw.githubusercontent.com/rlvaugh/Impractical_Python_Projects/master/Chapter_13/tvashtar_plume.gif
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14789 (14K) [image/gif]
Saving to: ‘tvashtar_plume.gif’

tvashtar_plume.gif  100%[===================>]  14.44K  --.-KB/s    in 0.01s   

2020-08-20 10:47:28 (1.14 MB/s) - ‘tvashtar_plume.gif’ saved [14789/14789]

In [28]:
!mkdir particles
In [29]:
!apt install xvfb
!pip install pyvirtualdisplay
!pip install pygame
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following package was automatically installed and is no longer required:
  libnvidia-common-440
Use 'apt autoremove' to remove it.
The following NEW packages will be installed:
  xvfb
0 upgraded, 1 newly installed, 0 to remove and 35 not upgraded.
Need to get 784 kB of archives.
After this operation, 2,266 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 xvfb amd64 2:1.19.6-1ubuntu4.4 [784 kB]
Fetched 784 kB in 1s (1,125 kB/s)
Selecting previously unselected package xvfb.
(Reading database ... 144487 files and directories currently installed.)
Preparing to unpack .../xvfb_2%3a1.19.6-1ubuntu4.4_amd64.deb ...
Unpacking xvfb (2:1.19.6-1ubuntu4.4) ...
Setting up xvfb (2:1.19.6-1ubuntu4.4) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Collecting pyvirtualdisplay
  Downloading https://files.pythonhosted.org/packages/d0/8a/643043cc70791367bee2d19eb20e00ed1a246ac48e5dbe57bbbcc8be40a9/PyVirtualDisplay-1.3.2-py2.py3-none-any.whl
Collecting EasyProcess
  Downloading https://files.pythonhosted.org/packages/48/3c/75573613641c90c6d094059ac28adb748560d99bd27ee6f80cce398f404e/EasyProcess-0.3-py2.py3-none-any.whl
Installing collected packages: EasyProcess, pyvirtualdisplay
Successfully installed EasyProcess-0.3 pyvirtualdisplay-1.3.2
Collecting pygame
  Downloading https://files.pythonhosted.org/packages/8e/24/ede6428359f913ed9cd1643dd5533aefeb5a2699cc95bea089de50ead586/pygame-1.9.6-cp36-cp36m-manylinux1_x86_64.whl (11.4MB)
     |████████████████████████████████| 11.4MB 2.9MB/s 
Installing collected packages: pygame
Successfully installed pygame-1.9.6
In [30]:
from pyvirtualdisplay import Display
d = Display()
d.start()
Out[30]:
<pyvirtualdisplay.display.Display at 0x7f1c396e2c88>
In [31]:
import sys
import math
import random
import pygame as pg

pg.init()
    
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
LT_GRAY = (180, 180, 180)
GRAY = (120, 120, 120)
DK_GRAY = (80, 80, 80)

class Particle(pg.sprite.Sprite):

    gases_colors = {'SO2': LT_GRAY, 'CO2': GRAY, 'H2S': DK_GRAY, 'H2O': WHITE}
    
    VENT_LOCATION_XY = (320, 300)  # mouth of volcano
    IO_SURFACE_Y = 308  # y location of Io surface
    GRAVITY = 0.5  # pixels-per-frame   
    VELOCITY_SO2 = 8  # pixels-per-frame
    
    # scalars (SO2 atomic weight/particle atomic weight) used for velocity
    vel_scalar = {'SO2': 1, 'CO2': 1.45, 'H2S': 1.9, 'H2O': 3.6}    
      
    def __init__(self, screen, background):
        super().__init__()
        self.screen = screen
        self.background = background
        self.image = pg.Surface((4, 4))
        self.rect = self.image.get_rect()
        self.gas = random.choice(list(Particle.gases_colors.keys()))
        self.color = Particle.gases_colors[self.gas]
        self.vel = Particle.VELOCITY_SO2 * Particle.vel_scalar[self.gas]      
        self.x, self.y = Particle.VENT_LOCATION_XY
        self.vector()

    def vector(self):
        """Calculate particle vector at launch."""
        orient = random.uniform(60, 120)  # 90 is vertical
        radians = math.radians(orient)
        self.dx = self.vel * math.cos(radians)
        self.dy = -self.vel * math.sin(radians)  # negative as y increases down
        
    def update(self):
        """Apply gravity, draw path, and handle boundary conditions."""
        self.dy += Particle.GRAVITY
        pg.draw.line(self.background, self.color, (self.x, self.y),
                     (self.x + self.dx, self.y + self.dy))
        self.x += self.dx
        self.y += self.dy
        if self.x < 0 or self.x > self.screen.get_width():
            self.kill()
        if self.y < 0 or self.y > Particle.IO_SURFACE_Y:
            self.kill()
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
In [32]:
screen = pg.display.set_mode((639, 360))
pg.display.set_caption('Io Volcano Simulator')
background = pg.image.load('tvashtar_plume.gif')

# Set-up color-coded legend
legend_font = pg.font.SysFont('None', 24)
water_label = legend_font.render('--- H2O', True, WHITE, BLACK)
co2_label = legend_font.render('--- CO2', True, GRAY, BLACK)
so2_label = legend_font.render('--- SO2/S2', True, LT_GRAY, BLACK)
h2s_label = legend_font.render('--- H2S', True, DK_GRAY, BLACK)

particles = pg.sprite.Group()

clock = pg.time.Clock()

img = []
#while True:
for i in range(100):
    clock.tick(25)
    particles.add(Particle(screen, background))
    for event in pg.event.get():
        if event.type == pg.QUIT:
            pg.quit()
            sys.exit()

    screen.blit(background, (0, 0))
    screen.blit(water_label, (40, 20))
    screen.blit(h2s_label, (40, 40))
    screen.blit(co2_label, (40, 60))
    screen.blit(so2_label, (40, 80))
    particles.update()
    particles.draw(screen)
    pg.image.save(screen, 'particles/particles' + str(i).zfill(4) + '.jpg')
    pg.display.flip()
In [34]:
from PIL import Image, ImageDraw

images = list()
for i in range(100):
  img = Image.open("particles/particles{0:04d}.jpg".format(i))
  images.append(img)
images[0].save('particles.gif',
               save_all=True, append_images=images[1:], optimize=False)
In [35]:
# from JSAnimation.IPython_display import display_animation
import matplotlib.pyplot as plt
from matplotlib import animation
from IPython.display import HTML

plt.figure(figsize=(639/72, 360/72), dpi=72)
patch = plt.imshow(images[0])
plt.axis('off')
  
def animate(i):
  patch.set_data(images[i])
    
anim = animation.FuncAnimation(plt.gcf(), animate, frames=len(images), interval=50)
HTML(anim.to_jshtml())
Out[35]: