Tweet
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
- Newer: 初めてのPerl:ディレクトリ内のhtmlファイルに含まれる英単語数を数える(ついでにgoogleのapiで翻訳)
- Older: GoogleのTwitter初発言をJavaScriptで読めるように
Home > > ActionScript再挑戦!Flexで人工無脳作ってみた
Tweet
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
Home > > ActionScript再挑戦!Flexで人工無脳作ってみた
Home > Flash・Flex・AS > ActionScript再挑戦!Flexで人工無脳作ってみた
Tweet
2009/06/20 20:10
誤字脱字修正。
2009/03/06 22:45
htmlのソースとプロジェクトファイル一式を追加しました。
たぶん、今までで一番長文です。
1年以上前に書いた、
・ Hello, Flash!:ActionScriptを初めて使ってみたらお絵かきが簡単にできてびっくりした - Born Neet
は今だに僕のブログで一番の人気記事です。
(HolyGrailさんのおかげでしょうが…)
にもかかわらず、それから一年以上ASの話題を扱わないという体たらく。
(地味に勉強してたりはしたんですが、記事にするまでにはいたりませんでした。)
というわけで改めて学びなおすべく、新しい言語の学習にはもってこい(?)の人工無脳を作ってみました。
以下に手順をメモしますので興味があればどうぞ。
ソースのライセンスも(使用ライブラリに合わせて)修正BSDにしとくのでご自由に。
前やった時は、FlexのFの字もわかってなかったのでたいした説明はできませんでしたが、
今回は本読んだり、(だいぶ前ですが)セミナーに行ったりもしてたのでいくらかはマシだと思います。
Flexは、Flashの技術を利用したリッチインターネットアプリケーション(RIA)です。
Flexならデザインセンスのカケラもない僕でも、プログラミングするだけでFlash Player上で動くアプリケーションを作ることができるのです。
と、僕は理解してます。
まぁ細かい定義なんかはどうでもよくて、FlashPlayerがあればどこでも同じように動く、
つまり、「Firefoxで開発→IEで確認→動かない→直す→Firefoxで変に」みたいなことをしなくて済むのです。
ということで僕は勝手にFlexはRIAの本命なんじゃないかと思ってます。
まずは環境を整えます。
やったのは半年以上前なので抜けてるかもしれません。
開発には、FlashDevelopを使います。
補完がないときついので。(テキストエディタでJavaを開発するぐらいのしんどさです)
というわけで、以下のサイトあたりを参考にFlex SDKとFlashDevelopを(ないならJavaも)インストール。
(自分が参考にしたサイトは忘れちゃったので適当に検索しました。)
・ Adobe Flex SDK超入門 (treasuring misc.)
・ フリーのFlash統合開発環境 FlashDevelop (+flex 3 SDK)を入れてみました:■ 音楽方丈記 ■
他にも情報は山ほどあるのでここは省略。
Flashはどうやって作ってるのかさっぱりわかりませんが、
FlexはWebプログラマにとって非常にわかりやすい構造です。
(カッコ内参照)
作成するファイルは以下の3つ。
・ mxml(htmlの役目)
・ ActionScript(JavaScriptの役目)
・ CSS(そのまま)
HTMLベースのアプリと同様に、
mxmlで構造、ASでイベント等を設定、CSSで装飾します。
さらにASとJSは型とclassがあること意外ほとんど同じなので、
mxmlだけ覚えればもう何でも作れちゃうのです!
(実際は以前の僕の記事のようにmxmlなしでも作れますが…)
さて、そろそろ飽きてきましたが。。。
FlashDevelopは高機能なので初めて使う時若干とまどいます。
特に新規プロジェクト作成の選択肢が多すぎる!
ってことで僕の作成手順を書いときます。
1. AS3のEmptyProject(なんか2個あるけど上の方)を選択
・ Nameは適当(一応ラクダ文字が規則みたい)
・ packageは空で
これで余計なものが何もない空のプロジェクトが作られます。
2. Projectの箱を右クリックしてmxmlを追加
さらに
・ 追加したmxmlを右クリックしてAlwaysCompileにチェック
・ プロジェクトのプロパティ(右クリック or メニューから)で
「No output~」のチェックを外し、ファイル名を適当に入力
FlashDevelopがちゃんとインストールされていれば、
これでコンパイルでき、Flashでおなじみのswfファイルが作成されるはずです。
(参考サイトにもありますが、External Playerの設定大事)
あとはASなりCSSなりサブのmxmlなりをガシガシ追加していくだけです。
もう駄目だ…長文すぎる…。
というわけで、ソース以外はこれで最後です。
Flashを公開する時はHTMLに埋め込むことになります。
しかしこれが、objectタグやらembedタグやら実にややこしい。
そこで、swfobjectです。
このライブラリを使えばid指定とjs1行で済みます。
詳しくは、
・ 八角研究所 : FlashをHTMLに貼るライブラリ swfobject 2 を使う
・ SWFObject v2.0 ドキュメント日本語訳 : Media Technology Labs (MTL) : メディアテクノロジーラボ ブログ
・ nondelion.com - 続・swfobject で flash を Window 内に全画面表示
等をどうぞ。
ようやく本題です。
もう説明する気力は残ってないのでコメントを参照してください。
僕の試行錯誤の結果です…。
動くサンプルはここに置いときます→Flexで人工無能 - tnantoka.net
(はじめは空っぽですが、会話を覚えていきます。
またstudyタブからテキストをaddすれば賢くなるかもしれません。)
プロジェクトファイル一式も置いとくのでどうぞ。
画面構造
<?xml version="1.0" encoding="utf-8"?>
<!--
Applicationにwidth,heightを設定すれば、-config.xmlをいじらなくても大きさ指定できる
creationCompleteはwindow.onload的存在(as内からは設定できないので属性で)
-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
<!-- as,css外部ファイル化 -->
<mx:Script source="init.as"/>
<mx:Style source="style.css"/>
<!-- 大枠 -->
<mx:Panel width="100%" height="100%" title="Flexで人工無脳" horizontalAlign="center">
<!--
タブ切り替え
creationPolicy="all"にしないと初期化時にイベント設定できない
-->
<mx:ViewStack id="viewStack" width="100%" height="100%" creationPolicy="all">
<!-- 会話画面 -->
<mx:VBox label="talk" horizontalAlign="center">
<mx:HBox width="70%">
<mx:TextInput width="90%" id="msgInput" />
<mx:Button label="send" id="sendButton" />
</mx:HBox>
<mx:TextArea width="70%" height="85%" id="historyArea"></mx:TextArea>
</mx:VBox>
<!-- 学習画面 -->
<mx:VBox label="study" horizontalAlign="center" styleName="study">
<mx:TextArea width="70%" height="87%" id="sourceArea"></mx:TextArea>
<mx:HBox width="70%">
<mx:Button label="init" id="initButton" />
<mx:Spacer width="100%"/>
<mx:Button label="add" id="addButton" />
</mx:HBox>
</mx:VBox>
</mx:ViewStack>
<!-- タブメニュー(各要素のlabelがタブに) -->
<mx:LinkBar dataProvider="{viewStack}"/>
</mx:Panel>
</mx:Application>
イベントを設定したり、Munouクラスを使ったり。
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import mx.events.FlexEvent;
import mx.rpc.http.HTTPService;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.controls.Alert;
// グローバル使わないために関数内で処理
private function init():void {
var munou:Munou;
// テキストを読み込んで学習
// XMLHttpRequest同様に使える
var http:HTTPService = new HTTPService();
http.url = 'test.txt';
http.resultFormat = 'text'; // デフォルトはXML
// 成功
http.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
// munou = new Munou(event.result as String);
munou = new Munou(''); // 今回は白紙で
});
// 失敗
http.addEventListener(FaultEvent.FAULT, function(event:FaultEvent):void {
Alert.show(event.fault.faultString);
});
http.send();
// sendクリックで話しかける
sendButton.addEventListener(MouseEvent.CLICK, send);
// エンター押下にも同じイベント設定
msgInput.addEventListener(FlexEvent.ENTER, send);
// 初期化
initButton.addEventListener(MouseEvent.CLICK, function(event:Event):void {
//
munou.init(sourceArea.text);
sourceArea.text = '';
});
// 覚えさせる
addButton.addEventListener(MouseEvent.CLICK, function(event:Event):void {
if (sourceArea.text) {
munou.learn(sourceArea.text);
sourceArea.text = '';
}
});
// 話しかける
function send(event:Event):void {
var msg:String = msgInput.text;
// ちょっとだけhtmlが使える
historyArea.htmlText += '<p>あなたの発言:<br/>\t' + msg + '</p>';
historyArea.htmlText += '<p><font color="#0000ff">munouの発言:<br/>\t' + munou.response(msg) + '</font></p>';
msgInput.text = '';
// スクロールバーを最終行に設定
// (遅延実行?しないと更新前の位置になる)
callLater(function():void {
historyArea.verticalScrollPosition = historyArea.maxVerticalScrollPosition;
});
}
// かぎカッコ内のテキストを抽出(不使用)
function getTalk(text:String):String {
var talk:Array = text.match(/「[^」]+?」/g);
for(var i:int = 0; i < talk.length; i++) {
talk[i] = talk[i].replace(/[「\s 」]+/g, '');
}
return talk.join('\n');
}
} // init
人工無脳(簡易形態素解析+マルコフ連鎖)で会話するclassです。
/**
* 人工無脳(簡易形態素解析+マルコフ連鎖)で会話するClass
*/
package {
// import org.coderepos.text.TinySegmenter; // CodeRepos
import uwi.tinysegmenter.TinySegmenter; // SparkProject
// mxml名と被るとダメ
public class Munou {
// 文頭・文末識別子
private const START:String = '__START__';
private const END:String = '__END__';
// 初期化テキストを一応保存
private var text:String;
// 形態素解析マシン
private var segmenter:TinySegmenter;
// 学習した結果
private var dic:Object;
// コンストラクタ
public function Munou(text:String) {
this.text = text;
segmenter = new TinySegmenter();
init(text);
}
// 初期化
public function init(text:String):void {
dic = {};
learn(text);
}
// 学習
public function learn(text:String):void {
if (text) {
// スペース・タブは1字に圧縮
// 改行で区切る(スペース・タブは残したいので\sは使わず)
// そのほかの記号は無視
var a:Array =
text.replace(/([ \t])+/g, '$1')
.split(/[\r\n]+/);
// Vistaならtraceログは以下に
// C:\Users\<user>\AppData\Roaming\Macromedia\Flash Player\Logs
// trace(a.join(','));
for (var i:int = 0; i < a.length; i++) {
var b:Array = morph(a[i]);
trace(b.join('|'));
b.unshift(START);
b.push(END);
for (var j:int = 0; j < b.length - 1; j++) {
var s:String = b[j];
if (dic[s]) dic[s].push(b[j + 1])
else dic[s] = [b[j + 1]];
}
}
}
}
// 形態素解析
private function morph(text:String):Array {
return segmenter.segment(text);
}
// マルコフ連鎖で文章作成
private function markov(text:String):String {
if (!dic[START]) return '';
var s:String = dic[START][Math.floor(Math.random() * dic[START].length)];
var r:String = '';
while (s != END) {
r += s;
// 文末っぽい記号が出ても終了
if (s.match(/[。!!??]/)) break;
s = dic[s][Math.floor(Math.random() * dic[s].length)];
}
return r;
}
// 応答
public function response(msg:String):String {
var func:Function;
learn(msg);
// 今回はマルコフのみで
// switch(Math.floor(Math.random() * 10)) {
// 1/10の確立でオウム返し
// case 0:
// func = echo;
// break;
// 1/10の確立で定型応答
// case 1:
// func = random;
// break;
// その他はマルコフで
// default:
func = markov;
// }
return func(msg);
}
// オウム返し(不使用)
private function echo(msg:String):String {
return msg;
}
// ランダム応答(不使用)
private function random(msg:String):String {
var a:Array = [
'',
];
return a[Math.floor(Math.random() * a.length)];
}
// 初期化テキスト表示(不使用)
public function getText():String {
return text;
}
} // class
} // package
見た目を調整。
htmlほど自由には設定できません。
@charset "UTF-8";
Application {
background-color: #fff;
/* width: 300px; 効かない */
}
Panel {
/* width: 100%; %指定はエラー */
/* padding: 10px; 効かない */
padding-top: 20px;
padding-bottom: 20px;
}
HBox {
/* text-align: center; TextInputの中身がセンタリングされちゃう */
padding-top: 10px;
padding-bottom: 10px;
}
.study {
padding-top: 10px;
}
swfを全画面表示
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Flexで人工無脳 - tnantoka.net</title>
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" type="text/css" href="style.css" media="all" />
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF('Munou.swf', 'swfArea', '100%', '100%', '9.0.0');
</script>
<style type="text/css">
/* for Firefox */
html, body {
height: 100%;
}
html {
overflow: hidden;
}
/* common */
body {
margin: 0;
}
</style>
</head>
<body>
<div id="swfArea" style="width: 100%; height: 100%;">
</div>
</body>
</html>
だいぶ前に読んだ時はイマイチと思ったんだけど、
(AIRプログラミング入門と内容を使い回しすぎだし)
今回作るにあたってリファレンスとして結構役に立った。
初Flexのお供に是非。
ホントはFlex3.0SDKで学ぶActionScript3.0入門が欲しかったんだけど、
どこにもないので(発売後1年足らずなのに…)しかたなく、同じくFlex SDK(Builderではなく)で作るこの本を購入。
(安さにつられたわけじゃ…)
プログラミング初心者用の本のため、他言語の経験者にはあまり向かない。
僕はE4Xを触ったことがなかったので多少はためになりました。
(本は対象読者を見てから買いましょう、ですね!)
あと、ところどころに、ん?と思う説明が。。。
関数名だけで利用される関数をクロージャともいいます(p.168)
…いいません!(笑)
とかね。
・ TextArea自動スクロール
FirefoxのTextAreaと同じくtextを追加するとスクロールバーが先頭に戻っちゃう対策。
・ [Air/Flex]ViewStackの落とし穴 - 秘密結社ぎゅう☆ぎゅう倶楽部
スムーズな画面遷移と引き換えにイベント設定ができなくなるとか…。
・ たまご日記(別館) [flex] テキストの改行が余分に付く
改行の扱いにわりと苦労させられました。
・ /air/TLife/src/uwi/tinysegmenter/TinySegmenter.as - Spark project
・ /lang/actionscript/as3tinysegmenter/src/org/coderepos/text/TinySegmenter.as -- CodeRepos::Share -- Trac
TinySegmenterのAS移植版。
僕はなんとなくSparkProjectの方を使ってます。
Home > Flash・Flex・AS > ActionScript再挑戦!Flexで人工無脳作ってみた