乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

プログラミング

非常に役に立た無いプログラムを作ってみました。

何処かで架空の国旗を作った
みたいな話が出ていたので
自分も架空の国旗作りに挑戦してみました。

解説動画はこちら




コードはこちら
from PIL import Image, ImageDraw, ImageFont
import matplotlib.pyplot as plt
import numpy as np
import random
%matplotlib inline

size  = (320, 180)
c,o = (0,64,128,192,255) , (32,96,160,224)
colors = [(r,g,b) for r in c for g in c for b in c]
ol_colors = [(r,g,b) for r in o for g in o for b in o]
base_color = random.choice(colors)

def base():
    im =  Image.new('RGB',size)
    target = random.randint(1,6)
    # 配色
    rgb = (random.choice(colors),random.choice(colors),random.choice(colors))
    # べた塗り
    if target ==1:
        [im.putpixel((x,y),rgb[0]) for x in range(size[0]) for y in range(size[1])]
    # 縦半分
    elif target ==2:
        [im.putpixel((x,y),rgb[0]) for x in range(0,size[0]//2) for y in range(size[1])]
        [im.putpixel((x,y),rgb[1]) for x in range(size[0]//2,size[0]) for y in range(size[1])]
    # 横半分
    elif target ==3:
        [im.putpixel((x,y),rgb[0]) for x in range(size[0]) for y in range(0,size[1]//2)]
        [im.putpixel((x,y),rgb[1]) for x in range(size[0]) for y in range(size[1]//2,size[1])]
    # 縦3分
    elif target ==4:
        [im.putpixel((x,y),rgb[0]) for x in range(0,size[0]//3) for y in range(size[1])]
        [im.putpixel((x,y),rgb[1]) for x in range(size[0]//3,size[0]//3*2) for y in range(size[1])]
        [im.putpixel((x,y),rgb[2]) for x in range(size[0]//3*2,size[0]) for y in range(size[1])]
    # 横3分
    elif target ==5:
        [im.putpixel((x,y),rgb[0]) for x in range(size[0]) for y in range(0,size[1]//3)]
        [im.putpixel((x,y),rgb[1]) for x in range(size[0]) for y in range(size[1]//3,size[1]//3*2)]
        [im.putpixel((x,y),rgb[2]) for x in range(size[0]) for y in range(size[1]//3*2,size[1])]
    # 4ブロック
    elif target ==2:
        [im.putpixel((x,y),rgb[0]) for x in range(0,size[0]//2) for y in range(0,size[1]//2)]
        [im.putpixel((x,y),rgb[1]) for x in range(size[0]//2,size[0]) for y in range(0,size[1]//2)]
        [im.putpixel((x,y),rgb[1]) for x in range(0,size[0]//2) for y in range(size[1]//2,size[1])]
        [im.putpixel((x,y),rgb[0]) for x in range(size[0]//2,size[0]) for y in range(size[1]//2,size[1])]
    # 9ブロック
    elif target ==6:
        [im.putpixel((x,y),rgb[0]) for x in range(0,size[0]//3) for y in range(0,size[1]//3)]
        [im.putpixel((x,y),rgb[1]) for x in range(size[0]//3,size[0]//3*2) for y in range(0,size[1]//3)]
        [im.putpixel((x,y),rgb[2]) for x in range(size[0]//3*2,size[0]) for y in range(0,size[1]//3)]
        [im.putpixel((x,y),rgb[1]) for x in range(0,size[0]//3) for y in range(size[1]//3,size[1]//3*2)]
        [im.putpixel((x,y),rgb[2]) for x in range(size[0]//3,size[0]//3*2) for y in range(size[1]//3,size[1]//3*2)]
        [im.putpixel((x,y),rgb[0]) for x in range(size[0]//3*2,size[0]) for y in range(size[1]//3,size[1]//3*2)]
        [im.putpixel((x,y),rgb[2]) for x in range(0,size[0]//3) for y in range(size[1]//3*2,size[1])]
        [im.putpixel((x,y),rgb[0]) for x in range(size[0]//3,size[0]//3*2) for y in range(size[1]//3*2,size[1])]
        [im.putpixel((x,y),rgb[1]) for x in range(size[0]//3*2,size[0]) for y in range(size[1]//3*2,size[1])]
    return im

def overlay():
    im_ol = Image.new('RGB',size,(100,100,100))
    target = random.randint(1,9)
    # 配色
    rgb = (random.choice(ol_colors),random.choice(ol_colors),random.choice(ol_colors))
    for x in range(size[0]):
        for y in range(size[1]):
            # 十字
            if target ==1:
                if (x >= size[0]//7*3 and x <= size[0]//7*4) or (y >= size[1]//5*2 and y <= size[1]//5*2+size[0]//7) :
                    im_ol.putpixel((x,y),rgb[0])
            # 左斜め
            elif target ==2:
                if (x >= y*size[0]//size[1] and x <= y*size[0]//size[1] + size[1]//4) :
                    im_ol.putpixel((x,y),rgb[0])
            # 右斜め
            elif target ==3:
                if (x >= size[0] - size[1]//4  - y*size[0]//size[1] and x <= size[0] - y*size[0]//size[1]) :
                    im_ol.putpixel((x,y),rgb[0])
            # クロス
            elif target ==4:
                if (x >= y*size[0]//size[1] and x <= y*size[0]//size[1] + size[1]//4)  or (x >= size[0] - size[1]//4  - y*size[0]//size[1] and x <= size[0] - y*size[0]//size[1]):
                    im_ol.putpixel((x,y),rgb[0])
            # なし
            elif target ==5:
                pass
            # 左三角
            elif target ==6:
                if (x=size[1]//2):
                    im_ol.putpixel((x,y),rgb[0])
            # ダイヤ
            elif target ==7:
                if (x >= (size[0]  - y*size[0]//size[1]) - size[0]//2 and x<= size[0]//2  + (y*size[0]//size[1])  and y<=size[1]//2):
                    im_ol.putpixel((x,y),rgb[0])
                if ( x >= y*size[0]//size[1]-size[0]//2 and x<= size[0] -(y*size[0]//size[1]-size[0]//2)  and y>=size[1]//2):
                    im_ol.putpixel((x,y),rgb[0])
            # ずれ十字
            if target ==8:
                if (x >= size[0]//7*1 and x <= size[0]//7*2) or (y >= size[1]//5*1 and y <= size[1]//5*1+size[0]//7) :
                    im_ol.putpixel((x,y),rgb[0])
            # 左上
            if target ==9:
                if (x >= 0 and x <= size[0]//3)  and   (y >= 0 and y <= size[1]//2):
                    im_ol.putpixel((x,y),rgb[0])
    if random.choice([True,False,False,False,False,False,False,False]):
        im_ol = Image.new('RGB',size,(100,100,100))
        draw = ImageDraw.Draw(im_ol)
        e_size = max(size)//3
        x1,y1 = (size[0]-e_size)//2 , (size[1]-e_size)//2
        x2,y2 = size[0]-(size[0]-e_size)//2 , size[1]-(size[1]-e_size)//2
        draw.ellipse((x1,y1,x2,y2), fill=rgb[0], outline=rgb[0])
    return im_ol

def simbol():
    rgb = (random.choice(ol_colors),random.choice(ol_colors),random.choice(ol_colors))
    s_size,gray = (size[0]//3,size[1]//2),(100,100,100)
    im_si = Image.new('RGB',s_size,gray)
    draw = ImageDraw.Draw(im_si)
    target = random.randint(1,8)
    if target==1:
        draw.ellipse((0,0,s_size[0],s_size[1]), fill=rgb[0], outline=rgb[0])
        draw.ellipse((30,10,s_size[0],s_size[1]-10), fill=gray, outline=gray)
    elif target ==2:
        draw.ellipse((0,0,s_size[0],s_size[1]), fill=rgb[0], outline=rgb[0])
        draw.ellipse((15,15,s_size[0]-15,s_size[1]-15), fill=gray, outline=gray)
    elif target==3:
        draw.ellipse((0,0,s_size[0],s_size[1]), fill=rgb[0], outline=rgb[0])
        draw.ellipse((0,10,s_size[0]-30,s_size[1]-10), fill=gray, outline=gray)
    elif target==4:
        draw.pieslice((0, 0, s_size[0],s_size[1]), start=     0, end=  60, fill=rgb[0], outline=gray)
        draw.pieslice((0, 0, s_size[0],s_size[1]), start=120, end=180, fill=rgb[0], outline=gray)
        draw.pieslice((0, 0, s_size[0],s_size[1]), start=240, end=300, fill=rgb[0], outline=gray)
    elif target ==5:
        draw.pieslice((0, 0, s_size[0],s_size[1]), start=30, end=150, fill=rgb[0], outline=gray)
        draw.pieslice((0, 0, s_size[0],s_size[1]), start=210, end= 330, fill=rgb[0], outline=gray)
    elif target ==6:
        for x in [i*60+15 for i in range(6)]:
            draw.pieslice((0, 0, s_size[0],s_size[1]), start=x, end=x+30, fill=rgb[0], outline=gray)
    elif target ==7:
        for x in [i*45 for i in range(8)]:
            draw.pieslice((0, 0, s_size[0],s_size[1]), start=x+15, end=x+30, fill=rgb[0], outline=gray)
    elif target ==7:
        pass
    if random.choice([True,False,False,False,False]):
        draw.pieslice((20, 20, s_size[0]-20,s_size[1]-20), start=     0, end= 360, fill=rgb[0])
    return im_si

# 実行部
im_base = base()
im_ol = overlay()
im_si = simbol()
si_x , si_y = im_si.size[0],im_si.size[1]
s_size = (size[0]//3,size[1]//2)
for x in range(size[0]):
    for y in range(size[1]):
        r,g,b = im_ol.getpixel((x,y))
        if all([r!=100,g!=100,b!=100]):
            im_base.putpixel((x,y),(r,g,b))

for x in range(s_size[0]):
    for y in range(s_size[1]):
        r,g,b = im_si.getpixel((x,y))
        if all([r!=100,g!=100,b!=100]):
            im_base.putpixel((x,y),(r,g,b))

file_name = 'fictional_flag.png'
im_base.save(file_name)

使い方は簡単
コードをJupyter Notebookにコピーして
実行するだけ

ランダムで架空の国旗pngファイルを生成します。

簡単に説明すると
base画像をPILで作ります。
この時点で何色かに色分けされた画像ができます。

そこにoverlayで画像を付け足します。
十字とか、斜め線が入ったりします。
最後にsimbolでシンボルマークを付け足して出来上がり。

シンボルはnumpyとImageDrawを使っていろいろやっています。
円を特定の角度分だけ塗ったりすれば
ピザのスライスになり
そこに円を足せば雪マークになったりしますね。


flag


シンボルが左上にしか描画していなかったり、
パターンが少なかったりで
全部のパターンを把握していませんが
まあまあの組み合わせになるんではないでしょうか?

1ピクセルづつ色を塗っているだけの
単純なプログラムで
複雑な形を表現できていないです。

も少しスマートに描く方法は
ないものだろうか・・・

片手間では
この程度でしょうか。


またまた数字のトリビアの検証です

解説動画はこちら




最初のトリビアは
数字のトリビア.007




初めのトリビアは
数字のトリビア.011

きれいに1が並ぶピラミッドのような
かけ算の方法です。

桁が増えるごとに
1
12
123

と数を増やして行き
そこに9をかけて元の数より1大きい数を足します。

すると綺麗に1が並ぶピラミッドが形成されます。

コードは
for i in range(1,10):
    tmp = ''
    for j in range(1,i+1):
        tmp+=str(j)
    print('{0: 11} * 9 + {1:02}'.format(int(tmp),i+1), int(tmp)*9 +i+1)

結果は:

1 * 9 + 02 11
12 * 9 + 03 111
123 * 9 + 04 1111
1234 * 9 + 05 11111
12345 * 9 + 06 111111
123456 * 9 + 07 1111111
1234567 * 9 + 08 11111111
12345678 * 9 + 09 111111111
123456789 * 9 + 10 1111111111

となります。

お次は
数字のトリビア.012

これも似たようなかけ算です。

かける数字は1を桁分用意して、それを二乗するような形になります。

コードは
for i in range(1,10):
    a = int('1' *i)
    print('{0: 10} * {0: 10} = '.format(a) , a*a)


結果は:
1 * 1 = 1
11 * 11 = 121
111 * 111 = 12321
1111 * 1111 = 1234321
11111 * 11111 = 123454321
111111 * 111111 = 12345654321
1111111 * 1111111 = 1234567654321
11111111 * 11111111 = 123456787654321
111111111 * 111111111 = 12345678987654321

先ほどとは真逆で、1の連続を掛け合わせると
どんどん数字が重なって行きます。

次のトリビアは
数字のトリビア.013

宴会や合コンで使えるテクニックです。

まずは365日分の文字を用意します。
nums = []
for m in range(1,13):
    for d in range(1,32):
        if m==2 and d>28:
            continue
        elif m in (4,6,9,11) and d==31:
            continue
        nums.append('{0:02}{1:02}'.format(m,d))
次に
その文字を使って1年分の検証をします。

上記操作をすると
最後に相手に答えてもらった数字から225を引くと
相手の誕生日になるということです。

for day in nums:
    m = int(day[0:2])
    d = int(day[2:4])
    m2 = m * 4
    m3 = m2 + 9
    m4 = m3 * 25
    m5 = m4 + d
    answer = m5 -225
    print(day , answer)
結果は全部同じ日になります。

これでうまいこと
誕生日を知ることができるわけです。

まあ最初は
郵便番号とかしか
聞いてはダメでしょうねwww


次は

数字のトリビア.014

人と人との出会いが
いかに奇跡的なことかというお話です。
res=1
for num ,name in zip([1,60,60,24,365,50],['秒','分','時間','日','年','50年']):
    res*=num
    print('{0}は{1}秒'.format(name , res))
秒は1秒
分は60秒
時間は3600秒
日は86400秒
年は31536000秒
50年は1576800000秒

1秒に1人出会えても
50年で15億人しか出会うことはでき無いのです。

地球の全人類と出会うには
250年は掛かりそうです。

なので人生にの出会いというものは
奇跡なのだよという、ちょっと哲学的なお話です。


さて最後のトリビアは
数字のトリビア.015


組み換えが気持ちいーー
6桁の数字が有ります

それは

142857

これに
1から数字をかけて行くと・・・

for i in range(1,8):
    print('142857 * {0}'.format(i) , 142857 * i)

142857 * 1 142857
142857 * 2 285714
142857 * 3 428571
142857 * 4 571428
142857 * 5 714285
142857 * 6 857142
142857 * 7 999999

はい、結果は同じ数字が入れ替わります。
7までかけたら終了ですね。

いやー気持ちいい




はい
またまた 数字のトリビアをPythonで検証してみました。

解説動画はこちら




最初のトリビアは
数字のトリビア.007

割るときれいな数字がでる組み合わせです。

コードは
print(1/81)
print(1/891)
print(1/8991)
print(1/89991)
print(1/8181)
print(1/818181)

0.012345679012345678
0.001122334455667789
0.00011122233344455567
1.1112222333344445e-05
0.0001222344456667889
1.2222234444456666e-06

以外ときれいに並びますねー
Pythonのデフォルトでは桁数がそんなに多く出せ無いので
こんな感じになってしまいます。


次は
数字のトリビア.008

またまた割り算のトリビアですが
これはデフォルトでは桁が足り無いので
正確な小数点の計算をするためのライブラリを用います。

decimal

コードは
import decimal

decimal.getcontext().prec = 1000
a = decimal.Decimal(10000)
b = decimal.Decimal(9801)
print(a / b)
結果は・・・
1.02030405060708091011121314151617181920
2122232425262728293031323334353637383940
4142434445464748495051525354555657585960
6162636465666768697071727374757677787980
818283848586878889909192939495969799000
・・・
1から一つづつ数字が増えていく結果になります。

おしい
97までは並んだのに

というかこれを発見した人
絶対ヒマ人でしょ

こんな計算
いつやるの?


・・
・・・

ひまでしょ!!

はい。

お次は
数字のトリビア.009

なんか良くわかりませんが上記の操作をすると
必ず同じ数字に戻るんだそうです。
なんか不思議ですね
for i in range(100,1000):
    a2 = int(str(i)*2)
    a3 = a2//7
    a4 = a3//11
    a5 = a4//13
    print(i,a5)



トリは
数字のトリビア.010

ゾロ目以外の4桁の数字で
数字を大きい順に並び替えたものから
数字を小さい順に並び替えたものを引く。

それをまた同じ操作をしていくと・・・

6174になるんだそう。

検証したコードはこちらに。

まずは上記の操作をする関数kapを作ります。
6174になるまで再帰します。

def kap(i):
    ma = sorted([a for a in str(i)],reverse=True)
    mi  = sorted([a for a in str(i)])
    m  = int(''.join(ma)) - int(''.join(mi))
    if m ==6174:
        return m
    else:
        return kap(m)
for i in range(1000,10000):
    if str(i)[0]==str(i)[1]==str(i)[2]==str(i)[3]:
        continue
    else:
        try:
            m = kap(i)
            print(i,m)
        except:
            print(i,'X')

あとはゾロ目は除いて
4桁の数字を検証。

だいたいは
6174になるようですね。
一部は再帰が終わらずエラーになってしまいました。


このように
最大に並べ替えたものから最小に並べ替えたものを引いた答えが
元と同じになるような数をカプレカ数と言うのだそうで。

なかなか面白い数字ですね。

また次回もお楽しみに!!

数字にまつわるトリビアを
Pythonで検証してみました。


解説動画はこちら




まず始めのトリビアは

数字のトリビア.002

はい、1回折れれば厚さが二倍になるということで
検証したコードがこちら
moon = 0.08 * (2 ** 43)
print('{}万キロ'.format(moon/10/100/1000/10000))
70.368744177664万キロ

飛んでもないですね
43乗すれば月まで届きそうですね

折れればですが

花山薫のピンチ力をもってしても
無理そうな問題です

お次が
数字のトリビア.003
コードは
for i in range(1,10):
    print('3912657840 / {0} '.format(i) , 3912657840%i)

3912657840 / 1 0
3912657840 / 2 0
3912657840 / 3 0
3912657840 / 4 0
3912657840 / 5 0
3912657840 / 6 0
3912657840 / 7 0
3912657840 / 8 0
3912657840 / 9 0

余りがないということは割り切れている
ということで、きれいに割り切れました。

お次は
数字のトリビア.004

これまた割り切り問題ですね

コードは
まずこの9つの数字を使った順列を求めます。
import itertools
seq = ['1','2','3','4','5','6','7','8','9']
per = list(itertools.permutations(seq))
print(len(per))
362880

この順列と同じだけ検証して
合っていれば+1カウントします。

結果は・・
count = 0
for tmp in itertools.permutations(seq):
    num = int(''.join(tmp))
    if num % 3 == 0:
        count+=1
print(count)
362880

全部割り切れました。1-9全部使った9桁の数値は
みな3で割り切れます。

ちなみにこの数は絶対9の倍数になるので
必ず3では割り切れるようになっています。

次は
数字のトリビア.005


コードは
for i in range(1,10):
    print('12345679 * 9 * {0}'.format(i) , 12345679 * 9 * i)

12345679 * 9 * 1 111111111
12345679 * 9 * 2 222222222
12345679 * 9 * 3 333333333
12345679 * 9 * 4 444444444
12345679 * 9 * 5 555555555
12345679 * 9 * 6 666666666
12345679 * 9 * 7 777777777
12345679 * 9 * 8 888888888
12345679 * 9 * 9 999999999

結果は綺麗にそろいます。
元の数字は8だけ抜けてますけどね。

さて最後は
数字のトリビア.006


語呂合わせで
18782 + 18782

この結果は・・・・

37564

ということでした。
良く知られた数字の計算ですね。

また次回も数字のトリビアをお送りします。

週1でお世話になるサイゼリア

好きなメニューは
青豆の温サラダ

これがあるから
サイゼリアは止められない!!!!

そんなサイゼリアさんで
いつも話題に上がるのが

サイゼリアの間違い探し
難しすぎ問題


普段そんなに
間違い探しとかに気を取られないが

注文したメニューが来るまでは
考えちゃいますよねーー

そんな間違い探しを
プログラムの力で解いてみたい
という挑戦です。

動画はこちら




まずは
元の画像をサイゼリアさんの公式ページから
お借りしてきました。

間違い探し

saize201810

これが間違い探しの問題の画像です。

これは1200 x 578ピクセルのサイズでした。

これを
左右を同じサイズで切り取って
そのピクセルを比較すれば、
間違い探しの答えが浮かび上がるのではないか?

そう考えたわけです。

まずは
左右二つの画像に切り分けます。

Pythonでは画像を取り扱うライブラリもあるので
それが使えます。

まずはライブラリのインポート
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

im = Image.open('saize201810.png')
rgb_im = im.convert('RGB’)
PILというライブラリで画像を取り込み
描画用にmatplotlibを使います。

matplotlibの画像を描画させるのに
numpyのarrayでなければならないので
numpyも読み込み

matplotlibを
インラインで表示させたいので指定します。

画像をとりこんだあとは
左右に切り分けます。
im1 = Image.new('RGB',(572,578))
im2 = Image.new('RGB',(572,578))

for x in range(0,572):
    for y in range(578):
        r,g,b = rgb_im.getpixel((x+28,y))
        im1.putpixel((x,y),(r,g,b))
        
for x in range(601,1173):
    for y in range(578):
        r,g,b = rgb_im.getpixel((x,y))
        im2.putpixel((x-601,y),(r,g,b))

plt.imshow(np.array(im1))
plt.imshow(np.array(im2))

左右に余白があり
マージンを取って取り込みます。
ピクセルのRGB値を取得して
新たな画像として生成します。

左側

saize1

右側
saize2

次に
この画像のピクセル同士を比較します。

この問題の左右がコピーされていて
ほぼ同じものであったなら
そのピクセルの違う部分が答えなのではないかと

im3 = Image.new('RGB',(572,578))

for x in range(572):
    for y in range(578):
        r1,g1,b1 = im1.getpixel((x,y))
        r2,g2,b2 = im2.getpixel((x,y))
        if r1!=r2 or g1!=g1 or b1!=b2:
            im3.putpixel((x,y),(r1,g1,b1))
        else:
            im3.putpixel((x,y),(0,0,0))

plt.imshow(np.array(im3))

左右のピクセルを比較した結果
違っていればそのピクセルを
合っていれば黒で答えを作りました。

結果は・・・・

saize3

なんか
いろいろ写っちゃってるやないかーーい


左右は全くの同じではなく
少し違いがあるか、ズレが生じているようで

単純なピクセルの比較では
答えの部分だけを出すのは難しいようです。

一応、違いが大きいところは
色が付いているので
着目すれば10個の答えは出そうですが

うまく、結果だけを出す
アルゴリズムを考えないと
くっきりした答えには
たどり着けないですねーーー

うーん
画像は奥が深い

ということで
皆さん
サイゼでガッツリ食べながら
この問題を解いてみましょう(笑)


このページのトップヘ