新しく宣言した変数のリファレンスを取得する方法

今まで変数のリファレンスを取得するためには,わざわざリファレンス変数に代入してから使っていた.


こうすれば変数宣言と同時にリファレンスを取得できるみたい.

\ my %hash;


確認プログラム

my $hoge_ref = \ my %hoge;
%hoge = (yamada => 1, tanaka => 2, sato => 3);

while ( my ($key, $val) = each %$hoge_ref ){
  print "$key:$val\n";
}
__End__
# 出力結果
yamada:1
sato:3
tanaka:2

リファレンス渡しの関数を呼び出すときに今までよりも一行少なくて済みそう.

レッツ・チャレンジパソコン甲子園第12回の問題を解いてみた

日経ソフトウェア2008年4月号のパソコン甲子園の問題を解く連載.今回はブラックジャックの手札が与えられた際に点数を返すというもの.


とても時間がかかりました.けれど,解法にはそれなりに満足.

ブラックジャックルール説明

ブラックジャックは,1〜13の数が書かれたカードを使う.

  • 1は1点,あるいは11点
  • 2から9までは書かれている数通りの点数
  • 10から13までは10点

手札の合計で点数を決める.手札による合計点の算出方法は以下の通り

  • カードの点数の合計が21より大きくなるときは0点
  • 1は1点と計算しても11点と計算してもよいが,手の点数が最大となるほうを選ぶこととする(ただし21を超えない範囲で)

問題

配られたカード情報を入力とし,手の点数を出力するプログラムを作成せよ.
ただし,ひとつの手に含まれるカードの枚数nは1以上21以下とし,同じ数を何枚も含むことができるものとする.



どうやらこの問題は高めの50点問題,そして正答率が40%.ぱっと見の難易度を考えたらなんでこんなに点数が高くて,そして正答率が低いんだろう,と思った.けれど気がついて納得(?).問題の最後の条件から,ひとつの手札に21枚1が含まれていることがある,という場合にきちんと21点を返せないんじゃないかなと思ったりする.


この問題のポイントは,1を11点と数えるか1点と数えるか,というロジック.問題が簡単だからLispで書こうと思ったのだけれど,ロジックが思い浮かばず10分で諦める.


正直悔しかったので,他の作業をしながら考えていたら思いついた.

1の点数を11点とする.
手札に含まれる1の枚数をk枚とする.
手札の合計をtとする.

tが21を超えており,かつkが1枚以上あれば
tにt-10を代入し,kにk-1を代入する

わかりづらッ!
こゆことです.なんとなくRubyスタイル

while t > 21 and k > 0
  t = t - 10
  k = k - 1
end

1の点数を11点に固定しておいて21を超えたら引く,というad-hocなアプローチ.
というわけで問題が一気に簡単になり,与えられた手札の中に何枚1が含まれているかを数えれば解けるようになった.


Lispで実装してみた.whileが便利すぎるのでEmacs-lispまたはXyzzy-lispで.
black-jack関数内で1の数を数えて,black-jack-sub関数で上述のロジックを計算している.

(defun black-jack (lis)
  (let ((count-of-1 0))
    (dolist (x lis)
      (if (= x 1) (setq count-of-1 (1+ count-of-1))))
    (black-jack-sub lis count-of-1)))

(defun black-jack-sub (lis count)
  (let ((total 0) (tmpcount count))
    (dolist (card lis)
      (setq total (+ total (bj-score card)))
      (while (and (> total 21) (>= tmpcount 1))
	(progn
	  (setq total (- total 10))
	  (setq tmpcount (1- tmpcount)))))
    (if (> total 21) 0 total)))

(defun bj-score (card)
  (cond ((= 1 card) 11)
	((>= card 10) 10)
	(t card)))

(black-jack '(1))
=> 11
(black-jack '(7 7 7))
=> 21
(black-jack '(7 7 8))
=> 0
(black-jack '(12 1))
=> 21
(black-jack '(10 1 1))
=> 12
; こんなパターンもありうる
(black-jack '(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))
=> 21

ちゃんと解けた!
高校3年生に比べて4/3倍生きている面子が保てた?

Perlにおけるgrepが見つからない〜そこでTIMTOWTDIですよ!

Lispには高階関数が沢山用意されている.map族でいえば,mapにはじまり,mapcar, mapcan, mapcon, maplist, map-intoなどがある.ほとんど知らんし,使えん.

当然のことながら今までmapcarくらいしか使ったことがなかったのだが,そういやPerlにおけるgrepに相当する関数を知らないなと思った.
(調べ方が悪いのだけれど)見つからなかったから手持ちの写像関数で実装してみた.

mapcanは,リストの各要素に関数を適用した結果得られたリストをnconc(破壊的append)して返してくれる.これ使えばいいじゃん.

例えばリストの中で3より大きいという条件を満たす値を要素とするリストを取得する.
普通に書くのは嫌だったので,Perlっぽく書いてみた.Perl6のsayも使ってますぜ

use Perl6::Say;
foreach ( grep { $_ > 3 } (3, 4, 5) ){
  say
}
__END__
出力結果
4
5


Lispだったらmapcan使ってこう書く

(mapcan #'(lambda (x)
	    (if (> x 3) (list x) nil)) '(3 4 5))
; (4 5)


うん,TIMTOWTDIだしね!

Mew IMAPでgmail(IMAP超初心者編)

昨年GmailIMAP対応したというので,やろうやろうと思っていてやっていなかった.ようやく手を出したものの,色々と躓いたのでメモ

自分のスペック

  • stunnelやopensslは入っている
  • Mewの基本的な設定はおk


まず,.mew.elにこんな感じで書く.

; IMAP for Gmail
(setq mew-proto "%")
(setq mew-user "xxx")
(setq mew-mail-domain "gmail.com")

(setq mew-imap-server "imap.gmail.com")
(setq mew-imap-user "xxx@gmail.com")
(setq mew-imap-auth  t)
(setq mew-imap-ssl t)
(setq mew-imap-ssl-port "993")
(setq mew-smtp-auth t)
(setq mew-smtp-ssl t)
(setq mew-smtp-ssl-port "465")
(setq mew-smtp-user "xxx@gmail.com")
(setq mew-smtp-server "smtp.gmail.com")


Mewを起動してsを押し,更新しようとすると

「3Zを押しな!」(原文忘れた)

というメッセージが出るので押す.するとCase-valueと聞かれたので,DefaultのままEnterを押したらエラーメッセージが.

Creating an SSL/TLS connection...FAILED (cert verify failure)

あれま.


StunnelはGmailをPOPで吸い出すときに使ったし,OpenSSLは当然入ってるし.理由がわからない.エラーメッセージで検索したらどんぴしゃぽいのが出てきた.


どうやら証明書が必要らしい.~/.certsって聞いたことないんですけど.
mew-distにそれっぽい投稿があったのでチェック.キャッシュからしか見れなかったのでコピーしておく.

  • [mew-dist 27313] CA certificates for Mew to use Gmail by 木下達也氏
Fedora Core 5についてはよくわかりませんが、手元では、Debianパッケージ
ca-certificatesに含まれている証明書で、pop.gmail.comのverifyが成功する
ことを確認できています。

Debian以外の環境でも下記のようにすれば利用できるものと思いますので、
試されてはいかがでしょうか。

* http://packages.qa.debian.org/ca-certificates
  のSource filesから、*.tar.gzと*.dscをダウンロード。

  (*.dscにはメンテナ(ukaiさん)のGPG署名付きでMD5 checksumが書かれており、
  ファイルの改竄がないか確認できます)

* ca-certificatesに含まれているMozilla builtin CA certificatesを~/.certs
  にコピー。

  $ tar zxvf ca-certificates_20060816.tar.gz
  $ cd ca-certificates-20060816/mozilla/
  $ make  # 要ruby
  $ mkdir ~/.certs
  $ for f in *.crt; do cp $f ~/.certs/`openssl x509 -hash -noout -in $f`.0; done

ちなみにDebian GNU/Linux 3.1 (sarge)以降のmewおよびmew-betaパッケージ
では、デフォルトでca-certificatesパッケージに含まれている証明書で検証
するよう設定されています。


そのまんまで成功した!やた!!
MewIMAP操作はよくわからないので,あとで色々練習してみよう.