Emacs Lispことはじめ ~OpenContest1を解く~
この記事は、SLP_KBIT Advent Calendar 2016 - Qiitaの1日目の記事です。
はじめに
ここ最近、SLPのVim勢がとっても本格的になっていてすごいな(小並感)となってます。
Emacs派の自分としては、もっとちゃんとEmacsの勉強をしないと失礼かなと思って絶賛勉強中。
そこで、Emacs派ももっと盛り上がって行きたいなと思ってEmacs Lispについて書こうかなっと思った次第です。
Emacs LispはEmacsの設定書くための言語ではありますが、今回はわかりやすいと思い、SLPおなじみのOpenContest1から幾つか抜粋して紹介していこうと思います。
四則演算 3変数の和と平均
コード
(setq x (string-to-number (read-string "x = "))) (setq y (string-to-number (read-string "y = "))) (setq z (string-to-number (read-string "z = "))) (princ-list "sum is " (+ x y z)) (princ-list "avg is " (/ (+ x y z) 3.0))
実行結果
$ emacs --script answer.el x = 1 y = 6 z = 10 sum is 17 avg is 5.666666666666667
解説
関数と演算子
EmacsLispでは、関数は以下のような形式で利用します
(関数名 値 ...)
C言語のprintfで例えると printf("Hello World!");
は (printf "Hello World!")
演算子なども同様で、前置記法で記述されます。
(+ 2 3) => 5
標準入力からの読込み
標準入力からの読込みは、read-string
関数で行います。
read-string
関数は、第一引数で与えられた文字列を出力した後、標準入力から読み込んだ文字列を返却します。この関数自体は、数値や文字列などの指定なく返却します。("Hello World"と入力すれば、返却値は"Hello World")
(read-string "x = ") => "3" (標準入力で入力された値)
文字列から数値への変換
read-lineで読み込んだ値は、文字列であるため、そのままでは演算出来ません。
そこで、string-to-number
関数を利用して、数値に変換します。
(string-to-number "3") => 3
変数への代入
Emacs Lispでは、変数宣言の必要はありません。
変数への代入は、setq
関数を利用します。(set
関数でも出来ます。違いはググってください)
(setq x 3) => x = 3
以上の処理により、1-3行目では、標準入力から読み込んだ値を数値として変数に格納しています。
標準出力への表示
princ-list
関数は、引数を結合して標準出力に表示します
(princ-list "Hello" "my" "name" "is" "Taro") => Hello my name is Taro
if構文による分岐
整数 n を入力し、2 でも 3 でも割り切れないときは、1、 2 でのみ割り切れるときは 2、3 でのみ割り切れるときは 3、 2 でも 3 でも割り切れるときは 6 を出力する。
解答
(setq n (string-to-number (read-string "n = "))) (cond ((eq (% n 6) 0) (princ "6\n")) ((= (% n 3) 0) (princ "3\n")) ((= (% n 2) 0) (princ "2\n")) (t (princ "0\n")))
実行結果
$ emacs --script answer.el n = 12 6
解説
cond文
EmacsLispでの条件文には、if
、when
、unless
、cond
があります。(本当は条件文ではなく全て関数らしいのですが)
if文は、else if
といったことが出来ません。 そこで、cond文を使います。cond文は、Cのswitch文みたいなものです。
以下の形式で実行します。
(cond (条件式 文) (条件式 文) (条件式 文))
上から順に条件式が実行され、条件がt(true)になった文を実行します。
どれにも当てはまらなかったときの条件は、条件式にt
と書くことで、必ず成立するようにして書きます。
for構文による低反復
初期値 c0, c1 と係数 r1, r2 を入力し、項数 n を指定する。 初期値 A(0)=c0, A(1)=c1 と漸化式 A(n)=r1×A(n-1)+r2×A(n-2) で定義される数列を、 第 0 項から第 n-1 項まで、各行に、項番 項値 を出力する。
コード
(setq c0 (string-to-number (read-string "c0 = "))) (setq c1 (string-to-number (read-string "c1 = "))) (setq r1 (string-to-number (read-string "r1 = "))) (setq r2 (string-to-number (read-string "r2 = "))) (setq n (string-to-number (read-string "n = "))) (princ-list "[0] " c0) (princ-list "[1] " c1) (setq count 2) (while (<= count (- n 1)) (setq next (+ (* c1 r1) (* c0 r2))) (princ-list "[" count "] " next) (setq c0 c1) (setq c1 next) (setq count (+ count 1)))
実行結果
$ emacs --script answer.el c0 = 2 c1 = 3 r1 = 1 r2 = 1 n = 5 [0] 2 [1] 3 [2] 5 [3] 8 [4] 13
解説
while文
EmacsLispには、for文に相当するものがないようなので、while文で行いました。
while文は、以下のような形式で記述します。
(while 条件式 文...)
インクリメントとclライブラリ
今回のコードでは、インクリメントを(setq count (+ count 1))
と書いています。
EmacsLispのデフォルトでは、インクリメントを行う関数は用意されていません。
しかし、clライブラリ(Common Lisp)をrequireすれば、incf
という便利なマクロを利用することが出来ます。
(require 'cl) ... (while (< count (- n 1)) ... (incf count))
2016年の指定月のカレンダー出力
最後に、みんなを悩ませた枠付きカレンダーの出力をやってみよう。
ほとんど、これまでに説明した内容で出来るはずです!
解答コードはこちら
(require 'cl) ;; 関数宣言========================================= ;; 該当月の日付を取得する関数 (defun get-day-count (month is-leap-year) (setq day-count 31) (cond ((or (eq month 4) (eq month 6) (eq month 9) (eq month 11)) (setq day-count 30)) ((eq month 2) (setq day-count 28) (when is-leap-year (setq day-count 29)))) day-count) ;; うるう年判定の関数 (defun is-leap (year) (or (eq (% year 400) 0) (and (eq (% year 4) 0) (/= (% year 100) 0)))) ;; 本体================================================ (setq year 2016) (setq month (string-to-number (read-string "month = "))) (princ "日 月 火 水 木 金 土\n") ;; うるう年の判定 (setq is-leap-year (is-leap year)) (setq days (get-day-count month is-leap-year)) (setq pasted-days 0) (setq pasted-month 1) ;; 月の初めまでの日数を格納 (while (< pasted-month month) (incf pasted-days (get-day-count pasted-month is-leap-year)) (incf pasted-month)) ;; 月の初めの曜日コードを取得(1月1日は金曜日) (setq first-day-code (% (+ pasted-days 5) 7)) (setq day-code-count 0) (while (< day-code-count first-day-code) (princ " ") (incf day-code-count)) (setq today 1) (while (<= today days) (princ (format "%02d " today)) (when (eq day-code-count 6) (princ "\n") (setq day-code-count -1)) (incf day-code-count) (incf today))
実行結果
$ emacs --script answer.el month = 12 日 月 火 水 木 金 土 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
さいごに
次回は、もっとEmacsLispっぽいコードを書こうかなとおもっています。
みんなも一緒にEmacsLisp勉強しよう!
Teraterm + Emacs で動作が崩れる話
XperiaZ5 画面故障からUSBマウスを認識させる方法
まえがき
つい昨日、自転車で意気揚々と走っていた所、最近買ったばかりのXperiaZ5を落としてしまいました。
まあ割とよく落としてるし。。。と思いつつ拾ってみると、落とし方が悪かったのか、画面を割ってしまいました。ナンテコッタ
タッチを認識しなくなってしまい、これは交換するしか無いな。。。
まあデータはPCに繋げば吸い出せるし。。。と思ったところで、ソシャゲの引き継ぎ設定を指定なかったことに気づきました。
俺の城下町がああああああああああ。
諦めきれず四苦八苦したところ、なんとか動かすことが出来たので私のような人が1人でも多く助かるように書こうと思います
USBマウスでスマホ操作
調べた所、同じような状況の人は結構いて、「スマホ 画面 割れた 操作」などで検索すると出てきました
結果的に、USBマウスを繋げて簡単に操作できることが分かりました。
個々に関しては様々な方々が記事を書かれているので割愛します。
以下などが参考になると思います。
XperiaZ5のクソ仕様
ここで意気揚々と変換ケーブル買ってマウスさして動く!と思ったが、認識しない。
タブレットでは動くので、ケーブルは悪くない模様。
ここで調べた所、以下のサイトがヒット
[設定]-[Xperia接続設定]-[USB接続設定]-[USB機器を検出]という手動操作を行わないと使用可能になりません。
それが出来ねえんだよ!!クソ!!
本題
ここでようやく本題
諦めきれずに四苦八苦して8時間
ついに見つけたタッチせずにUSBマウスを認識させる方法を!!
以下がその手順です。
- XperiaZ5の電源ボタン+ボリュームアップボタンを長押しして電源を強制終了
- USBマウスを接続する
- 電源ボタンを長押しして起動
するとUSBマウスを認識させることができました!!やった!!お帰り俺の城!!
おわり
なぜXperiaZ5(Z4も?)だけこんな仕様なのか。。このクソ仕様がなければこんなに苦労しなかったのに。
次の機種では治っているといいな
でもiPhone勢は割れても使えてる人たくさんいるし、次はiPhoneにしようかな
そもそも割るなよって話ですね。。。気をつけよう
パスワードクラッキング(超初級)
まえがき
SLP KBIT Advent Calendar 2015 - Adventar用の記事です!
年を経るに連れて下級生の参加が減ってる気がする...
____ ) 簡単な内容でいいからみんな書くんだお /⌒ ⌒\ ) /( ●) (●) \ )/⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y⌒Y丶 / ::::::⌒(__人__)⌒::::: \ | |r┬-| | \ `ー'´ / ノ \ /´ ヽ カ | l l||l 从人 l||l l||l 从人 l||l カ タ ヽ -一''''''"~~``'ー--、 -一'''''''ー-、. タ ヽ ____(⌒)(⌒)⌒) ) (⌒_(⌒)⌒)⌒)) ┌┬┬┐┌┬┬┬┐┌┬┬┬┐┌┬┬┬┐ ,. - ''"| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ρ ̄`l  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ノ ̄ ̄
とりあえず自分の知ってる知識でがんばって書きます。 間違ってたらごめんね
パスワードの保存方法
みんなパスワードってどういう形式で保存されてるか知っますか? パスワードは、原則的にはハッシュという形式で保存されています。 そもそもハッシュとはなんぞやって人は以下を参照。 知ってる人は飛ばしてね。
暗号とハッシュ
ハッシュ化は、暗号化と似ていて、データの機密性を向上させるものです。 しかし、そこには決定的な違いが有ります。
- 暗号化は、復号化して、元のデータを得ることができる
- ハッシュ化は、元のデータを復元することが出来ない
暗号化は、内容が重要で、相手にデータの内容が見える必要があるが、第3者に見られたくない時に利用されます。
主に、セキュアな通信などで用いられます。
しかし、ハッシュ化は、内容は重要ではなく、データが一致するかどうかだけ確かめる必要があるが、元のデータはバレてはならない時に利用されます。
主に、パスワード管理に用いられます。
パスワードとハッシュ
ユーザのパスワードを管理する場合、データベースにそのままパスワードを保存していると、なんらかの形でパスワードデータが漏洩した場合、そのユーザとパスワードを用いて、容易に不正アクセスすることが可能となります。
しかし、パスワードをハッシュとして保存していると、パスワードデータが漏洩しても、そこにはハッシュ値しか書かれていないため、元のパスワードを復元することができません。
パスワードへの攻撃
パスワードへの攻撃手法としては、ネットワークを介して攻撃をする「オンライン攻撃」とパスワードのハッシュファイルを手に入れてから攻撃をする「オフライン攻撃」があります。
総当たり攻撃
読んで時のごとく、パスワードの候補となる文字列を順番に全て試していく方法です。 時間はかかりますが、全ての組み合わせを実行することができるため、確実にパスワードを突破することが出来ます。 5文字以内なら数分程度で解けますが、10文字ともなると数年単位の時間がかかります
辞書式攻撃
これもまた字の如く、辞書を用いた攻撃です。
パスワードに登録されやすい単語を辞書ファイルとして保存しておき、それを用いて攻撃を行う手法です。
総当りと比較すると、確実性には欠けますが、英単語や"hoge"なんかのパスワードだと、ほぼ一瞬で突破することが出来ます。
サーバへユーザ登録する際に、「辞書に乗っている単語です」と怒られた人は多いのではないでしょうか
類推攻撃
またまた字のごとく、パスワードを類推する攻撃手法です。 アカウントやメールアドレス、生年月日など、ユーザが公開している情報を元にパスワードを推測し、攻撃する手法です
まとめ
パスワードをきちんと管理しましょうという意味をきちんと理解できるようになったでしょうか
パスワードはできるだけ長く、文字種も多くしたほうが安全というのは常識ですが、なぜそうなのかも説明できるとなお良いですね。
また、今回紹介した攻撃手法は、擬似的なものであればC言語などでも実装できるので、ぜひ書いてみて、その処理速度を比較してみても
面白いかもしれません。
このままアドベントカレンダーに空きがあるようならするかもしれませんw
サーバセットアップ手順 自分用
サーバセットアップするときの手順 自分用のメモ書き
update
$ aptitude update
gcc
$ aptitude isntall gcc
開発環境?
$ aptitude install build-essential $ aptitude install openssl libssl-dev zlib1g-dev libreadline-dev libcurl4-openssl-dev
porg
$ wget http://downloads.sourceforge.net/project/porg/porg-0.8.tar.gz $ ./configure --disable-grop $ make $ make install $ make logme $ porg -a
ruby
rbenvをワールドワイドに使う場合
sudo git clone https://github.com/sstephenson/rbenv.git /usr/local/rbenv sudo git clone https://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build // 絶対これじゃない sudo chmod 777 -R /usr/local/rbenv sudo visudo #===================================================================== # /etc/sudoers # Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin ← 元の記述はコメントアウトするなど Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/rbenv/bin:/usr/local/rbenv/shims Defaults env_keep += "RBENV_ROOT" #===================================================================== sudo rbenv init - #===================================================================== export RBENV_ROOT=/usr/local/rbenv export PATH="$RBENV_ROOT/bin:$PATH" eval "$(rbenv init -)" #===================================================================== source /etc/profile export RUBY_BUILD_SKIP_MIRROR=1 rbenv install `rbenv install --list | grep -v - | tail -1` rbenv global `rbenv install --list | grep -v - | tail -1` ruby -v
rbenvを使う場合
sudo aptitude install -y rbenv vi .bashrc # export PATH="$HOME/.rbenv/bin:$PATH" # eval "$(rbenv init -)" source .bashrc export RUBY_BUILD_SKIP_MIRROR=1 rbenv install `rbenv install --list | grep -v - | tail -1` rbenv global `rbenv install --list | grep -v - | tail -1` ruby -v
rbenvを使わない場合
$ wget https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.3.tar.gz $ ./configure $ make $ porg -lp ruby-2.2 "make install
ruby 開発環境
//rbenvならやっちゃだめ? //sudo aptitude install -y ruby-dev sudo gem install bundler
zsh
$ aptitude install zsh
git
$ sudo aptitude install -y git libexpat1-dev gettext $ cd /usr/locar/src $ sudo git clone https://github.com/git/git.git $ sudo aptitude remove git $ cd git $ sudo make prefix=/usr/local all $ sudo porg -lp git 'make prefix=/usr/local install'
PostgreSQL
$ sudo aptitude install -y postgresql-9.3 libpq-dev
direnv
$ cd /usr/local/src $ sudo git clone https://github.com/direnv/direnv $ sudo porg -lp direnv "make install"
rails
$ sudo gem install rails pg
ntp
sudo aptitude install ntp sudo /etc/init.d/ntp stop sudo ntpdate ntp.nict.jp sudo vi /etc/ntp.conf #============================- # server ntp.ubuntu.com server ntp.nict.jp server ntp.nict.jp server ntp.nict.jp #============================- sudo /etc/init.d/ntp start
Emacsでゲームしよう
SLP Advent Calendar用に記事書きます。
先月は5つくらいなら記事書けそうな気がしたんですが、
いろいろイベントがあるうちに、どんなネタがあったか忘れてしまった..orz
相変わらず何かをしていると何かを忘れる鳥頭です。
皆さん、思いついたことはとりあえず何かにメモしておきましょう。
何書くか迷ったんですが、そういえば前のLTで次回Emacsについてするって言ってたし、
それ消化しようかと思い、Emacsについてしてみることにしました。
今回は、Emacsを知らない人のために、Emacsの説明をた後で、
最近僕がハマっているEmacs上のゲームをいくつか紹介したいと思います。
Emacsとは
Emacsとは、世界で最も優れたエディタです。
え?V●●?なにそれ美味しいの?
と言うのは冗談です。とりあえずお約束です。
よく話には聞くと思いますが、EmacsはVimと双璧を成すと言われるテキストエディタです。
たまにEmacsはエディタではなく環境と言われますが、
確かにEmacsの拡張性はエディタの範疇を超えてるといわれるほど高いです(ドヤ。
Emacsの特徴としては、以下のようなものがあります。
- 豊富なコマンドがある
- 様々なプログラミング言語に対応している
- 高い拡張性を持つ
当然他にもいろいろありますが、とりあえず分かりやすいかと思うものを挙げました。
とりあえず、エディタ使っててこれ出来ないかなって思ったものは大抵出来ます。
Emacsを使って皆さんも幸せなエディタライフを送りましょう。
Emacsの操作方法
Emacsを起動するには、プロンプト上でemacs
と入力します。
Emacsのコマンドは、主にControlキーとMetaキーを用いて入力します。
Metaキーは、ほとんどのキーボードには付いてないので、Altキーで代用します。
Tera Termを使ってる場合は、設定 > キーボード
を開いて、Metaキーにチェックをつけることで、AltキーをMetaキーとして使えます。
また、Controlキーを押しながらaを押すなどという動作は、C-a
と書きます。
Emacsを終了する場合は、C-x C-c
と入力します。
Emacsの基本操作は、M-x help-with-tutorial-spec-language
と打って、その後Japanese
を入力すると、
日本語チュートリアルが始まります。これを終えると、基本的な動作はマスターできます。
Emacs標準搭載のゲーム
それでは、Emacsが標準で搭載しているゲームをいくつか紹介します。
基本的に、M-x <ゲーム名>
でゲームを始め、C-x k
で終了することが出来ます。
1.スネーク
M-x snake
で、snakeを遊ぶことが出来ます。snakeは、tronのようなゲームです。
方向キーで蛇を操作し、壁や自身にぶつからないようにするゲームです。
蛇の後ろから物体が出現するので、そのう●こを集めてスコアをアップさせましょう。
2.テトリス
M-x tetris
で誰もがご存知テトリスを遊ぶことが出来ます。
方向キー上下で回転、左右でブロックを移動、スペースで落下させることが出来ます。
僕はこういうタイプのゲームは苦手で、すぐ死んでしまいますね...
3.ハノイの塔
C-u <数字> M-x hanoi
で、指定した数の段のハノイの塔が完成するまでを眺めることが出来ます。
眺めるだけです。癒されますね。やっぱりEmacsって素晴らしい。
4.五目並べ
M-x gomoku
で五目並べができます。日本人なら誰でもご存知ですね。
これはカーソルを動かして石を置いていくだけです。
ちなみに僕はこのAIに勝ったことがありません()。
最後に
今回は簡単なものをいくつか紹介しました。
他にも標準搭載されているものや、拡張で出来るゲームがたくさんあります。
勉強にもメモにも遊びにも、何でも出来るEmacs、皆さんぜひ使いましょう。