2009年8月28日金曜日

PythonのワンライナーでTwitterを使う

このブログ記事をはてなブックマークに追加

Twitterでつぶやいたり、タイムラインを取得したりするPythonのワンライナー(1行プログラム)を作ってみた。取り敢えずWindowsで動作は確認した。Pythonさえ入っていればどこでも動くと思う。シェルやcronに組み込んだり、ウェブアプリや自作プログラムで利用したり、Python以外に必要なものがないから手軽に使えるんじゃないかな。ただ、ユーザ名とパスワードは生テキストなのでその辺は気をつけるべきかも。

まず、Twitterでつぶやくワンライナー。

python -c "import urllib,urllib2;pm=urllib2.HTTPPasswordMgrWithDefaultRealm();pm.add_password(None,'twitter.com','username','password');urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(pm)));urllib2.urlopen('http://twitter.com/statuses/update.xml',urllib.urlencode({'status':'つぶやき'.decode('cp932').encode('utf-8')}))"

次に、タイムライン取得。simplejsonを使っている。

python -c "import sys,urllib,urllib2,xml.sax.saxutils,simplejson;pm=urllib2.HTTPPasswordMgrWithDefaultRealm();pm.add_password(None,'twitter.com','username','password');urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(pm)));sys.stdout.write(''.join(['%s: %s\n'%(d['user']['screen_name'],xml.sax.saxutils.unescape(d['text']))for d in simplejson.loads(urllib2.urlopen('http://twitter.com/statuses/friends_timeline.json').read())]).encode('cp932','replace'))"

因みに文字コードはCP932、簡単に言えばShift JISなので(厳密には違うけど)、環境に合わせて修正したり、nkfをかませるなどして欲しい。それにしても、TwitterのAPIは使いやすくていいね。

追記(2009/8/29):

Twitterのつぶやきとタイムライン取得の両方を行うワンライナーも書いてみた。このコードはPython 2.5以上で動作する。

python -c "import sys,urllib,urllib2,xml.sax.saxutils,simplejson;pm=urllib2.HTTPPasswordMgrWithDefaultRealm();pm.add_password(None,'twitter.com','username','password');urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(pm)));sys.stdout.write(''.join(['%s: %s\n'%(d['user']['screen_name'],xml.sax.saxutils.unescape(d['text']))for d in simplejson.loads(urllib2.urlopen('http://twitter.com/statuses/friends_timeline.json').read())]).encode('cp932','replace'))if len(sys.argv)<2 else urllib2.urlopen('http://twitter.com/statuses/update.xml',urllib.urlencode({'status':sys.argv[1].decode('cp932').encode('utf-8')}))" つぶやき

「つぶやき」を書けばそれがTwitterに送信され、書かなければタイムライン取得となる。また、「つぶやき」にスペースなどが入る場合はダブルクォーテーション(")で括ること。

次のコードであればPython 2.4以下でもいけるかな。

python -c "import sys,urllib,urllib2,xml.sax.saxutils,simplejson;pm=urllib2.HTTPPasswordMgrWithDefaultRealm();pm.add_password(None,'twitter.com','username','password');urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(pm)));len(sys.argv)<2and[sys.stdout.write(''.join(['%s: %s\n'%(d['user']['screen_name'],xml.sax.saxutils.unescape(d['text']))for d in simplejson.loads(urllib2.urlopen('http://twitter.com/statuses/friends_timeline.json').read())]).encode('cp932','replace'))]or[urllib2.urlopen('http://twitter.com/statuses/update.xml',urllib.urlencode({'status':sys.argv[1].decode('cp932').encode('utf-8')}))]" つぶやき

続きを読む...

2009年8月27日木曜日

Windows PowerShellを便利に使うための10のミニテクニック

このブログ記事をはてなブックマークに追加

Microsoftが提供していてWindows 7では標準搭載になるWindows PowerShellがもっと広まって欲しいこともあって、CodeZineWindowsのコマンドプロンプトを便利に使うための10のミニテクニックのPowerShell版を書いてみた。

まず、Windows PowerShell 2.0 CTP3をダウンロードして、インストールする。さらに便利に使うためにPowerShell Community ExtensionsからPSCX 1.2をダウンロード・インストールする。

さて、これで準備が整った。因みに以下のテクニックは、Windows XP、Vista、Windows 7のどのOSでも使えると思う(ただし、確認したのはXPのみ)。

コマンドプロンプトからエクスプローラに移動する

以下のように起動するだけ。

ii .

エクスプローラからコマンドプロンプトに移動する

これは標準では難しいと思う。自分はエクスプローラの使い勝手には非常に不満を持っているので、ずいぶん前からWindowsではFileVisorを使っている。FileVisorであれば以下のコマンドをホットキーに登録しておくことで、現在のディレクトリをカレントディレクトリとして一発でPowerShellを開くことができる。

C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe -NoExit -Command Set-Location $P

カレントディレクトリを記憶し、あとで戻ってくる

これはそのまま、pushd .popdが使える。

2つのディレクトリを行ったり来たりする

これもほとんど一緒。

doskey /exename=powershell.exe d1=cd $pwd

一時的にネットワークドライブを割り当てる必要はない

PowerShellではcdでそのままネットワークをまたげるので必要ないと思う。

cd \\computer1\project1\program1

処理結果をクリップボードにコピーする

ocb (Out-Clipboard)を使う。

dir | ocb tree | ocb

因みに、gcb (Get-Clipboard)を使うことで、PowerShell上に貼り付けもできる。

gcb

ずれたインデントを修正する

これもあまり変わらない。

more.com /t4 hello.c

ページごとに止めずに、一気に出力する。

more.com /t4 hello.c | echo

簡単な計算をする

setコマンドは使う必要はなく、そのまま計算させるだけ。

10-20+30 20

(10+20)*30/50 18

0xFF 255

因みに、小数も扱える。また、10進→16進変換は以下のようにすればできる。

"{0:X}" -f 255 FF

ファイルのタイムスタンプを変更する

UNIXのtouchコマンドと全く同じで以下のようにする。

touch file.ext

因みに、以下のようにもできる。

dir file.ext | % { $_.lastwritetime = get-date }

コマンドプロンプトの色やサイズを調整する

背景色を変える。

$host.ui.rawui.backgroundcolor = "blue"

画面の大きさを幅120桁、高さ50行に変える。

$host.ui.rawui.windowsize = new-object system.management.automation.host.size(120, 50)

画面のバッファを幅120桁、高さ3000行に変える。

$host.ui.rawui.buffersize = new-object system.management.automation.host.size(120, 3000)

おわりに

これを機にPowerShellが流行るといいなぁ。Windows 7では標準で付いてくるしね。

続きを読む...

2009年8月26日水曜日

Google App Engineを利用してmixiアプリを作成する

このブログ記事をはてなブックマークに追加

最近、mixiアプリの正式版がリリースされたらしい。以前、オープンベータが始まったときにちょっと興味を抱いたのだが、そのまま忘れてしまっていた。しかし、この正式版リリースでまた興味が湧き、Google App Engine (GAE)と絡めてちょっといじってみたので、GAEを利用したmixiアプリの作成方法を説明してみようと思う。

まず、GAEを初めて利用する場合は、Google App Engine - Google Codeでアカウントを取得する。SDK一式を落としてきて使えるようにしておくこと。次に、mixiアプリを申請できるように、デベロッパー登録をしておこう。

さて、ここから本格的にmixiアプリを作成するわけだが、誰でも(自分を含めて)簡単に理解できるように「はじめてのmixiアプリ」の「Hello, world!」アプリケーションを元に作成することにした。

ところで、GAEを単なるファイル置き場として使うだけであれば、次のように設定すればいい。まず、作業ディレクトリにgadgetsディレクトリを作成して、そこにGadget XMLファイル(ここではhello.xmlとする)を置き、app.yamlのhandlersに以下の設定を追加する。

- url: /(.*\.xml) static_files: gadgets/\1 upload: gadgets/(.*\.xml)

これを、そのまま以下のコマンドでアップロードする。そして、mixiアプリ登録で、Gadget XMLファイルのURLを、http://アプリケーション名.appspot.com/hello.xmlのように指定するだけだ。

appcfg.py update アプリケーション名

しかし、ファイル置き場にするだけならば、GAEである必要はないわけで、ここではちゃんとGAEを利用した使い方を説明する。

Google App Engineを利用したmixiアプリ「Hello, world!」

GAEを利用するということで、「Hello, world!」アプリケーションの表示を「Hello, ユーザ名!」から、時間に応じた挨拶に変更してみる。朝なら「おはよう, ユーザ名!」、昼なら「こんにちは, ユーザ名!」、夜なら「こんばんは, ユーザ名!」という具合に。

まず、時間による挨拶の取得をGAEのPythonで以下のように実装する。

mixi_apps.py

#!/usr/bin/env python # -*- coding: utf-8 -*- import datetime import wsgiref.handlers from google.appengine.ext import webapp class Hello(webapp.RequestHandler): def get(self): greeting = u"こんにちは" H = (datetime.datetime.utcnow() + datetime.timedelta(hours=9)).hour if H >= 3 and H < 9: greeting = u"おはよう" elif H >= 9 and H < 18: greeting = u"こんにちは" elif H >= 18 or H < 3: greeting = u"こんばんは" self.response.headers["Content-Type"] = "text/plain; charset=utf-8" self.response.out.write(greeting) def main(): application = webapp.WSGIApplication([("/apps/hello", Hello)], debug=False) wsgiref.handlers.CGIHandler().run(application) if __name__ == "__main__": main()

このスクリプトをmixi_apps.pyという名前でGAEの作業ディレクトリに置く。そして、app.yamlのhandlersに以下を指定しておく。

- url: /apps/.* script: mixi_apps.py

アップロード後、http://アプリケーション名.appspot.com/apps/helloにアクセスし、「こんにちは」や「こんばんは」などのように表示されれば、正常に動作している。

次に上記で作成したプログラムを呼び出すように元のGadget XMLを修正する。外部サーバを呼び出すには、gadgets.io.makeRequest関数を利用する。使い方は実際に修正したファイルを見て貰った方が早いだろう。赤字で示している部分が元のファイルから修正したコードだ。

hello.xml

<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Hello, world!"> <Require feature="opensocial-0.8" /> </ModulePrefs> <Content type="html"><![CDATA[ <div><span id="greeting"></span>, <span id="target"></span>!</div> <script type="text/javascript"> function init() { var url = "http://アプリケーション名.appspot.com/apps/hello"; var params = {}; params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET; params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT; params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.NONE; gadgets.io.makeRequest(url, function(response) { document.getElementById("greeting").innerHTML = response.data; }, params); var req = opensocial.newDataRequest(); req.add(req.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), "viewer"); req.send(function(data) { var viewer = data.get("viewer").getData(); var name = viewer.getDisplayName(); document.getElementById("target").innerHTML = name; }); } gadgets.util.registerOnLoadHandler(init); </script> ]]></Content> </Module>

gadgets.io.makeRequest関数については、「外部サーバを呼び出してみよう」に詳しく出ているので詳細を知りたい方はこちらを参照して欲しい。

このように、Google App Engineを利用したmixiアプリは簡単に作ることができる。今回作成したアプリはGAEを使う必要がないような非常に単純なものだが、これを応用してもっと複雑で多種多様なアプリを作成することはそれほど難しいことではないと思う。

続きを読む...

2009年8月18日火曜日

HTTP CookieとFlash Cookieとで同期を行う

このブログ記事をはてなブックマークに追加

前回に引き続き、今回もCookie関連の記事だ。ITmediaユーザーが制御できない「秘密cookie」、半数強のサイトが利用という記事で、「ユーザーが削除したHTTP cookieを、Flash cookieを使って復活させているケース」があると書かれているが、技術的には簡単だ。

まず、HTMLのhead内にJavaScriptでdocument.cookieを設定・取得する関数を定義する。Flash (ActionScript 3.0)側では、flash.external.ExternalInterfaceを利用してHTTP Cookieを取得する。もし、取得できなければFlash Cookie (Local Shared Object, LSO)の取得を試みる。両方とも取得できない場合は、初めての利用と判断される。どちらか一方を取得できたのなら、もう一方に対して取得した値を渡す。これにより、どちらかが削除されたとしても再読み込みした際に、HTTP CookieとFlash Cookieとで同期され、削除されたデータは復元する。

異なるCookieの同期はデータの永続性を強固にする利点があるが、削除したつもりのデータが実は消えていないということも起こり得るわけで、セキュリティの面からするとあまり良くないかもしれない。これを防ぐためには、Cookieの制御に関する正しい知識を持つしかないだろう。前回の記事でも書いたが、Flash Cookieについてはグローバルストレージ設定パネルの「今後表示しない」を選択することで禁止することができる。既に書き込まれているFlash Cookieは、Webサイトの記憶領域設定パネルから、削除や禁止、ディスク容量の調整などが行える。また、HTTP Cookieについてはブラウザの設定で削除できる。

最後に、「ActionScript 3.0でFlash Cookieを利用する」で作成したプログラムを、HTTP CookieとFlash Cookieとで同期させるように変更してみたので、そのソースコードを以下に示しておく。赤字は前回からの修正箇所となる(クラス名などは除く)。使用する際は、HTMLのhead内に、

<script language="JavaScript" type="text/javascript"> function getCookie() { return document.cookie; } function setCookie(cookie) { document.cookie = cookie; } </script>

とJavaScriptのコードを記述しておくこと。

SyncCookie.as

// SyncCookie by nox, 2009.8.18 package { import flash.display.Sprite; import flash.text.* import flash.events.*; import flash.net.SharedObject; import flash.net.SharedObjectFlushStatus; import flash.external.ExternalInterface; [SWF(backgroundColor="0xffffff", width="300", height="100", framerate="30")] public class SyncCookie extends Sprite { [Embed(systemFont='MS P明朝', fontName='myFont', mimeType='application/x-font', unicodeRange='U+0030-U+0039,U+003F,U+2026,U+3044,U+304A-U+304B,\ U+304E,U+3053,U+3055,U+3057,U+3059,U+3066-U+3067,\ U+306A,U+306D-U+306F,U+307E,U+3081,U+3088-U+3089,\ U+308B,U+3092,U+4F1A,U+521D,U+56DE,U+62D2,U+72ED,\ U+76EE,U+79C1,U+7D76' )] private static const myFont:Class; private var textFormat:TextFormat = new TextFormat(); private var textField:TextField = new TextField(); private var mySharedObject:SharedObject; private function InputChar(event:KeyboardEvent):void { if (event.keyCode == 27) mySharedObject.clear(); textField.text = "さよなら…"; } public function SyncCookie() { textFormat.color = 0x000000; textFormat.size = 30; textFormat.font = "myFont"; textFormat.align = "center"; textField.defaultTextFormat = textFormat; textField.antiAliasType = flash.text.AntiAliasType.ADVANCED; textField.autoSize = TextFieldAutoSize.CENTER; textField.selectable = true; textField.embedFonts = true; var str:String; var count:int = 1; var allcookies:String = ExternalInterface.call("getCookie").toString(); var pos:int = allcookies.indexOf("SyncCookie="); if (pos != -1) { var start:int = pos + 11; var end:int = allcookies.indexOf(";", start); if (end == -1) end = allcookies.length; count = int(allcookies.substring(start, end)); mySharedObject = SharedObject.getLocal("SyncCookie"); mySharedObject.data.count = ++count; str = "お会いするのは\n"; str += count.toString(); str += "回目ですね"; textField.text = str; } else { try { mySharedObject = SharedObject.getLocal("SyncCookie"); var flushStatus:String = mySharedObject.flush(); if (flushStatus == SharedObjectFlushStatus.FLUSHED) { if (mySharedObject.data.count) { mySharedObject.data.count += 1; count = mySharedObject.data.count; str = "お会いするのは\n"; str += mySharedObject.data.count.toString(); str += "回目ですね"; textField.text = str; } else { mySharedObject.data.count = 1; textField.text = "初めてお会いしますね"; } } else { textField.text = "ここは狭すぎます…"; } } catch (e:Error) { textField.text = "私を拒絶するのですか?"; } } ExternalInterface.call("setCookie", "SyncCookie=" + count.toString()); textField.x = stage.stageWidth / 2 - textField.textWidth / 2; textField.y = stage.stageHeight / 2 - textField.textHeight / 2; stage.addEventListener(KeyboardEvent.KEY_DOWN, InputChar); addChild(textField); } } }

続きを読む...

2009年8月14日金曜日

ActionScript 3.0でFlash Cookieを利用する

このブログ記事をはてなブックマークに追加

ユーザーが制御できない「秘密cookie」、半数強のサイトが利用というITmediaの記事を読んで、実際どの程度のものかを理解するためにActionScript 3.0でFlash Cookieを利用してみた。因みに、ここで言う秘密CookieやFlash Cookieはローカル共有オブジェクト(Local Shared Object, LSO)と呼ばれるもので、Flash PlayerがユーザーのPCに保存するデータのことだ。

早速、ActionScript 3.0でLSOを利用したFlashコンテンツを作成してみた。作成するに当たって、ActionScript 3.0コンポーネントリファレンスガイドSharedObjectを参考にした。

プログラムはコンテンツを読み込んだ回数をLSOに保存する。初めてコンテンツを読み込んだ場合は、「初めてお会いしますね」と表示され、2回目以降は「お会いするのは2回目ですね」のように表示される。また、LSOの保存領域が保存するデータよりも小さい場合は「ここは狭すぎます…」、保存が禁止されている場合は「私を拒絶するのですか?」と出力される。保存したデータを削除する場合は、エスケープキーを押すことで「さよなら…」と出て削除される。

LSOの制御方法だが、グローバルストレージ設定パネルの「今後表示しない」を選択することでLSOを禁止することができる。また、ディスク容量を0KBにすると、禁止はされないが容量不足により書き込みができなくなる。既に書き込まれているLSOについては、Webサイトの記憶領域設定パネルにより、削除や禁止、ディスク容量の調整などが行える。

Flash Cookie、そこまで騒ぎ立てるほどのものではないと思うが、気になる人は設定で禁止なり削除なりすればよいと思う。コンテンツ制作者側からすれば便利なのは確か。

以下、ソースコード。

SharedObjectTest.as

// SharedObjectTest by nox, 2009.8.14 package { import flash.display.Sprite; import flash.text.* import flash.events.*; import flash.net.SharedObject; import flash.net.SharedObjectFlushStatus; [SWF(backgroundColor="0xffffff", width="300", height="100", framerate="30")] public class SharedObjectTest extends Sprite { [Embed(systemFont='MS P明朝', fontName='myFont', mimeType='application/x-font', unicodeRange='U+0030-U+0039,U+003F,U+2026,U+3044,U+304A-U+304B,\ U+304E,U+3053,U+3055,U+3057,U+3059,U+3066-U+3067,\ U+306A,U+306D-U+306F,U+307E,U+3081,U+3088-U+3089,\ U+308B,U+3092,U+4F1A,U+521D,U+56DE,U+62D2,U+72ED,\ U+76EE,U+79C1,U+7D76' )] private static const myFont:Class; private var textFormat:TextFormat = new TextFormat(); private var textField:TextField = new TextField(); private var mySharedObject:SharedObject; private function InputChar(event:KeyboardEvent):void { if (event.keyCode == 27) mySharedObject.clear(); textField.text = "さよなら…"; } public function SharedObjectTest() { textFormat.color = 0x000000; textFormat.size = 30; textFormat.font = "myFont"; textFormat.align = "center"; textField.defaultTextFormat = textFormat; textField.antiAliasType = flash.text.AntiAliasType.ADVANCED; textField.autoSize = TextFieldAutoSize.CENTER; textField.selectable = true; textField.embedFonts = true; try { mySharedObject = SharedObject.getLocal("SharedObjectTest"); var flushStatus:String = mySharedObject.flush(); if (flushStatus == SharedObjectFlushStatus.FLUSHED) { if (mySharedObject.data.count) { mySharedObject.data.count += 1; var str:String; str = "お会いするのは\n"; str += mySharedObject.data.count.toString(); str += "回目ですね"; textField.text = str; } else { mySharedObject.data.count = 1; textField.text = "初めてお会いしますね"; } } else { textField.text = "ここは狭すぎます…"; } } catch (e:Error) { textField.text = "私を拒絶するのですか?"; } textField.x = stage.stageWidth / 2 - textField.textWidth / 2; textField.y = stage.stageHeight / 2 - textField.textHeight / 2; stage.addEventListener(KeyboardEvent.KEY_DOWN, InputChar); addChild(textField); } } }

続きを読む...

2009年8月5日水曜日

Scratchで素数を求めてみた

このブログ記事をはてなブックマークに追加

小学生にプログラミングの楽しさを伝えてみた」を読んで、プログラミング言語Scratch(スクラッチ)にとても興味を覚えた。そこで、子供たちに使わせて、その様子でも見てみようかと思ったんだけど、使わせる前にまず自分で試すべきだと考え、簡単なプログラムを作ったところ、これがまた面白い。どういう面白さかというと、小さい頃に遊んだレゴブロックみたいな感じ。ブロックで巨大ロボットを作ったあの感覚。それに、プログラムの要素がタイルになっていて、それをピタピタと貼り付けるんだけど、これもかなり気持ちいい。

で、単なるお試しのつもりで100までの素数を求めるプログラムを作ったんだけど、前回のエントリ「4ビットマイコンで素数を求めてみた」との対比が面白くて、思わずブログ記事にしてしまった。一方は機械が透けて見えるアセンブリ言語によるLED表示で、もう一方はコンピュータと言うよりレゴブロック(?)に近いScratchによるYouTubeライクなアニメーション。同じ素数を求めるプログラムと言っても、ここまで違うと何だか妙な感じだ。

ネコのキャラクターをクリックすると開始。※音が出るので注意 このプロジェクトについてもっと知る

ところで、素数を求めるプログラムを作った理由だけど、自分にとってそれがHello worldプログラムのようなものだから。"Hello, world!"なんて画面に出しただけじゃその言語のことはほとんど分からないからね。因みに、Scratchのプログラムの方では、ちょっとだけ遊びを入れてみた。ナベアツプログラムを真似て、一の位が 9 の時だけネコがちょっとリアル(?)になる。

また、Scratchでは作成したプログラムをYouTubeのように簡単にウェブ上で共有できる。しかも、Scratch上からボタン一つという手軽さだ。さらに、そのプログラムをブログなどに貼り付けることもできる。ただ、Scratch上で日本語を表示するのは問題ないのだが、ウェブにアップロードしたものは文字化けをしてしまうようなのでこの点だけ注意して欲しい。あと、この記事に作成したプログラムを貼り付けておいた。実行するにはネコのキャラクターをクリックすればいい。音が出るので注意すること。

ところで、現時点での最新版であるScratch 1.4では、剰余の計算のところが間違っていて、「AをBで割った余り」のAとBが逆になっている。つまり、「10を7で割った余り」の答えが7になってしまう。正しく3と計算させるためには「7を10で割った余り」としなくてはならない。もっとも、これを直すのは簡単で、Scratchをインストールしたディレクトリにあるlocaleディレクトリのja.poファイルの「msgstr "%n2 を %n1 で割った余り"」を「msgstr "%n を %n で割った余り"」に変更するだけだ。因みに、メニューの地球アイコンで漢字をひらがなに変更できるが、こちらは特に問題はない。

以下に、ソースコードを掲載しておく。


追記(2009/8/5):

[Squeak-ja: 4297] Scratch 1.4の日本語翻訳ファイルの誤りについて

Scratchを日本語翻訳されている方からのコメントで、修正ファイルの情報を教えて頂いた。上記のリンク先から入手できる。また、次期バージョンでは修正されるとのこと。

続きを読む...

2009年8月3日月曜日

4ビットマイコンで素数を求めてみた

このブログ記事をはてなブックマークに追加

最近、大人の科学マガジン4ビットマイコン(GMC-4)が付いていると聞いて早速購入してみたのだが、ここまで面白いものだとは思わなかった。本物のコンピュータが付いて2,500円というのもの非常にリーズナブルだ。自分は純粋に楽しめたが、教育用に使うのも良さそうだ。雑誌自体はかなり薄い作りだが、内容はとても興味深いものだった。コンピュータの歴史から、ハードの仕組み、インタビュー、4ビットマイコンの説明など。読んでいるだけでワクワクする。

付録の4ビットマイコンにはGMC-4という名前が付いているが、これはGakken Micro Computerの略なんだそうだ。メモリはかなり貧弱で、プログラムメモリで00~4F番地まで、データメモリで50~5F番地までしかない。しかも、それぞれの番地は4ビットしか情報量を持たない。つまり1バイトを8ビットとすると、プログラムメモリで40バイト、データメモリで8バイトしかない。また、レジスタは補助レジスタをあわせて8種類あるが、同時に扱えるレジスタはAレジスタとYレジスタしかない。しかし、これだけの制約があると逆に挑戦してやろうと思ってしまうから不思議だ。

そこで、今回は素数を求めるプログラムを作ってみることにした。最初に考えた方法は、求めた素数をメモリに保存し、その素数を使って新たな素数を求めていくものだった。しかし、当然のように除算命令などないし、メモリが貧弱のため、求めた素数を取り置くのも難しい。そこで、求めた素数は使わずに、素数候補の数値を奇数で割っていき、その奇数が素数候補となるまで割り切れなければ素数とした。ここでは「割る」と書いたが、プログラム上では素数候補から奇数を引いていき、0になれば割り切れるとしている。このようにして求めた素数は数字LEDにそれぞれ一秒間表示される。今回は3~15(F)までの素数を求めた。それほど難しいプログラムであるわけでもないのに、数字LEDに3, 5, 7, b(11), d(13)と順次表示されるのを確認したときには妙に嬉しくなった。

久々のハンドアセンブルであったが、非常に楽しいものだった。当時もこのようにして夢中になったことを思い出した。もっとも、今回の4ビットマイコンは当時のZ80と比べてもかなり貧弱な環境だったが。素数を求めるプログラムもプログラムメモリ領域ぎりぎりの40バイトを全部使った。もう少し効率よく書けるかもしれないけど、プログラムの入力だけでも結構な手間なので取り敢えずこのままで。

最後に、今回作成したプログラムを掲載しておく。

00 TIA 8 ; Aレジスタ(Ar)に3を代入. 素数候補用. 01 <3> 3 02 TIY A ; Yレジスタ(Yr)に0を代入. 03 <0> 0 04 AM 4 ; 50番地のメモリ(M[0])にArを代入. 素数を入れておく. LABEL1: 05 AO 1 ; LEDに素数を表示. 06 TIA 8 ; ウェイトを1秒に設定. 07 <9> 9 08 CAL E 09 TIMR C ; ウェイト. 0A MA 5 ; ArにM[0]を代入. Arに素数を入れ直す. LABEL2: 0B AIA 9 ; Arに2を足す. 素数は奇数のみ. 0C <2> 2 0D AM 4 ; M[0]にArを代入. 新たな素数. 0E CIA C ; ArがF(15)か? 0F <F> F 10 JUMP F ; ArがF(15)でないなら LABEL3 に飛ぶ. 11 <1> 1 12 <6> 6 13 JUMP F ; ArがF(15)なら END に飛ぶ. 14 <4> 4 15 <D> D LABEL3 16 TIA 8 ; Arに3を代入. 素数チェック用の数値の初期値. 奇数. 17 <3> 3 LABEL4 18 TIY A ; Yrに1を代入. 19 <1> 1 1A AM 4 ; M[1]にArを代入. 素数チェック用数値. 1B TIY A ; Yrに0を代入. 1C <0> 0 1D MA 5 ; ArにM[0]を代入. 素数候補. 1E TIY A ; Yrに1を代入. 1F <1> 1 20 M- 7 ; Arに M[1] - Ar を代入. 21 JUMP F ; Arが負の数なら LABEL5 に飛ぶ. 素数ではない. 22 <2> 2 23 <A> A 24 TIY A ; Yrに0を代入. 25 <0> 0 26 MA 5 ; M[0]にArを代入. 素数候補をArに戻す. 27 JUMP F ; Arが正の数なら LABEL1 に飛ぶ. 素数が見つかった. 28 <0> 0 29 <5> 5 LABEL5: 2A TIY A ; Yrに0を代入. 2B <0> 0 2C MA 5 ; ArにM[0]を代入. 素数候補をArに戻す. 2D TIY A ; Yrに1を代入. 2E <1> 1 LABEL6: 2F M- 7 ; Arに M[1] - Ar を代入. 30 JUMP F ; Arが負の数なら LABEL7 に飛ぶ. 31 <3> 3 32 <E> E 33 CIA C ; Arが0か? 34 <0> 0 35 JUMP F ; Arが0でないなら LABEL8 に飛ぶ. 36 <4> 4 37 <6> 6 38 TIY A ; Yrに0を代入. 39 <0> 0 3A MA 5 ; ArにM[0]を代入. 素数候補をArに戻す. 3B JUMP F ; LABEL2 3C <0> 0 3D <B> B LABEL7: 3E CAL E 3F CMPL 4 ; Arをビット反転. 40 AIA 9 ; Arに1を足す. 負の数を正の数に変換. 2の補数. 41 <1> 1 42 KA 0 ; 実行フラグを1にするため. 43 JUMP F ; LABEL6 に飛ぶ. 44 <2> 2 45 <F> F LABEL8: 46 MA 5 ; ArにM[1]を代入. 素数チェック用の数値をArに戻す. 47 AIA 9 ; Arに2を足す. 次の素数チェック用の数値. 48 <2> 2 49 KA 0 ; 実行フラグを1にするため. 4A JUMP F ; LABEL4 に飛ぶ. 4B <1> 1 4C <8> 8 END: 4D JUMP F ; 終了後は無限ループ. 4E <4> 4 4F <D> D

続きを読む...