TechTrainを使ってみた

今まで自分のためにつらつらブログを書いていたのですが, 初めてちょっと発信する感じで書いてみようと思います。といっても文才はないです。 最近, 僕はある会社の社員になりました。まさか来年就職するのに今年に2社目に入社すると思っていなかったです。というのも, その会社はいとこが1人で切り盛りしているデザインの会社で, そのいとこからwebプラットフォームを作るにはどうすればいいのか相談されました。そこで, 相談に乗っているうちに自分で作っちゃおっかなと思って, 給料をもらわずステータスだけもらって社員になりました。最近いとこと接点がなかったので, 思わぬ形で一緒に仕事ができていて楽しいです。 サービスの内容は明かせませんが, ココナラhttps://coconala.com/というフリマのサービスから改良に改良を重ねたサービスを作ることになりました。そこで迷うのが何で作ればいいのかという問題です。僕の経歴はあらゆるプログラミング言語に浮気し続けているので, 何が得意という訳でもありません。浮気はよくないといろんな人に言われるのですが, 心からお付き合いしたい人が見つかりません。 強いて言えばrubyのルールがカチッとした感じがタイプです。日本人が日本語喋れる感じで日本人エンジニアは日本人が生み出した言語を喋れなあかんかなという義務感もあります。ただ, rubyでAPI開発をしたことがあるのですがこれまた大変なんです。厳密なデータ設計をする必要がありますし, APIとは別にフロントも開発する必要があります。 そこで, React, Redux + Firebase というチャラい感じの設計の方が, 1人で開発する際には合っているのではないかと考えました。Firebaseがバックを担ってくれてブラウザ上からぽちぽちと設定するだけで認証の仕組みなんかが簡単に導入できます。Reactは単なる浮気の延長というのもあるのですが(触ったことないし), このサービスには通話機能が欲しいので, この本がjavascriptで書かれている点からReactありなんじゃないかという発想もありました。 この点を相談するためにTechTrainというサービスを使ってみました。このサービスはおざまささんという元京大出身の方が立ち上げた, 社会人ITエンジニアと無料でオンライン面談できるサービスです。約35社70名のエンジニアメンターをおざまささんがかき集めたそうです。いとこといいおざまささんといい, 自分がやりたいことのために会社を立ち上げていて本当に尊敬します。 僕はこのサービスを広めるために少しお手伝いさせていただいていて, この記事も少し宣伝口調になっていてすみません。。。といっても, 現役のエンジニアの方を独占しての無料でお話できるなど恐れ多い話で, メリットしかないサービスだと思います。 今回は, フリーランスでお仕事をされている八幡さんというインフラエンジニアの方と面談させていただきました。設計の相談もしたかったので, フロントの方やバックの方でもよかったのですが, 敢えていままでお話ししたことのないインフラの方とお話ししてみたいと思い選びました。 結果として, 非常に有意義なお話をさせていただきました。まずサービスの設計については通話サービスを作ること自体だいぶ手間がかかる(過去に少し作られていた)ので外部のAPIなどを利用したほうがいいという意見をいただいたり, Firebaseを使う点には賛成の意見をいただき方向性に自信がもてたりしました。そのほかにもOracleで働かれていた時の話や, フリーランスとしてのエンジニアの働き方の話なんかもできて, とても楽しかったです。 今現在自分は大学にいて, 情報学研究科にいるので直接相談できる人がたくさんいるので簡単な質問では使おうとはならないですが, 高校生だったり他学科の人だと利用したくなるサービスなのかなと思いました。また, キャリアなどの現役ITエンジニアならではの知見が欲しい点に関しては, プロエンジニアを目指す人は大いに活用できると思います。是非使ってみてください! TechTrainの他にもHachBowlというハッカソンのイベントもやっているそうなので、興味のある方は是非!

August 7, 2019 · 1 min

汎用性のあるシミュレータ

最近, cloudnetという学会に論文を投稿したのだが, そこでデータを集める際に制作したシミュレータがいい感じにできたのでそれについて書いてみる。 https://github.com/adshidtadka/server-allocation Parameterクラス まず良かった点としてParameter クラスを作ったことである。 import numpy as np import pandas as pd import itertools import sys import Constant class Parameter: USER_NUM_CONST = 500 SERVER_NUM_CONST = 10 CAPACITY_CONST = 50 def __init__(self, seed): np.random.seed(seed) self.USER_NUM = 500 self.SERVER_NUM = 10 self.DELAY_MAX = 10 self.DELAY_SERVER = 1 self.CAPACITY = 50 def create_input(self): # inputs self.e_u = list(itertools.product(range(self.USER_NUM), range(self.SERVER_NUM))) self.e_s = list(itertools.combinations(list(range(0, self.SERVER_NUM)), 2)) self.d_us = np.random.randint(1, self.DELAY_MAX, (self.USER_NUM, self.SERVER_NUM)) self.m_s = np.full(self.SERVER_NUM, self.CAPACITY) def set_param(self, var_name, consts, var): if var_name == 'user': self.USER_NUM = var self.SERVER_NUM = consts['server'] self.CAPACITY = consts['capacity'] elif var_name == 'server': self.USER_NUM = consts['user'] self.SERVER_NUM = var self.CAPACITY = consts['capacity'] elif var_name == 'capacity': self.USER_NUM = consts['user'] self.SERVER_NUM = consts['server'] self.CAPACITY = var else: sys.exit('invalid var_name = ' + str(var_name)) def get_const(var_name): if var_name == 'user': return Parameter.USER_NUM_CONST elif var_name == 'server': return Parameter.SERVER_NUM_CONST elif var_name == 'capacity': return Parameter.CAPACITY_CONST else: sys.exit('invalid var_name = ' + str(var_name)) これを作ることで1つのインスタンスが1つのパラメータに対応することになるので, 全部グローバル変数で書いていた前回のシミュレータよりめちゃめちゃわかりやすくなった。また, インスタンスメソッドを呼び出してパラ調整がしやすく, メソッドとしてパッケージ化することでエラーを極力避けれるようになった。 IlpクラスとMmdクラス class Ilp: def __init__(self, param): self.create_dataframe(param) self.set_input() def set_input(self): # optimization problem problem = LpProblem() # decision variables self.df_e_u['variable'] = [LpVariable('x_us%d' % i, cat=LpBinary) for i in self.df_e_u.index] self.df_e_s['variable'] = [LpVariable('x_st%d' % i, cat=LpBinary) for i in self.df_e_s.index] self.df_v_s['variable'] = [LpVariable('y%d' % i, cat=LpBinary) for i in self.df_v_s.index] self.D_u = LpVariable('D_u', cat=LpInteger) self.D_s = LpVariable('D_s', cat=LpInteger) # objective function problem += 2 * self.D_u + self.D_s self.problem = problem def create_dataframe(self, param): # dataframe for E_U df_e_u = pd.DataFrame([(i, j) for i, j in param.e_u], columns=['user', 'server']) df_e_u['delay'] = param.d_us.flatten() self.df_e_u = df_e_u # dataframe for E_S df_e_s = pd.DataFrame([(i, j) for i, j in param.e_s], columns=['server_1', 'server_2']) df_e_s['delay'] = param.DELAY_SERVER self.df_e_s = df_e_s # dataframe for V_S df_v_s = pd.DataFrame(list(range(0, param.SERVER_NUM)), columns=['server']) df_v_s['capacity'] = param.m_s self.df_v_s = df_v_s def solve_by_ilp(self, solver=None): t_0 = time.perf_counter() # solve try: # constraints self.problem = self.create_constraints(self.problem) if solver == 'cplex': self.problem.solve(GLPK_CMD(msg=0)) else: self.problem.solve(CPLEX_CMD(msg=0)) except PulpSolverError: print(CPLEX_CMD().path, 'is not installed') t_1 = time.perf_counter() return t_1 - t_0 def print_result(self): if self.problem.status == 1: print('objective function is ', value(self.problem.objective)) print('cpu time is ' + str(self.cpu_time) + ' sec') else: print('status code is ', self.problem.status) def create_constraints(self, m): # constraints # (1b) for k, v in self.df_e_u.groupby('user'): m += lpSum(v.variable) == 1 # (1c) for k, v in self.df_e_u.groupby('server'): m += lpSum(v.variable) <= self.df_v_s['capacity'][k] # (1d) for k, v in self.df_e_u.iterrows(): m += v.variable * v.delay <= self.D_u # (1e) for k, v in self.df_e_s.iterrows(): m += v.variable * v.delay <= self.D_s # (1f) for k, v in self.df_e_u.groupby('user'): for l, w in self.df_v_s.iterrows(): m += w.variable >= v.variable # (1g) for k, v in self.df_e_s.iterrows(): m += self.df_v_s.iloc[v.server_1].variable + \ self.df_v_s.iloc[v.server_2].variable - 1 <= v.variable # (1h) for k, v in self.df_e_s.iterrows(): m += v.variable <= self.df_v_s.iloc[v.server_1].variable # (1i) for k, v in self.df_e_s.iterrows(): m += v.variable <= self.df_v_s.iloc[v.server_2].variable return m class Mmd: def __init__(self, param): self.set_input(param) def set_input(self, param): # edges list edges = np.empty(3, dtype=int) for k, v in enumerate(param.d_us): for i, j in enumerate(v): edges = np.vstack((edges, np.array([k, i, j]))) self.edges = edges def start_algorithm(self, param): t_0 = time.perf_counter() L_1 = self.one_server_case(param) L_2 = self.multiple_server_case(param) D_u = min([L_1, L_2]) if D_u > param.DELAY_MAX: self.status = False else: self.status = True self.objective_function = D_u * 2 + param.DELAY_SERVER t_1 = time.perf_counter() return t_1 - t_0 def one_server_case(self, param): # step 1: consider one server case # allocate all user and get L_1 dic_l = dict() for k, v in enumerate(param.m_s): if v >= param.USER_NUM: D_u = param.d_us[:, k].max() dic_l[k] = D_u # search minimum D_u if bool(dic_l): return min(dic_l.values()) else: return Constant.INF def multiple_server_case(self, param): # step 2: consider multiple server case # initialize the bipartite graph added_server = param.SERVER_NUM for k, v in enumerate(param.m_s): for j in range(param.USER_NUM): delay = param.d_us[j][k] for i in range(added_server, added_server + v - 1): self.edges = np.vstack((self.edges, np.array([j, i, delay]))) added_server += v - 1 param.COPY_SERVER_NUM = added_server # search matching for i in range(1, param.DELAY_MAX): hc = HopcroftKarp(param.USER_NUM, param.COPY_SERVER_NUM) for j in np.where(self.edges[:, -1] <= i)[0]: hc.add_edge(self.edges[j][0], self.edges[j][1]) if hc.flow() == param.USER_NUM: return i return Constant.INF def print_result(self): if self.status: print('objective function is ', str(self.objective_function)) print('cpu time is ' + str(self.cpu_time) + ' sec') else: print('Error') inputを入れればoutputが出るツールとして2つのクラスを作った。これにさっき定義したParameterをそのままいれればいいので, ブラックボックスとして扱える。set_inputなんかのメソッドを共通化してもよかった。また Ilp ではPulpを使ってソルバを簡単に切り替えられるようにした。 ...

July 17, 2019 · 5 min

texでeps画像を表示させたい

論文を投稿するときに, epsの表示周りでめちゃめちゃエラーがでていたときに, ドライバオプションの設定でうまくビルドできた. それを最近忘れていて時間食ったので, 備忘録として残しておく. 詳しくは この方 がまとめてくれている. epsを表示する \usepackage[dvips]{graphicx} と, dvips をドライバで指定する. pdf, jpg, pngを表示する \usepackage[dvipdfmx]{graphicx} と, dvipdfmx をドライバで指定する. 感想 texの設定は理解しにくいので備忘録をこまめに書いていきたい.

June 19, 2019 · 1 min

正規表現チートシート

udemyの教材で正規表現の勉強をした。いままでなんとなく書いていたたが, これからはなんでもかける気がする… 基本的な記号 = 文字または数字を1文字分指定する ^(キャロット) = 直後の文字または数字を指定しない -(ハイフン) = 文字数字の範囲を指定する (バックスラッシュ) = 直後のメタ文字を単なる文字として扱う . (ワイルドカード) = なんでもよし |(パイプ) = 左右のどちらかにマッチするか判定する ()(丸かっこ) = 正規表現をグループ化する 数量詞 繰り返したいパターンの直後におく +(プラス) = 1回以上の繰り返し *(アスタリスク) = 0回以上の繰り返し ?(クエスチョンマーク) = 入力なしか1文字のみ {n} = n回の繰り返し {n, } = n回以上の繰り返し {n, m} = n回以上, m回以下の繰り返し 一致方法 最長一致(デフォルト) 最短一致 ?を数量詞の最後につける 区切り ^ = カバーする範囲の先頭を行頭に指定 $ = カバーする範囲の最後を行末に指定 \b = スペースや改行による単語の区切り 前後につけて単語を見つける \B = \b以外の区切り 単語の中の文字列を見つける 1文字のメタ文字では機能が逆になる ショートコード [0-9] = \d [^0-9] = \D [a-zA-Z0-9_] = \w [^a-zA-Z0-9_] = \W \n = 改行 \t = タブ \r = リターン \f = 改ページ [\n\t\r\f ] = \s [^\n\t\r\f ] = \S 修飾子 g(global) = マッチする結果すべてを抽出 i(case-insensitive) = 大文字と小文字を区別しない m(multiline) = ^と$の挙動を変え, 複数行を対象にする 日本語 ひらがな [ぁ-ん] [\u3041-\u3096] [\x{3041}-\x{3096}] カタカナ [ァ-ヶ] [\u30A1-\u30FA] [\x{30A1}-\x{30FA}] 漢字 [亜-煕] [々〇〻\u3400-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF] [々〇〻\x{3400}-\x{9FFF}\x{F900}-\x{FAFF}]|[\x{D840}-\x{D87F}][\x{DC00}-\x{DFFF}] 半角文字以外 [^\x01-\x7E] 応用 フリーダイヤル /0120-((\d{2}-\d{4})|(\d{3}-\d{3}))/ 市街局番 /\d{2, 4}-\d{2, 4}-\d{4}/ 携帯番号 /(090|080|070)-\d{4}-\d{4}/ URL /http[s]?://[\w/%&$#?()=~+-]+/ メールアドレス /[\w-]+@([/w-]+.)+[a-zA-Z]{2, } 感想 とりあえず正規表現が使えそうだったらこのページを参考に書いてみようと思う. ...

June 5, 2019 · 1 min

kaggle勉強会 | @KDL

先週, 神戸デジタルラボにお邪魔してkaggleの勉強会に参加してきました。研究室の先輩の稲垣さんに講義してもらった。そこでの講義資料がこちら。 u++さんという有名な人のQiitaに従って解説してもらった。kaggleは何回か参加したことがあるが, 改めて勉強になった。

June 5, 2019 · 1 min

第5回CTF勉強会 | ksnctf

seccon beginners ctf前の最後の勉強会. 今回はアルゴリズムに関する問題が多かった. Math I RSAの公開鍵暗号に関する問題. ちなみに、 RSA暗号とは、桁数が大きい合成数の素因数分解問題が困難であることを安全性の根拠とした公開鍵暗号の一つである。 c(暗号文)とm(平文)は以下のようにして求める. c = m^e mod n m = c^d mod n よってdさえ求まれば復号できる. dを求める式は以下の通り. d = e^(-1)(mod(p-1)(q-1)) dを求めるには, n = pqを求める p-1とq-1の最大公倍数lcm(p-1, q-1) = (p-1)(q-1)/gcd(p-1)(q-1)を求める ed≡1(mod L)となるようなedの組みを求める 拡張ユークリッドの互除法が使われている. このサイトを参考にして実装した. import math e = 65537 n = 1517330236262917595314610888889322115651087080826711948897066340883208205571592392362650858571076247939805436226544833224526137582834770402681005343930059463684528957271778199162575053306238099823295117697031968370690372250916935800738698142103275969223264184374648246277564306900886005299731265812255274723175925185522344831066577166867786835955092059346244885587228196357297758371381557924676260190209536670230008561217008649261974735505203813478978893582292682827884118215872470401293272325715864815977064075988643101088355047954735427424641386870772845440782632933485165110172437511822736907550777817722248753671107339823410418938404382732079381329288400012929311347390423061254658780185245562668131009832293474920208834795460061115101364091252176594144096675899952570380792978037217747311595899301451192342027799533264325948876556110474850761538179748318187805312451895898751337975457949549497666542175077894987697085521882531938339334715190663665300179658557458036053188152532948734992896239950564081581184284728802682982779186068791931259198917308153082917381616147108543673346682338045309449569430550618884202465809290850964525390539782080230737593560891353558335337408957948041667929154230334506735825418239563481028126435029 c = 225549592628492616152632265482125315868911125659971085929712296366214355608049224179339757637982541542745010822022226409126123627804953064072055667012172681551500780763483172914389813057444669314726404135978565446282309019729994976815925850916487257699707478206132474710963752590399332920672607440793116387051071191919835316845827838287954541558777355864714782464299278036910958484272003656702623646042688124964364376687297742060363382322519436200343894901785951095760714894439233966409337996138592489997024933882003852590408577812535049335652212448474376457015077047529818315877549614859586475504070051201054704954654093482056493092930700787890579346065916834434739980791402216175555075896066616519150164831990626727591876115821219941268309678240872298029611746575376322733311657394502859852213595389607239431585120943268774679785316133478171225719729917877009624611286702010936951705160870997184123775488592130586606070277173392647225589257616518666852404878425355285270687131724258281902727717116041282358028398978152480549468694659695121115046850718180640407034795656480263573773381753855724693739080045739160297875306923958599742379878734638341856117533253251168244471273520476474579680250862738227337561115160603373096699944163 p = 34111525225922333955113751419357677129436029651245533697825114748126342624744832960936498161825269430327019858323450578875242014583535842110912370431931233957939950911741013017595977471949767235426490850284286661592357779825212265055931705799916913817655743434497422993498931394618832741336247426815710164342599150990608143637331068220244525541794855651643135012846039439355101027994945120698530177329829213208761057392236875366458197098507252851244132455996468628957560178868724310000317011912994632328371761486669358065577269198065792981537378448324923622959249447066754504943097391628716371245206444816309511381323 q = 44481453884385518268018625442920628989497457642625668259648790876723318635861137128631112417617317160816537010595885992856520476731882382742220627466006460645416066646852266992087386855491152795237153901319521506429873434336969666536995399866125781057768075533560120399184566956433129854995464893265403724034960689938351450709950699740508459206785093693277541785285699733873530541918483842122691276322286810422297015782658645129421043160749040846216892671031156465364652681036828461619272427318758098538927727392459501761203842363017121432657534770898181975532066012149902177196510416802134121754859407938165610800223 # step1 L = (p-1)*(q-1)//math.gcd(p-1, q-1) # step2 def ex_euclid(x, y): c0, c1 = x, y a0, a1 = 1, 0 b0, b1 = 0, 1 while c1 != 0: m = c0 % c1 q = c0 // c1 c0, c1 = c1, m a0, a1 = a1, (a0 - q * a1) b0, b1 = b1, (b0 - q * b1) return a0 d = ex_euclid(e, L) # step3 m = pow(c,d,n) print ("%0512x"%m).decode("hex") Math II モジュロ演算という割り算の余りを求める計算と関わっている. xの101乗根を普通に求めようとしてもオーバーフローが起きてしまうので, 二分探索を実装する. このサイトを参考にした. ...

May 29, 2019 · 2 min

蟻本 | 2-7 GCJの問題に挑戦してみよう(1)

今まで学んだことを生かして4問解いてみた. 答えと全然違う実装をしたくないので, 問題を読んで実装の流れを考えたら答えをみるという流れでやってみた. Minimum Scalar Product (2008 Round1A A) 2つのベクトル成分を自由に入れ替えて内積を最小にする問題. 最初は数の正負を考えて, 正の数で絶対値が大きいものには負の数で絶対値が大きいものと積を取るようにみたいなことを考えていたが, シンプルに2つの成分を順と逆順でソートすればよかった. const int MAX_N = 800; typedef long long ll; int n; int v1[MAX_N], v2[MAX_N]; void solve() { sort(v1, v1 + n); sort(v2, v2 + n); ll ans = 0; for (int i = 0; i < n; i++) { ans += (ll)v1[i] * (ll)v2[n - i - 1]; } printf("%lld\n", ans); } ```cpp ### Crazy Rows (2009 Round2 A) 行をバブルソートする問題. 行列が与えられて下三角行列がどうとか難しい話をしているが案外簡単で, 上から順に行を埋めていくことを考える. 動かす行は上の行にすることで, 動かす操作数を最小化する. 実装のポイントとしては`a[i]: i行目の最後に現れる1の位置-1 ~ N-1`を定義することで行列より扱いやすくしている. また, 配列の要素を入れ替える`swap`をうまく使って再帰的な処理を実現している. ```cpp void solve() { int res = 0; // 配列にする for (int i = 0; i < N; i++) { a[i] = -1; for (int j = 0; j < N; j++) { if (M[i][j] == 1) { a[i] = j; } } } for (int i = 0; i < N; i++) { int pos = -1; // i + 1行目に移動する行番号 for (int j = i; j < N; j++) { if (a[j] <= i) { pos = j; break; } } // 実際にスワップ for (int j = pos; j > i; j--) { swap(a[j], a[j - 1]); res++; } } printf("%d\n", res); } ```cpp ### Bribe the Prisoners (2009 Round 1C C) 囚人の問題. 普通に問題として面白かった. アルゴリズムのポイントとしては, 空き部屋の概念と端の概念を一緒にしていかに再帰を実現するか. 実装のポイントとしては, 動的計画法を用いるために`dp[MAX_Q + 1][MAX_Q + 2]: (i, j)を解放するのに必要な金貨`を定義して使うところ. dpがどういう動きをするのかが最初わかりにくいので具体的な例でdpテーブルを埋める作業をしてみる. 幅が小さい順に調べるモチベーションがわかる. ```cpp const int MAX_Q = 100; int P, Q, A[MAX_Q + 2]; // (i, j)を解放するのに必要な金貨 int dp[MAX_Q + 1][MAX_Q + 2]; void solve() { // 簡単のため端をAに追加する A[0] = 0; A[Q + 1] = P + 1; // 初期化 for (int q = 0; q <= Q; q++) { dp[q][q + 1] = 0; } // 幅が小さい順にdpを埋めていく for (int w = 2; w <= Q + 1; w++) { for (int i = 0; i + w <= Q + 1; i++) { int j = i + w; int t = INT_MAX; // 最初に解放する囚人を全て試し最小コストのものを探す for (int k = i + 1; k < j; k++) { t = min(t, dp[i][k] + dp[k][j]); } // 最初の解放では解放する囚人にかかわらずA[j] - A[i] - 2の金貨が必要 dp[i][j] = t + A[j] - A[i] - 2; } } printf("%d\n", dp[0][Q + 1]); } ```cpp ### Millionaire (2008 APAC local onsites C) お金の掛け方が整数に限られていないので, 全探索ができない. ここで, ラウンドが1回しかなかった場合, 金額によって0%, P%, 100%の3つの確率に分けられることに気づく. さらに2ラウンドの場合は, 5つの確率に分けられる. この考えかたを動的計画法で実装する. 実装のポイントとしては, iラウンド目の確率はi-1ラウンド目の確率をもとに計算するので, 2つの配列`prv`と`nxt`を用意してうまく使うところにある. i-1ラウンド目の状態から正解・不正解する場合を確率の独立性を生かして考える. ```cpp typedef long long ll; const int MAX_M = 15; int M, X; double P; double dp[2][(1 << MAX_M) + 1]; void solve() { // n = 2^M int n = 1 << M; double \*prv = dp[0], \*nxt = dp[1]; memset(prv, 0, sizeof(double) * (n + 1)); // 既に100万円持っていれば確率1 prv[n] = 1.0; for (int r = 0; r < M; r++) { for (int i = 0; i <= n; i++) { int jub = min(i, n - i); double t = 0.0; for (int j = 0; j <= jub; j++) { t = max(t, P * prv[i + j] + (1 - P) * prv[i - j]); } nxt[i] = t; } swap(prv, nxt); } // 全勝した場合の金額 / 100万円 int i = (ll)X * n / 1000000; printf("%.6f\n", prv[i]); } ```cpp ### 感想 アルゴリズムに落とし込むところは発想力, そのあとの実装は再帰などをどう実現するかの数学力が必要なのではないかと思った.

May 21, 2019 · 3 min

第4回CTF勉強会 | ksnctf

今日は4人しかこなかった… 火曜の8:45からってのがきつすぎるんかな… 31 Kangacha PHPで書かれた簡単なwebアプリケーションの問題. Gachaというボタンを押せば日本の戦艦の名前がランダムでリストに追加されていく. ソースコードも与えられているので読んでいく. if (isset($_POST['submit'])) { // Gacha if ($_POST['submit'] === 'Gacha') { // Yamato is ultra rare $ship[] = mt_rand(0, count($shipname)-2); $s = implode(',', $ship); $sign = hash('sha512', $salt.$s); setcookie('ship', $s); setcookie('signature', $sign); } // Clear if ($_POST['submit'] === 'Clear') { setcookie('ship', '', 0); setcookie('signature', '', 0); } header("Location: {$_SERVER['REQUEST_URI']}"); exit(); } このソースから, $_COOKIE['ship']に戦艦の番号の配列が, $_COOKIE['signature']にあらかじめ決められた$saltと戦艦番号のハッシュ値が格納される. // Check signature and read if (isset($_COOKIE['ship']) and isset($_COOKIE['signature']) and hash('sha512', $salt.$_COOKIE['ship']) === $_COOKIE['signature']) $ship = explode(',', $_COOKIE['ship']); else $ship = array(); ここで$_COOKIE['signature']のバリデーションを確認され, 不正であれば配列の中身が空になってしまう. ...

May 17, 2019 · 3 min

蟻本 | 2-6 数学的な問題を解くコツ

ユークリッドの互除法やエラストテネスの篩, 繰り返し二乗法の計算を勉強した. 線分上の格子点の個数 最大公約数-1がこの問題の解となる. ユークリッドの互除法を元にgcdを実装. #include <iostream> #include <vector> using namespace std; int x_1, x_2, y_1, y_2; int gcd(int a, int b) { if (b == 0) { return a; } else { return gcd(b, a % b); } } int main(int argc, char const *argv[]) { cin >> x_1 >> y_1 >> x_2 >> y_2; int x_diff = abs(x_1 - x_2); int y_diff = abs(y_1 - y_2); cout << gcd(x_diff, y_diff) - 1 << endl; return 0; } ```cpp ### 双六 ユークリッドの互除法を拡張する. `ax+by=1`を満たす整数`x, y`を探すには以下のようなスクリプトを書く. ```cpp int extgcd(int a, int b, int& x, int& y) { int d = a; if (b != 0) { d = extgcd(b, a % b, y, x); y -= (a / b) * x; } else { x = 1; y = 0; } return d; } ```cpp ### 素数判定 素数かどうかは`2 ~ √n`までを調べればよい. ```cpp // 素数判定 bool is_prime(int n) { for (int i = 2; i * i <= n; i++) { if (n % i == 0) return false; } return true; } // 約数の列挙 vector<int> divisor(int n) { vector<int> res; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res.push_back(i); if (i != n / i) { res.push_back(n / i); } } } return res; } // 素因数分解 map<int, int> prime_factor(int n) { map<int, int> res; for (int i = 2; i * i <= n; i++) { while (n % i == 0) { ++res[i]; n /= i; } } if (n != 1) { res[n] = 1; } return res; } ```cpp ### 素数の個数 エラストテネスの篩と呼ばれるアルゴリズムを使って数える. 最小の素数の倍数をどんどん省いていく. ```cpp int sieve(int n) { int p = 0; for (int i = 0; i <= n; i++) { is_prime[i] = true; } is_prime[0] = is_prime[1] = false; for (int i = 2; i <= n; i++) { if (is_prime[i]) { prime[p++] = i; for (int j = 2 * i; j <= n; j += i) { is_prime[j] = false; } } } return p; } ```cpp ### 区間内の素数の個数 篩を2つ用いることで, 特定の区間の素数の個数を調べることができる. 区間`[a, b)`を調べる場合は, `[2, √b)`と`[a, b)`の篩を別々に作っておく. ```cpp const int MAX_N = 100000000; const int MAX_SORT_B = 100000000; typedef long long ll; bool is_prime[MAX_N]; bool is_prime_small[MAX_SORT_B]; int a, b; void segment_sieve(ll a, ll b) { for (int i = 0; (ll)i * i < b; i++) { is_prime_small[i] = true; } for (int i = 0; i < b - a; i++) { is_prime[i] = true; } for (int i = 2; (ll)i * i < b; i++) { if (is_prime_small[i]) { for (int j = 2 * i; (ll)j * j < b; j += i) { is_prime_small[j] = false; } for (ll j = max(2LL, (a + i - 1) / i) * i; j < b; j += i) { is_prime[j - a] = false; } } } } ```cpp ### Carmichael_Numbers 繰り返し二乗法を用いてべき乗を計算する. 基本的な考え方としては`x^22 = x^16 * x^4 * x^2`のようにx^2^i を順次求めながら計算する. ```cpp ll mod_pow(ll x, ll n, ll mod) { ll res = 1; while (n > 0) { if (n & 1) { res = res * x % mod; } x = x * x % mod; n >>= 1; } return res; } ```cpp ## 感想 最後のビット計算をうまく使う実装は自分でできる気がしない…

May 12, 2019 · 3 min

swiftの画像キャッシュライブラリ

iOSアプリケーションにて画像を表示する際, URLから非同期でデータを取得してUIImage化するという処理がなされていて, それを簡単に書けるライブラリを紹介する. ここでは, 以下の2つのサイトを参考にした. iOSアプリを作るときのおすすめ構成 Swiftの有名画像キャッシュライブラリを比較してみた 3種類のライブラリ 今回3つのライブラリに着目した. Nuke Kingfisher AlamofireImage 結論として, Nukeが一番流行ってて処理速度も早かった. 処理速度に関しては以下のチュートリアルを使って, 3つのライブラリ全て使ってみた. Nuke Tutorial for iOS: Getting Started 他のライブラリに関しては, KingfisherがObject-Cの時代のSDWebImageの流れを組んでいてドキュメントが多いのと, AlamofireImageは画像描画のアニメーションが豊富な点がいいのかなと思いました。 感想 普段ライブラリなんかはググって適当に使ってしまうが, こうして比較検討することはあとの変更コストをなくすために大事な作業だと思った.

May 11, 2019 · 1 min