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

プログラミング

さて
今回は免許証番号のチェックデジットについての
お話になります。

動画はこちら




免許証番号にも法則性があり
必ず一定のルールに従った番号体系になっています。

もしそのルールに番号に沿っていなかったら
そこで偽造だとわかる事になります。

 まず最初に免許証番号のルールですが
こんな感じだそうです。

免許証番号は、県警察電算処理システムの電子計算機で管理し
新規免許登録時に付与されるが、 公安委員会コード
年号記号、交付番号及び再交付記号並びに
チェックデジットをもって構成する(12桁の数)。

例 309212345610

最初の2桁は公安委員会コード
続く2桁は発行年号(下2桁)
続く6桁が交付番号(発行番号)
その次1桁がチェックデジット
最後の1桁は再発行回数

menban


公安委員会コードは定められていて
こんな感じです。
北海道 北海道
10
函館
11
旭川
12
釧路
13
北見
14
           
東北 青森
20
岩手
21
宮城
22
秋田
23
山形
24
福島
25
         
関東甲信越 東京
30
茨城
40
栃木
41
群馬
42
埼玉
43
千葉
44
神奈川
45
新潟
46
山梨
47
長野
48
静岡
49
北陸・中部 富山
50
石川
51
福井
52
岐阜
53
愛知
54
三重
55
         
関西 滋賀
60
京都
61
大阪
62
兵庫
63
奈良
64
和歌山
65
         
中国 鳥取
70
島根
71
岡山
72
広島
73
山口
74
           
四国 徳島
80
香川
81
愛媛
82
高知
83
             
九州・沖縄 福岡
90
佐賀
91
長崎
92
熊本
93
大分
94
宮崎
95
鹿児島
96
沖縄
97
     
東京で取得したならば
30ということになります。

続く年号記号(3桁目と4桁目の数字)は
初めて免許を取得した年の西暦下2桁
になります。

例:
2019年に取得 → 19
1992年に取得 → 92

ということで
あまりにもかけ離れていた場合
(今25歳なのに99になっているとか)
その番号が偽りの番号であると
すぐにわかる仕組みです。

続く6桁は発行番号で
一意になるような番号体系です。


最後の12桁目は再交付記号

再交付記号「0」は、再発行がされた事がないのを示し

この数字は紛失・盗難などで再発行する度に増えていき

10回再発行された場合には「1」と記載される仕組みです

なのでほとんどの人は
再発行していないと思うので
「0」になっているのではないかと思います。


そして
11桁目がチェックデジットです。

免許証のチェックデジットの計算方法は
次のとおりになります。


左から10個の数字にそれぞれ、5,4,3,2,7,6,5,4,3,2をかけて合計する

例:「309212345690」のうちの「3092123456」

5×3+4×0+3×9+2×2+7×1+6×2+5×3+4×4+3×5+2×6=123

次に、これを11で割って余りを出す 123÷11=11 余り 2

さらに、11から余りを引く 11-2=9


計算式 :
上位10桁をabcdefghijとすると

(11 - (5a+4b+3c+2d+7e+6f+5g+4h+3i+2j) mod 11) mod 10

チェックデジットを計算する関数は次のようになります。

def check_menkyo_degit(t):
    a = 5*int(t[0])
    b = 4*int(t[1])
    c = 3*int(t[2])
    d = 2*int(t[3])
    e = 7*int(t[4])
    f = 6*int(t[5])
    g = 5*int(t[6])
    h = 4*int(t[7])
    i = 3*int(t[8])
    j = 2*int(t[9])
    degit  = a+b+c+d+e+f+g+h+i+j
    return (11 - degit%11)%10

check_menkyo_degit('309212345690')
9

免許証番号を引数に入れると
チェックデジットが出ます。


これを使って
免許証番号を生成してみましょう。

東京で1999年に取得
交付番号はランダム
再発行は無し
とすると

def make_menkyo(st=30,year=1999):
    t = str(st) + str(year)[2:4]
    t += '{0:06}'.format(random.randint(1,10000))
    cd = check_menkyo_degit(t)
    return t + str(cd) + '0'

make_menkyo()

309900219680

このような形で作ることができます。


このようにチェックデジットは
偽造の防止などに役立てられているので

この番号体系に合わないものは
すぐに弾ける仕組みとなっています。

ましWEBサービスを運営しているのであれば
こういった番号のチェックを行うことで
不正防止をすることができます。

皆様も
お手元に免許証があれば
ぜひ番号チェックをしてみてください

今回はこれまでです
それでは。







さて今回は
「チェックデジット」
というものについてのお話です。




動画はこちら

 



チェックデジットは
データの正確性を保つ為に使用される文字のことで
様々な分野のID番号などの使用されています。

工業用のコード
クレジットカード
免許証

いろんなチェックデジットが存在し
計算方法が違っています。

今回はクレジットカードの
チェックデジットを計算してみましょう。

クレジットカードの番号には法則があり
最初の6桁はカードの発行元
7-15桁目はカード番号
最後の1桁がチェックデジット
となっています。

また
日本で流通しているカード体系で
最初の1桁は金融機関などの業種を表します。

例えば
Visa 4xxxxx
Mastercard51xxxx - 55xxxx
Amex 34xxxx, 37xxxx
などです。

なので最初の6桁と
最後の1桁は必ず法則に従わないと
そのクレジットカード番号は
正しくない番号となります。

それでは
チェックデジットを計算してみましょう。

クレジットカードのチェックデジットの計算方法

元の番号 : 4417123456789113

奇数桁目を2倍に掛ける
8 2 2 6 10 14 18 2

偶数桁目はそのまま足す
4 7 2 4 6 8 1 3

2桁の数は十の位と1の位を足して1桁にする
(2桁の数になったら9を引けばいい)

8+4+2+7+2+2+6+4+1+0+
6+1+4+8+1+8+1+2+3 = 70

和が10で割れる数なら、そのクレジットカードは有効

こんなルールでカード番号が作られています。

お手元に
クレジットカードがある方は
実際に計算してみてはいかがでしょうか?


それでは
このクレジットカードが正しいのかどうかを
計算するプログラムを作っていきたいと思います。

これは至極簡単で数行で済みます。

カード番号をチェックする関数はコレ。
def check_digit(num):
    tmp1 = [int(num[i])*2 for i in range(len(num)) if i%2==0]
    tmp1 = [i-9 if i>9 else i for i in tmp1]
    tmp2 = [int(num[i]) for i in range(len(num)) if i%2==1]
    total = sum(tmp1+tmp2)
    return total%10==0

これを使ってカード番号をチェックしてみましょう。

例題の番号をそのまま使い
check_digit('4417123456789113')
True

カード番号が合っていればTrue
違っていればFalseになります。



それではこの関数を使って
クレジットカード番号を生成してみましょう。

クレジットカード番号を生成する関数はコレ。

import random
def make_card(head = '498003'):    
    num = str(head) + ''.join([str(random.choice([i for i in range(10)])) for i in range(9)])
    for i in range(10):
        if check_digit(num + str(i)):
            return num + str(i)
    return None

実際に使う場合は
make_card(head = '498003')
4980030390770041

このようになります。

最初の6桁は発行元の番号体系に
合わせる必要があります。

引数headの6桁の番号を変更していただければ
その番号で始まるカード番号になります。



さて
チェックデジットはいかがでしたでしょうか?

このように
カード番号などは
チェック機能があるので
デタラメな番号は弾かれるようになっています。

ECサイトなども同様で
正しい番号体系を入れなければ
成立しないようにチェックが働いています。

皆様も
サイト構築をしたりする際は
チェックデジットの仕組みを導入すると
不正防止に繋がりますので
いろいろ考えてみてくださいね

今回はここまでです
それでは。


日本で一番有名なマークである

安産祈願マークを
プログラムで作ってみましょう!!!


動画はこちら



さて
作り方は
numpyとmatplotlibを用いて
マークを描いていきます。

widgetも用いて
うねうね変形できるようにもします。

ソースはこちら
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider, IntSlider,Select
%matplotlib inline

r = IntSlider(min=1, max=8, step=1, value=5)
t = FloatSlider(min=1.0, max=1.5, step=0.1, value=1.0)
c = Select(options=['black', 'red', 'blue','green'],
    value='black',description='coler : ',disabled=False)

@interact(r=r,t=t,c=c)
def plot_man(r,t,c):
    plt.figure(figsize=(10,9))
    plt.axes().set_aspect('equal', 'datalim')
    
    # circle 1
    x = [np.sin(np.radians(_x))*r for _x in np.linspace(-180,180,721)]
    y = [np.cos(np.radians(_y))*r*t for _y in np.linspace(-180,180,721)]
    plt.plot(x, y, c)
    
    # circle 2
    x2 = [i*0.7 for i in x]
    y2 = [i*0.7 for i in y]
    plt.plot(x2, y2, c)
    
    # line
    x3 = [0,0]
    y3 = [min(y)*1.25,max(y)*1.25]
    plt.plot(x3, y3, c)
    
    # lines
    x4 = [i*1.2 for i in x]
    y4 = [i*1.2 for i in y]
    for i in range(16):
        x5 = [x[i*45],x4[i*45]]
        y5 = [y[i*45],y4[i*45]]
        plt.plot(x5, y5, c)
    
    plt.xlim([-20,20])
    plt.ylim([-20,20])
    plt.show()



結果はこうなります。

スクリーンショット 2019-07-28 15.47.34


rで円の半径を変更
tで楕円の倍率を変更
colorで色を変更です。

楕円は
円の縦横方向を n 倍にすることで実現しています。

なので
縦方向であれば
xの値はそのままに
yの値の倍率を変えてあげると
縦方向の楕円になります。

今回のやり方では
まず半径を決めて円を用意します。
内側の円は1つめの円の倍率を変えただけです。

縦棒はxの値が0でyの値を変化させることで
実現させ、外側の棒たちは

大きな円を用意し
1つめの円から外側の円に向かう値で
描いています。

一応16本になるみたいなので
22.5度の角度になるような計算で
座標を求めています。

全部足すと
安産マークになります!!!!!!!




せっかくなので
GIFも作ってみましょう


matplotlibではアニメーション機能で
mp4やgifも作れますが
環境によっては動かないこともあり

今回は
画像をたくさん生成して
無理くりGIFに落とし込みます。


ソースはこちら
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider, IntSlider,Select
import os

data_dir = 'anzan_data/'
if not os.path.exists(data_dir):
    os.makedirs(data_dir)

for a in range(30):
    plt.figure(figsize=(3,3))
    plt.axes().set_aspect('equal', 'datalim')
    plt.tick_params(labelbottom=False,
                    labelleft=False,
                    labelright=False,
                    labeltop=False)
    plt.tick_params(bottom=False,
                    left=False,
                    right=False,
                    top=False)
    plt.xlim([-20,20])
    plt.ylim([-20,20])
    c ='black'
    n = (np.abs(np.sin(a))+1)
    # circle 1
    x = [np.sin(np.radians(_x))*8 for _x in np.linspace(-180,180,721)]
    y = [np.cos(np.radians(_y))*8*n for _y in np.linspace(-180,180,721)]
    plt.plot(x, y, c)

    # circle 2
    x2 = [i*0.7 for i in x]
    y2 = [i*0.7 for i in y]
    plt.plot(x2, y2, c)

    # line
    x3 = [0,0]
    y3 = [min(y)*1.25,max(y)*1.25]
    plt.plot(x3, y3, c)

    # lines
    x4 = [i*1.2 for i in x]
    y4 = [i*1.2 for i in y]
    for i in range(16):
        x5 = [x[i*45],x4[i*45]]
        y5 = [y[i*45],y4[i*45]]
        plt.plot(x5, y5, c)
    file_name = data_dir + 'tmp_{0:02}.png'.format(a)
    plt.savefig(file_name)

images = []
for a in range(30):
    file_name = data_dir + 'tmp_{0:02}.png'.format(a)
    img = Image.open(file_name)
    images.append(img)

gif_name = 'anzan.gif'
images[0].save(gif_name,save_all=True, append_images=images[1:], optimize=False, duration=2, loop=0)





結果はこうなります。


anzan
びろんびろん動くのが
気持ちいいですよねーーーー


はい
周りのに安産祈願の方がいたら
是非送ってあげましょう!!

きっと喜ばれること
間違いなし




今回はここまでです。

それでは


 

はいどうも今晩は
乙pyです。

本日はまず
Youtube登録者数が
100人を突破いたしましたーーーーーーー

きゃー
うれスィー

こんな底辺YouTuberですが
登録者数1000人、1万人と目指して
今後とも頑張って行きたいと思います。

目標は
日本国民全員が
プログラミングできるようになること
プログラミングたーのしーって
思えるようになることを目指しておりますので
引き続き皆さま動画の方を
よろしくお願いいたします。

動画はこちら




今回は算数チャレンジです。
算数チャレンジとは?
140114nexus7_cm_pazzle


昔GoogleのCMでこんなのが有りましたね。
四つの数字を用いて
組み替えて10になるような計算方法を
考えましょうと言うもの。

1 1 5 8 
これに
+ー*/
で答えを10にしましょう。

・・・

実際これやってみると
意外と大変なものです。


これを自力で解くのは
結構頭を使うので
頭を使わないために
プログラムで解く方法を考えてみましょう(笑)。

まず考えるべきは
プログラムで使う部品です。

4つの数字
+-*/の記号

これだけだと
実は解けないんです。

計算では優先順位があるので
先に足すとかしたい場合は
カッコが必要になります。

このカッコ() を用いることができないと
算数の問題を解けません。

と言うことで
部品を揃えて行きましょう。

言語はPythonを用います。
Python言語では
分数の計算を行うことができる
Fractionと言うライブラリがあります。

これを用いると
通常は1/7など小数点になってしまい
計算が合わなくなってしまうのを
分数扱いできるので
正しく答えを求めることができます。

また、4つの数字は
色々組み替える必要があるので
この組み替えを行うために
itertoolsライブラリを用います。

まずはこの二つをインポートしておきます。
from fractions import Fraction
import itertools

次に
そう考えていくかと言うと
数式を作っていくことを考えます。

1+2+3+4

こんな感じで4つの数字と
記号を三つ組み合わせる式になるはずです。

加えてこれにカッコ()を付け足す形になるので
このかっこのパターンを含めた数式文字列の
パターンを用意してあげます。
pattern = [
    '%s%s%s%s%s%s%s',
    '(%s%s%s)%s%s%s%s',
    '(%s%s%s%s%s)%s%s',
    '%s%s(%s%s%s)%s%s',
    '%s%s(%s%s%s%s%s)',
    '%s%s%s%s(%s%s%s)',
    '(%s%s%s)%s(%s%s%s)'
]
このように
かっこのパターンを用意してあげます。

次に
数式をどう組み立てるかと言うと
このパターンの%sの部分に
数字と記号を当てはめて行きます。

for x, y, z in itertools.product('+-*/',repeat=3)


これで記号の全通りの組み合わせを作ることができます。
itertools.productはその文字数分だけ繰り返しが行われます。
repeat=3なので3文字分の記号の組み合わせを作成します。


QUESTION = '1158

for a, b, c, d in itertools.permutations(QUESTION,4)

文字の部分は
こんな感じになります。
permutationsで数字の順列を作成します。

この7つの文字を
先ほどのパターンに当てはめます。

f = p % (fa, x, fb, y, fc, z, fd)


これでfに数式が当てはまりました。
あとはこれを計算するのですが
この変数fの値は文字列なので
計算はできません。

Pythonでは
文字を数式として評価できる
eval()と言う関数があります。

これを用いると数式として計算ができるので
作成した文字を数式として扱って
計算した結果、10になったら
答えとして、結果を保存します。

結果はsetに格納して重複を排除しました。

プログラムを組み合わせると
こんな感じになります。

from fractions import Fraction
import itertools

pattren = [
'%s%s%s%s%s%s%s',
'(%s%s%s)%s%s%s%s',
'(%s%s%s%s%s)%s%s',
'%s%s(%s%s%s)%s%s',
'%s%s(%s%s%s%s%s)',
'%s%s%s%s(%s%s%s)',
'(%s%s%s)%s(%s%s%s)',
]
QUESTION = '1158'
result_set = set()
for x, y, z in itertools.product('+-*/',repeat=3):
    for a, b, c, d in itertools.permutations(QUESTION,4):
        fa, fb, fc, fd = ['Fraction(%s)' % n for n in [a, b, c, d]]
        for p in pattren:
            f = p % (fa, x, fb, y, fc, z, fd)
            try:
                result = eval(f)
            except ZeroDivisionError:
                continue
            if result == 10.0:
                result_set.add (p % (a, x, b, y, c, z, d))
for s in result_set:
    print(s)

この答えは
動画でご覧くださいませ。

さて
いかがでしょうか?

お子さんがいらっしゃる家庭であれば
宿題でこんな問題を
色々やらされことがあるかもしれませんが

このプログラムであれば
QUESTIONの部分を変えてもらえば
いろんな数字の答えを求めることができます。

是非ご活用ください。


それでは









ピースの角度は30度でおなじみの
美人Youtuberゆきりぬさん

いつも動画みてまーーーす。

今日は
動画の冒頭でいつもやっている
決めポーズ

ピーズの角度が何度なのかを
Pythonプログラムで検証してみました。


解説動画はこちら


さて
まずは角度の元になる画像を用意します。
yukirinu2

この肘の先あたりから
ピースの先端までの角度を
求めたいと思います。

どうやって求めるかというと
rad
2点の座標を決めて
その間の角度を求めるようにします。

コードはこんな感じになりました。
%matplotlib notebook
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import math

def onclick(event):
    tx = 'x=%f, y=%f' % (event.xdata, event.ydata)
    text.set_text(tx)

fig = plt.figure()
ax = fig.add_subplot(111)
im = Image.open("yukikinu1.png")
im_list = np.asarray(im)
plt.imshow(im_list)

text=ax.text(0,0, "", va="bottom", ha="left")
cid = fig.canvas.mpl_connect('button_press_event', onclick)

まず画像を用意してから
このコードを実行すると
jupyter notebook上に画像が表示されます。

あとは画像のピースの部分をクリックしてあげると
スクリーンショット 2019-05-03 16.04.17


このようにx,y座標が表示されます。

あとはこの座標を使って
角度を求めていきます。
x, y = 504,im.height-231
radian = math.atan2(y - 0, x - 0)
print(math.degrees(radian))

ちょっと残念なのは
y座標は上からの数値になってしまっているので
画像の高さから引いてあげます。

肘のあたりを0,0として
ピースの先端を504,画像の高さ-231とした際に
math.atan2(y - 0 , x - 0)で
ラジアンが求められるので
それをmath.degrees(ラジアン)
で角度に変換すると・・・

だいたい36度になりました。
四捨五入して40度くらいですね

ということで
ピースの角度は40度でした!!!!

このようにPythonプログラムを使うと
2点を使った角度が簡単に求められます。

プログラミングを覚えていない方は
ぜひ参考にしてみてください。

それでは

このページのトップヘ