ダブル完全数

cf. どう書く?.org – ダブル完全数

HaskellのほうがRubyよりすっきりしてるな。

divisors n = filter ((==0).mod n) [1..(n `div` 2 + 1)]

isDoublePerfectNumber n = (sum.divisors) n == (n*2)

main = mapM_ (putStrLn.show) $ filter isDoublePerfectNumber [1..10000]
def divisors(n)
  (1..(n/2+1)).to_a.select{|x| n % x == 0 }
end

def double_complete_number?(n)
  divisors(n).inject(0){|a,b| a+b } == 2 * n
end

(1..10000).to_a.each do |n|
  puts n if double_complete_number?(n)
end

結果は同じ(あたりまえ)だけど,Rubyのほうが速かった。

^o^ >runhaskell dpn.hs
120
672
^o^ >ruby dpn.rb
120
672

長方形の交差判定

cf. どう書く?.org – 長方形の交差判定

問題文中の top < bottom は間違いじゃないかと書いたら,グラフィックイメージの座標だと考えればOKだとコメントをもらった。なるほど。

判定方法は,要するに一方の長方形の4つある頂点のどれかか,もう一方の長方形の内部にあれば重なってると判定していいわけだ。

今日はRubyで書いた。

class Rect
def initialize(left, top, right, bottom)
@left = left
@top = top
@right = right
@bottom = bottom
end
def vertexes
[ [@left, @top],
[@left, @bottom],
[@right, @bottom],
[@right, @top] ]
end
def inner?(x,y)
(@left < x && x < @right) && (@top < y && y < @bottom)
end
def overlap?(rect)
rect.vertexes.any?{|x,y| inner?(x,y) }
end
end
r1 = Rect.new(  0,   0, 100, 100)
r2 = Rect.new(100,   0, 200, 100)
r3 = Rect.new( 50,  50, 150, 100)
p r1.overlap?(r2)                   # => false
p r1.overlap?(r3)                   # => true
p r2.overlap?(r3)                   # => true

追記:

このコードだと長方形がX方向とY方向の両方にずれていないと正しく判定できないことに気づいた。極端な話,ぴったりと重なっている長方形が「重なっていない」判定になる。

irb(main):001:0> r1 = Rect.new(0,0,100,100)
=> #<Rect:0x499f9f4 @top=0, @left=0, @bottom=100, @right=100>
irb(main):002:0> r1.overlap?(r1)
=> false

なんてこったい。

アルファベットの繰り上がり

cf. どう書く?.org – アルファベットの繰り上がり

succ でいいじゃん,と思ったらダメだった。

Prelude> succ 'A'
'B'
Prelude> succ 'Z'
'['

Ruby の String#succ はうまくやってくれるのに。

なら,26進数だと考えて素直に繰り上がりを処理すればいいか……と思ったけどこれもダメ。’A’ は 0 じゃない。要するに 0 が無いんだな。結局繰り上がりのところで汚いコードになってしまった。

module Main ( main ) where

import Data.Char ( ord, chr )
import Data.List ( mapAccumR, intersperse )

succS :: [Char] -> Int -> [Char]
succS s n = map intToAlpha $ g $ mapAccumR f n $ map alphaToInt s
  where
    alphaToInt c = (ord c ) - 64
    intToAlpha i = chr (i + 64)
    f acc x = let (d,m) = (acc+x) `divMod` 26
    in if m == 0 then (d-1,26) else (d,m)
    g (0,b) = b
    g (a,b) = a:b

main :: IO ()
main = putStr $ concat $ intersperse "," $ take 100 $ iterate (flip succS 1) "A"

実行:

^o^ >runhaskell succS.hs
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,A
J,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,
BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,CA,CB,CC,CD,CE,CF,CG,CH,CI,CJ,CK
,CL,CM,CN,CO,CP,CQ,CR,CS,CT,CU,CV

倍数になる13進数

cf. どう書く?.org – 倍数になる13進数

module Main (main) where

fromDecimal :: (Integral a) => a -> a -> a
fromDecimal n x = f 0 x 1
  where
    f r 0 _ = r
    f r y z = f (r + (y `mod` 10) * z) (y `div` 10) (z * n)

main :: IO ()
main = putStr $ show $ head $ filter (\x -> fromDecimal 13 x `mod` x == 0) [10..]

実行。

^o^ >runhaskell multiple13.hs
1557

/*コメント*/を取り除く

cf. どう書く?.org – /*コメント*/を取り除く

正規表現の最短一致を使ってこれでいいはず……だと思うんだけど。

def remove_comment(str)
str.gsub(/\/\*.*?(\*\/|\z)/,"")
end
samples = %w( AAA
               AAA/*BBB*/
               AAA/*BBB
               AAA/*BBB*/CCC
               AAA/*BBB/*CCC*/DDD*/EEE
               AAA/a//*BB*B**/CCC
            )
samples.each do |str|
puts str
puts " => #{remove_comment(str)}"
end

実行。

^o^ >ruby remove_comment.rb
AAA
=> AAA
AAA/*BBB*/
=> AAA
AAA/*BBB
=> AAA
AAA/*BBB*/CCC
=> AAACCC
AAA/*BBB/*CCC*/DDD*/EEE
=> AAADDD*/EEE
AAA/a//*BB*B**/CCC
=> AAA/a/CCC

アレイのuniq

cf. どう書く?.org – アレイのuniq

再帰で

uniq [] = []
uniq (x:xs) = x:uniq (filter (/=x) xs)

と書いてから,こんな関数ありそうだなぁと思ったらやっぱりあった。

Data.List nub

高階関数版:

uniq2 :: (Eq a) => [a] -> [a]
uniq2 = foldl (\a e -> if (elem e a) then a else a ++ [e]) []

型を明示しないとダメ。

Prelude> :l uniq2.hs
[1 of 1] Compiling Main             ( uniq2.hs, interpreted )

uniq2.hs:2:27:
    Ambiguous type variable `b' in the constraint:
      `Eq b' arising from use of `elem' at uniq2.hs:2:27-34
    Possible cause: the monomorphism restriction applied to the following:
      uniq2 :: [b] -> [b] (bound at uniq2.hs:2:0)
    Probable fix: give these definition(s) an explicit type signature
                  or use -fno-monomorphism-restriction
Failed, modules loaded: none.

はてなダイアリーライター Version 1.4.1 を試してみた

以前に試したときにはどういうわけだかうまくいかなかってけど,今度はうまくいったので(ちょっとはまったけど),メモ。

はてなダイアリーライター本体はここから(Version 1.4.1)。マニュアルもここ。

まずは試してみる。テスト用の日記ファイルを作って,設定ファイルはなしでやってみたらすんなり成功。ちょっと拍子抜け。

^o^ >perl hw.pl
WARNING: Crypt::SSLeay is not found, use non-encrypted HTTP mode.
Username: takatoh
Password: ********
Login to http://www.hatena.ne.jp/login as takatoh.
Login OK.
Post 2007-07-08.
Post OK.
Logout from http://d.hatena.ne.jp as takatoh.
Logout OK.

けどちょっと待て。Cyrpt::SSLeayが無いから暗号化しないモードを使うといってる。

……それで思い出した。以前うまくいかなかったのはこのあたりだった。

というわけで,このへんのページを参考に改めてチャレンジ。

まずはOpenSSLから。上のリストの2番目のページからインストーラ(最新版 Win32OpenSSL v0.9.8e)をダウンロードしてインストールするだけ。

Crypt::SSLeay のほうは上のリストの3番目のページにある「LWPで、「https://」で始まるSSL使用サイトにアクセスできますか?」を参考にした。ppmコマンドでインストールするんだけど,モジュール名ではなくPPDファイル名を指定する必要があるらしい(GUI版ppmのリストに出てこない)。ActivePerl 5.8.8 を使っているので:

^o^ >ppm install http://theoryx5.uwinnipeg.ca/ppms/Crypt-SSLeay.ppd

後半,dllをインストールするか聞いてくるので yes と答えてインストールする。デフォルトが[no]になってるので注意。

さて,改めて試してみよう。ついでに設定ファイルも書いておく。

id:takatoh
password:********
cookie:cookie.txt
proxy:http://proxy:8080/
client_encoding:Shift_JIS
server_encoding:EUC_JP

これでOKのはず。

^o^ >perl hw.pl
Login to https://www.hatena.ne.jp/login as takatoh.
Login OK.
Post 2007-07-08.
Old cookie. Retry login.
Login to https://www.hatena.ne.jp/login as takatoh.
Login OK.
Old cookie. Retry login.
Login to https://www.hatena.ne.jp/login as takatoh.
Login OK.
ERROR: try_it: Check username/password.

なんでエラーになるんだ!!……orz

えーと。いろいろ試した結果何とか動くようになった。これについてはエントリーを改めて書く。

さきに書いておくと,インストールや設定ファイルは上の通りで大丈夫(たぶん)。問題はcookie.txtだった。--(つづく)

はてなダイアリーライター Version 1.4.1 を試してみた(その2)

id:takatoh:20070708:hw のつづき。Crypt::SSLeayをインストールしたらエラーになった件。

いろいろ試した結果,クッキーファイル(cookie.txt)の有無と関係が有ることがわかった。表にするとこんな感じ。

cookie.txtあり cookie.txtなし
Crypt::SSLeayなし OK OK
Crypt::SSLeayあり OK エラー

Crypt::SSLeayが無い場合にはcookie.txtの有無に関わらずOKなんだけど,これは暗号化されないってことなんで非推奨。Crypt::SSLeayをインストールするとcookie.txtが無い場合にエラーになる。無けりゃ作ってくれるはずなんだけど,ここで失敗しているように見える(最後から2行目)。……ちがうのかな。

-d オプションをつけて実行した結果:

^o^ >perl hw.pl -d
DEBUG: Debug flag on.
Hatena Diary Writer Version 1.4.1
Copyright (C) 2004,2005 by Hiroshi Yuki.
DEBUG: Loading config file (config.txt).
DEBUG: load_config: id:takatoh
DEBUG: load_config: password:********
DEBUG: load_config: cookie:cookie.txt
DEBUG: load_config: proxy:http://proxy:8080/
DEBUG: load_config: client_encoding:Shift_JIS
DEBUG: load_config: server_encoding:EUC_JP
DEBUG: main: files: current dir (.): ./2007-07-08.txt ./touch.txt
DEBUG: login: proxy for http: http://proxy:8080/
DEBUG: login: proxy for https: http://proxy:8080/
Login to https://www.hatena.ne.jp/login as takatoh.
DEBUG: login: 200 OK
DEBUG: login: $r = <HTML></HTML>
Login OK.
DEBUG: login: Making cookie jar.
DEBUG: login: $cookie_jar =
DEBUG: read_title_body: input: ./2007-07-08.txt
DEBUG: Convert from Shift_JIS to EUC_JP.
Post 2007-07-08.
DEBUG: create_it: 2007-07-08.
DEBUG: create_it: 302 Moved
DEBUG: create_it: Location: /takatoh/
DEBUG: create_it: returns 0 (ERROR).
DEBUG: try_it: update_diary_entry: CREATE.
Old cookie. Retry login.
DEBUG: login: proxy for http: http://proxy:8080/
DEBUG: login: proxy for https: http://proxy:8080/
Login to https://www.hatena.ne.jp/login as takatoh.
DEBUG: login: 200 OK
DEBUG: login: $r = <HTML></HTML>
Login OK.
DEBUG: login: Making cookie jar.
DEBUG: login: $cookie_jar =
DEBUG: create_it: 2007-07-08.
DEBUG: create_it: 302 Moved
DEBUG: create_it: Location: /takatoh/
DEBUG: create_it: returns 0 (ERROR).
DEBUG: try_it: update_diary_entry: CREATE.
Old cookie. Retry login.
DEBUG: login: proxy for http: http://proxy:8080/
DEBUG: login: proxy for https: http://proxy:8080/
Login to https://www.hatena.ne.jp/login as takatoh.
DEBUG: login: 200 OK
DEBUG: login: $r = <HTML></HTML>
Login OK.
DEBUG: login: Making cookie jar.
DEBUG: login: $cookie_jar =
ERROR: try_it: Check username/password.

結局,Crypt::SSLeayをインストール/アンインストールしたり,設定ファイルを書き換えてみたりしてるうちにできた(つまりCrypt::SSLeayなしの時にできた)クッキーファイルがあって動くようになったので今回はOKとする。Crypt::SSLeayありの状態でクッキーファイルを作る方法はわからない。

なんだか中途半端だけど時間切れだ。

追記:PCの環境

  • Windows XP
  • ActivePerl 5.8.8
  • Crypt::SSLeay 0.53

追記2:proxyなしの場合

hyukiさんのアドバイスに従ってproxyの無い環境で試してみたら,正しく投稿できた。どうやら次の3つが重なったときにエラーになるらしい。

  • Crypt::SSLeay あり
  • クッキーファイルがない
  • proxyを利用