スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

雑草抜き

 某文芸サイトのね。サンドボックスというユーザが下書きを公開してみんなに批評もらうサイトのver.3作ってるんです。ノウハウは溜まったから時間ができたら何か書きます。

 今回は広告を消す為だけの記事ですね。
スポンサーサイト

オリジナルBrainfuck生成スクリプト

参考: 脳姦する機械

 オリジナルのBF生成スクリプトを作りました。

 さて、自分が活動しているサイトはSimeji_Daliしか知らない人には隠したい。でもライセンスはあっち名義で表記した。さて、どうしようか。

 うーん。某文芸サイトで「奇声」ってスレッド探してください。

 これは例えば「Kemono」等を簡単に作れます。
入力
出力 Pointer:
ReadPoint:
サンプルコード

 ちなみに上のインタプリタにあるコマンド表出力、BrainfuckからBrainfuck亜種への変換、Brainfuck亜種からBrainfuckへの変換は全てこのオリジナルBrainfuckの作成起動ライブラリに備わっている機能です。

テーマ:プログラミング - ジャンル:コンピュータ

書きかけの謎

何かの書きかけです 必要なものを内側に……外出しされたメソッドを介して操作。メソッド内では変数の型チェック。硬いコードにして汎用性を持たせる。
 定数はconstを使いたいが、constはブラウザがサポートしていないとシンタックスエラーになるのでObject.freeze()で、Object.freezeはObjectそのものを上書きする事が可能だが……まぁそれは意図しないとできないと思う。

続きを読む »

テーマ:プログラミング - ジャンル:コンピュータ

航空中の飛行機のメンテナンス

 IT企業というものを説明する動画で、空を飛んでいる飛行機に作業員数人がまたがり、飛行中の飛行機に対してメンテナンス作業をおこなうというものを見た事があります。私もそれを少し味わってます。作業をする側でね。

 今回、飛行機の搭乗客の視点から正にこの「飛行中の飛行機におけるメンテナンス」を味わったので、まぁまだ「おいしい話」にはなってないけど、ちょっとね。報告します。
エビデンス
上記の画像はニコニコ動画というサイトのニコポイントというサービスの購入履歴です。このニコポイントは「1ポイント=1円」で購入でき、このニコポイントを使ってサイト内の有料コンテンツを購入する事ができます。

 9000円もよく買ったねと思うでしょう。でもこの話の流れ、そして同日にきっちり1分置きに購入している事からわかるでしょう。買ってないんです。私は。そもそも、購入手続きでは認証とかが必要ですしこんな購入の仕方面倒ですよね?

 なんなんでしょうね。最初はメンテナンスした後の手作業によるテストでテスト用アカウントと間違えて私のアカウントに購入テストをやったのだと思っていました。ただ正確に1分置きだから何かプログラムが走ったと見た方が良いんですよね?
 時間的にメンテナンスしていた時間だと思うんです。テスト用のプログラムにバグなんでしょうかね?

 決済報告のメールは届いていないので、請求されないだろうと思うのですが(購入のエビデンスがないし)、ただこのままにしておくと何が起きるかわからないのでサポートに問い合わせました。

 予想できる結末は3つです。

1.約9000円請求される
2.今回の9253ポイントが引かれる
3.このままポイントをくれる

1番はまぁないでしょう。起きたらもう発狂します。SNSで拡散しまくるぐらい発狂します。

2番はわかるっちゃわかるが気分が悪いです。多くの企業はこうするでしょう。「気付かずにもともと持っていたポイント以上を使ったらどうなるの?」となると、法的に詐欺罪にあたるかも知れないですね……法は詳しくなく、「コンビニでお釣りを多くもらい、その事に気づきながら黙った場合詐欺罪にあたる可能性がある」とかテレビで聞いた事あるなぁぐらいのやつ。でもこの少額で訴えるとなるとそっちの費用の方がかかるでしょう。

3番はラッキーな対応です。ただ2番の時にあげた「気付かずにもともと持っていたポイント以上を使ったらどうなるの?」という話と合わせると、3番の対応が筋は通ってますけどね。2番対応になったら、まぁ「正直者はバカを見る時代に正直に言った俺がバカだった」って話でしょう。

私の個人的環境故、2番でも気分が悪いですが、こうしてメンテナンス時のエラーを身をもって味わえたのはそれなりにおいしいですが……あーでも想像するだけで気分悪くなるなぁ。

ITのお仕事というものは飛行中の飛行機にメンテナンスをするような作業が度々ある。その為このような事が起きても「まぁね」と思うけどこれは金がかかわりますからね。心理学的にも道端で拾った1万円を落としただけで、そう実際はプラスマイナス0であるにも関わらず1万損したと感じますからね。どうなるんだろうな。流石に1番はないよなぁ。2番だったらまたこのブログで愚痴って、3番だったら、ちょっと今某文芸サイトで使えるシステムで新しいアイデアが浮かんでいるので、それがある程度進んだ時、それを紹介して、その記事の中で顛末を話しましょう。
 人はポジティブな事よりネガティブな事の方をよく発信する。本当だなぁ。1番だったらブログ、SNSで発狂モードに入って2番だとブログでグチって、3番だと機会があったら喋るだもんなぁ……まぁ自分に嫌な思いをさせたものに対するネガティブな情報は、誰かに共有してもらう事だけで復讐の1つにはなりますからね。小さいけど。

 2番も3番と同じぐらいにしよう。機会があったら喋るレベル。1番はやばい。実際に金銭的被害を受けているし、誰かに相談して、何か動かないと……。

 ごめん。取り繕ったけど単純に不安な気持ちからこの記事書いてました。

テーマ:(´Д`;) - ジャンル:日記

剰余とランダム性について

  以前、私は人にプログラムを教えていると伝えました。結論としては最終講義で間違えた事を教えました。この記事は自己反省会及び、訂正講義用資料です。

 私が教えていたプログラムとはあるテーブルトークゲームのゲームマスターを行うものです。仕様は下記になります。
ゲームの構成要素
プレイヤーの役割:
 参加人数N人に対し
  村人 N-1 人、狼 1人
各プレイヤーは自身の役割を知らない

プレイヤーの行動: そのゲームごとに2つのお題(AとBとする)が用意される。村人はAのお題で、狼はBのお題で談笑を行う。この時各プレイヤーはお題そのもの(例えばAのお題が「おにぎり」であるならば、村人は談笑中「おにぎり」と言ってはいけない)を言ってはいけない

ゲームの目的: 談笑の中でただ1人違うお題で会話をおこなう狼を発見する。ただし、このゲームでは上述の通り、狼自身も自分が狼である事は知らないので、自分自身も推理対象となる
プログラムの仕様
全体概要
クライアントのみで制御を行う(サーバお金かかるし)
機能は大別して「お題表示機能」「狼判定機能」「回答表示機能」の3つがある
上述の3つの機能に数字を付ける。
1.「お題表示」
2.「狼判定」
3.「回答表示」
これらはそれぞれ自身より若い番号の機能が起動された後に使用可能になる。具体例で言えばプログラム起動時は「お題表示機能」のみが使用可能であり、「お題表示機能」を動かした後に「狼判定機能」が使用可能になる。
お題表示機能
ユーザはシード値(その回のゲームのお題や人狼を決定する為に使う数字)、参加人数、自身のプレイヤー番号を入力する
お題ボタンを押すと、プログラムは上述のゲームのルールで話したAかBのお題のみを出力する。ただし、プレイヤーに結果を出力していないだけでこの時点で狼番号(狼となるプレイヤー番号)や残りのお題も決定している
狼判定機能
ユーザは判定対象のプレイヤー番号を入力し、狼判定ボタンを押す
「お題判定機能」で決定した狼番号とユーザが入力したプレイヤー番号を比較し、ユーザが入力した番号の役割が村人であるか狼であるかを表示する。
回答表示機能
この回のゲームで決定された、AとBのお題内容及び狼番号を表示する。
画面モック
全機能が使用可能である状態の画面モックを下記に示す。
シード値:
参加人数:
プレイヤー番号:
プレイヤー番号:


この仕様において主立った課題は下記の物になります。
1.シード値からお題や狼番号が予測できないプレイヤー視点でのランダム性
2.どのクライアントからでも条件が同じならば、同じ結果(お題、狼番号)が返る再現性

 私はこの「お題、狼番号」を決定づける条件を計算式使ってグルグルと絡ませたいのですが、今回は私が作るものではなく、「人に教える」というか経緯としては「こういうものを作りたいけど手ほどきが欲しい」だったので、「お題と狼番号」を決定づける条件を下記に設定しました。

・お題:
 シード値
・狼番号
 シード値、参加人数

方針としてはプログラム内に乱数表を持ち、シード値の値をそのまま乱数表の番地とする。ただし、シード値の値が乱数表の番地数を超える可能性がある為、正確に言えばシード値に対して乱数表番地数の剰余計算を行い、その結果を乱数表の番地として扱うというものにしました。
 剰余計算とは割り算の余りを出すものですね。下記の式を書きます。
\[ X \bmod Y \]
Formula.1
Xが割られる対象、Yが割る数です。この計算式において任意の自然数Xと任意の自然数Yを選んだ時、出力される結果は0~Y-1までの値になります。

 またこのゲームは同じお題が出力されようとも、狼番号が違えば違うゲームと見なす事ができます。従って、お題選択用、狼番号選出用、「狼にAとBどちらのどちらのお題をふるか選出する為の乱数表」を用意しましたが3番目のお題割り振り用は比較的どうでもいいのでこの記事では省略します。割り振り用の乱数表本当はもうちょっと条件を絡ませないと余り意味がないのですが……まぁ私が作るものではないので押し付けるのも難ですからね。

 じゃあ「お題選択用」と「狼番号選出用」の乱数表のみに的を絞ります。この2つの乱数表があり、そして違うゲームになる条件とは即ちシード値に対する「お題選択用」乱数表の番地数及び「狼番号選出用」乱数表の番地数の剰余計算の結果の『組合せ』が違うものになる事です。

 どういう事かと言うと例えば「0-0」という書き方をします。この時、ハイフンを挟んで左側が「お題選択用」乱数表による剰余計算の結果、右側が「狼番号選出用」乱数表による剰余計算の結果とします。この時シード値のAとBの両方によって「お題番号選出用」乱数表による剰余計算の結果が「0」になったとします。この場合、シード値AとBのどちらにおいても同じお題が選出される事になります。しかし、このAとBによって「狼番号選出用」乱数表による剰余計算の結果が違うものになれば、それは違うゲームになるのです。言い換えるとそれぞれの組合せが、例えば
A: 0-0
B: 0-1
と違うものなればいいのです。

剰余計算とは周期性を持ちます。先ほど述べたように剰余計算とはFormula.1で示した計算式に則れば「0~Y-1」までの結果を返します。つまりXの値を0から初めて1ずつ増やしていくと、Yの倍数でまたその結果が0に戻る訳です。今回の場合は
\[ \begin{array}{rl} Formula A: & \\ & X \bmod Y \\ Formula B: & \\ & X \bmod Z \\ \end{array} \]
Formula.2
という2つの式があり、Xが0超でなおかつFormulaAとFormulaBの値がどちらとも0になる最小の自然数が2つの乱数表を用いた時の周期性となります。
 この場合Xの答えはYとZの最小公倍数となります。何故なら最小公倍数とはYとZの両方で割り切れる数です。だから
\[ XがYとZの最小公倍数である時\\ \begin{array}{rl} Formula A: & \\ & X \bmod Y = 0 \\ Formula B: & \\ & X \bmod Z = 0\\ \end{array} \]
Explain.1
上のFormulaAとFormulaBの結果はどちらも0になる訳です。またこの状態からXに1を足した時、FormulaAとFormulaBの結果の内どちらかがいきなり2になる等はありえず、どちらも等しく1になります。つまりXの値が0である時の組合せ「0-0」として、再び「0-0」の組合せに戻るまでを1周とした時、この1周までの数の幅はYとZの最小公倍数に等しくなるのです。

 最小公倍数とは、言ってしまえばYとZにある数Nをかけた時の積であり、なおかつ素因数分解の結果が共に等しくなっている結果の事です。その為、YとZの値が共に素数であるならば、その最小公倍数はYとZの積と等しくなります。つまり、2つの乱数表の番地数を素数にすれば、その積だけで組合せの周期をはかる事ができるのです。これによって簡単にユーザが入力できるシード値を網羅する組合せを作る事ができます。



 ここまでは正しかった……が最後の詰めが甘かった。さて、ここまで大活躍した乱数表ですが、下記のコードによって作りました。
<form id="hoge">
乱数番地数: <input type="text" name="Num" size="4"></input><br />
変数名:<input type="text" name="valueName" size="4"></input><br />
結果:
<textarea name="result" style="width:100%;height:300px;">
</textarea>
<input type="button" value="乱数生成" onclick="createRandomTable()"></input>
</form>
<script type="text/javascript">
function createRandomTable(){
var base = document.getElementById("hoge");
var RTlength = Number(base.Num.value);
if(isNaN(RTlength)){
alert("乱数番地数には半角数字を入力してください");
return;
}
var normalNumber = new Array();
for(var i = 0;i < RTlength;i++){
normalNumber.push(i);
}
var resultText = "var " + base.valueName.value+ " = [";
var resultTextBody = "";
while(normalNumber.length > 0){
var pickupNum = Math.floor(Math.random() * normalNumber.length);
resultTextBody += String(normalNumber[pickupNum])+",";
normalNumber.splice(pickupNum,1);
}
resultTextBody = resultTextBody.substring(0,resultTextBody.length-1);
resultText += resultTextBody + "];";
base.result.value = resultText;

}

</script>
Code.1
こいつを使うとランダムに一意の数が配置された配列のコードが出力される訳です。その数値の幅は0~乱数の番地数-1です。

 さて、これによって「狼番号選出用」乱数表を作ったのがいけなかったです。仮に「狼番号選出用」乱数表に使っている変数名をWolfSelectとしましょう。すると、このプログラムでは以下のようにして狼を選出しています。
var seed;//シード値
var members;//参加人数
var wolfNum;//狼番号
/*----
中略
----*/

wolfNum = WolfSelect[seed % WolfSelect.length] % members;
Code.2
この時、 WolfSelect[seed % WolfSelect.length]の値がmembers以上であるならばwolfNumの値はmembersの値によって変化します。しかし、 WolfSelect[seed % WolfSelect.length]の値がmembers未満である場合はwolfNumの値はmembersの値に関係なく固定されます。

剰余というものを一種の超過として考えましょう。そして0というものもある数Yの倍数として考える。剰余とは素朴な割算で考えれば、ある積Xに対して、X以下の値となるYの倍数を引いた差です。そして、 WolfSelect[seed % WolfSelect.length]の値がmembers未満であるという事は、言い換えればX以下となるYの倍数が必ず0になる状態です。つまり、ある数を超えるとXは必ずYのある倍数からX超過している事になるのです。これではランダム性が崩れます。
そこで私は下のコードを提供しました。結論から言うと下のコードもクソです。
var seed;//シード値
var members;//参加人数
var wolfNum;//狼番号
/*----
中略
----*/

wolfNum = WolfSelect[seed % WolfSelect.length];
var tyosei = Math.ceil(members/wolfNum);
wolfNum *= tyosei;
wolfNum %= members;
Code.3
Math.ceilとは小数点切り上げを行う関数です。割り算の結果が0.3なら1を、1.7だったら2を返します。これによってwolfNumを必ずmembers以上の値になるように調整したのです。しかし、これによって本当に参加人数による狼番号のランダム性が作れたのでしょうか?まず、上記のコード(Code.3)において、下記Code.4の時点でのwolfNumの値はどうなるでしょうか?
wolfNum = WolfSelect[seed % WolfSelect.length];
var tyosei = Math.ceil(members/wolfNum);
wolfNum *= tyosei;
Code.4
結論を言えば(とは言っても条件付きですが)
\[ members \geq 3 ならば\\ members \leq wolfNum \lt ((membrs \times 2)-1) \]
Formula.3
このゲームプレイヤーは最小でも3人いないと成り立たない。1人だと談笑相手がいないし2人だとただの2分の1の運ゲームになりますから、上記の条件は不当ではありません。

これは簡単に証明できます。まずtyoseiが1を超える際のWolfSelect[seed % WolfSelect.length]の最大の数を考えます。今回それぞれの数は自然数なので、当然答えは
\[ seed \bmod WolfSelect.length = members - 1 \]
Formula.4
です。で、計算すると
\[ members \geq 3 \\ 1 \lt \frac{members}{members-1} \lt 2 \\ \lceil \frac{members}{members-1} \rceil = 2 \\ (members-1) \times \lceil \frac{members}{members-1} \rceil = \\ (members - 1) \times 2 = \\ 2members - 2 \\ \]
Formula.5
はい……。[1]

 上記から何が言えるか。まず狼番号を選出する乱数表に0や1があるのはよろしくありませんね。0は何をかけても結果は0ですし、1もかけられた数と同じ値になります。ではWolfSelect[seed % WolfSelect.length]が2以上の時は?
 Formula.5から見てわかる通り、この場合は剰余の結果は単純にCode.3やCode.4におけるtyoseiをかけたwolfNumからmembersを引いた数によって割り出す事ができますね。で…
\[ \begin{array}{rl} 定義: & \\ & A,B,X,Y,Z \in \mathcal{N} \\ & A \gt 0 \\ & 1 \leq B \leq (X-1) \\ & X \lt Y \\ & Z = \lceil \frac{Y}{X} \rceil \\ & Y \leq XZ \leq 2Y-2 \end{array}\\ \]
\[ \begin{array}{l} この時、 Y = AX ならば、\\ \frac{Y}{X} = A = \lceil \frac{Y}{X} \rceil = Z\\ ZX = AX = Y\\ ZX - Y = 0 \\ 従って\\ 0 \leq ZX-Y \\   \\ この時、 Y = (AX+B) ならば、\\ A \lt \frac{Y}{X} \lt A+1\\ \lceil \frac{Y}{X} \rceil = (A+1) \\ ZX = AX + X \\ ZX - Y = (AX + X) - (AX + B) = X - B \\ Bの最小値 = 1 \\ 従って\\ ZX-Y \leq X-1 \end{array}\\ \]
\[ まとめると\\ 0 \leq ZX - Y \leq X-1 \]
Formula.6

という訳でCode.3の手法でも狼番号の選出の幅が0から「『狼選出用』乱数表から選ばれた数字-1」までしか持たない事になるのです。言い換えると若い番号に狼が集中しやすい仕組みになっていたのです。

 根本的な解決策は「狼選出用」乱数表の数字の最小値を充分に大きな数字にする事しかありません。流石に50人とか参加しないだろう。まぁ100ぐらいを最小値にすればいいかな?

 という事で私がする事は講義相手に提供したCode.1を改造して最小値を設定できるようにし、そして「狼選出用」乱数表をもう一度作ってもらう事ですね。後はこの記事と私の口で説明するしか。

 参りました。よく式にしてみれば簡単な話なのに……参ったなぁ。ミスったわ。

追記
 この記事では特に断わりなく基準となる視点を動かしています。なんて言うと……益々わからなくなりますね。

 簡単に言うと、Formula.5まではYの値を固定させて、Xの値を動かしている訳です。またここでの目的はCode.3による動き、つまり乱数表から選ばれた数が参加人数未満であった場合、乱数表から選ばれた数は参加人数を超える(ただし参加人数の2倍の数は超えない)という事を証明する事です。

Formula.6からはXの値を固定させてYの値を変動させています。そしてここで言いたい事はCode.3によって参加人数を超えた数であっても、その数を用いた剰余の計算の幅は元の数の範囲にとどまっているという事です。

注釈
1: もう少し真面目に証明します。
\[ \begin{array}{rl} 定義: & \\ & I.  A,B,X,Y,Z \in \mathcal{N}\\ & I\hspace{-1pt}I. X \lt Y \\ & I\hspace{-1pt}I\hspace{-1pt}I. Y \geq 3 \\ & I\hspace{-1pt}V. 1 \leq B \leq X-1 \\ & V. Z = \lceil \frac{Y}{X} \rceil \end{array}\\ この時のYに対するZXの最大値を考える \]
\[ Y = AX+B の時\\ \\ \begin{array}{rl} Aの値が0の場合: & \\ & Y=0X+B=B \\ & 定義I\hspace{-1pt}Vより\\ & B \lt X \\ & Y=Bの時、定義I\hspace{-1pt}I(X \lt Y)と矛盾 \\ & \therefore 1\leq A …V\hspace{-1pt}I. \end{array}\\ \begin{array}{l} Z = \lceil \frac{Y}{X} \rceil = A+1\\ ZX = (A + 1)X = AX+X\\ 2Y = 2AX + 2B \\ V\hspace{-1pt}Iより\\ AX + X \lt 2AX+2B \\ \\ (2AX + 2B)-(AX+X)=AX+2B-X \\ =(A-1)X + 2B \\ この時の差が最小の時ZXは最大値である\\ AとBの最小値を代入\\ A=1,B=1\\ (A-1)X + 2B =0X+2 = 2\\ \therefore ZX \leq 2Y - 2 \end{array} \]
\[ \begin{array}{l} 同じ条件でZXのYに対する最小値を考える\\ Y = AX の時\\ Z = \lceil \frac{Y}{X} \rceil = \frac{Y}{X}= A\\ A=0の場合、定義I\hspace{-1pt}I\hspace{-1pt}Iと矛盾\\ A \leq 1の場合、定義I\hspace{-1pt}Iと矛盾\\ 2\leq A \\ \\ \end{array}\\ ZXのYに対する幅は \therefore Y \leq ZX \leq 2Y-2 \]
また上記の証明の内、ZXのYに対する最大値を導いた部分を流用して
\[ \begin{array}{rl} 定義: & \\ & I.  A,B,X,Y,Z \in \mathcal{N}\\ & I\hspace{-1pt}I. X \lt Y \\ & I\hspace{-1pt}I\hspace{-1pt}I. Y \geq 3 \\ & I\hspace{-1pt}V. 1 \leq B \leq X-1 \\ & V. Z = \lceil \frac{Y}{X} \rceil \end{array}\\ \] \[ \begin{array}{l} 上記の定義におけるZXのYに対する最大値\\ 2Y - 2\\ ZXが上記の値をとる時、Yを下の様に表す\\ Y = AX + B\\ ZXが最大値の値をとる時、AとBは共に1である。\\ Y =X + 1\\ 右辺と左辺を入れ替える。\\ X= Y-1\\ よってZXが最大の値を取る時のXの値は \end{array}\\ X = Y-1 \]
ちょっと厳しい言い方をします。誰に向けてかはアレだけど。もしこの数式等に対して「Simeji_Daliがものを知っている」という認識でいたら、それは改めなければなりません。これは技術なのです。知っているかどうかより、このように考える術を得ているかだけなのです。そしてこれは技術であるが故に知識のように提供する事はできません。

テーマ:プログラミング - ジャンル:コンピュータ

Blog Top Next

π

Author

Simeji Dali Simeji Dali

美術史を学んでいます。
専門は「日本のシュルレアリスム」ですが、20世紀美術全般に興味があります。

最新記事

カテゴリ

年別アーカイブ一覧

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。