忍者ブログ

Home > > ActionScript再挑戦!Flexで人工無脳作ってみた

[PR]

  • 2024-04-27

Share on Tumblr このエントリーをはてなブックマークに追加

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

Comments:

Trackback+Pingback:

Listed below are links to weblogs that reference
[PR] from Born Neet

Home > > ActionScript再挑戦!Flexで人工無脳作ってみた

Home > Flash・Flex・AS > ActionScript再挑戦!Flexで人工無脳作ってみた

ActionScript再挑戦!Flexで人工無脳作ってみた

Share on Tumblr このエントリーをはてなブックマークに追加

2009/06/20 20:10
 誤字脱字修正。

2009/03/06 22:45
 htmlのソースとプロジェクトファイル一式を追加しました。

たぶん、今までで一番長文です。

1年以上前に書いた、
 ・ Hello, Flash!:ActionScriptを初めて使ってみたらお絵かきが簡単にできてびっくりした - Born Neet
は今だに僕のブログで一番の人気記事です。
HolyGrailさんのおかげでしょうが…)

にもかかわらず、それから一年以上ASの話題を扱わないという体たらく。
(地味に勉強してたりはしたんですが、記事にするまでにはいたりませんでした。)

というわけで改めて学びなおすべく、新しい言語の学習にはもってこい(?)の人工無脳を作ってみました。

以下に手順をメモしますので興味があればどうぞ。
ソースのライセンスも(使用ライブラリに合わせて)修正BSDにしとくのでご自由に。

前やった時は、FlexのFの字もわかってなかったのでたいした説明はできませんでしたが、
今回は本読んだり、(だいぶ前ですが)セミナーに行ったりもしてたのでいくらかはマシだと思います。

Flexとは

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)を入れてみました:■ 音楽方丈記 ■

他にも情報は山ほどあるのでここは省略。

Flexプログラミング入門

Flashはどうやって作ってるのかさっぱりわかりませんが、
FlexはWebプログラマにとって非常にわかりやすい構造です。
(カッコ内参照)

作成するファイルは以下の3つ。

 ・ mxml(htmlの役目)
 ・ ActionScript(JavaScriptの役目)
 ・ CSS(そのまま)

HTMLベースのアプリと同様に、
mxmlで構造、ASでイベント等を設定、CSSで装飾します。

さらにASとJSは型とclassがあること意外ほとんど同じなので、
mxmlだけ覚えればもう何でも作れちゃうのです!
(実際は以前の僕の記事のようにmxmlなしでも作れますが…)

FlashDevelopのプロジェクトの作り方

さて、そろそろ飽きてきましたが。。。

FlashDevelopは高機能なので初めて使う時若干とまどいます。
特に新規プロジェクト作成の選択肢が多すぎる!

ってことで僕の作成手順を書いときます。

 1. AS3のEmptyProject(なんか2個あるけど上の方)を選択
   ・ Nameは適当(一応ラクダ文字が規則みたい)
   ・ packageは空で
   これで余計なものが何もない空のプロジェクトが作られます。

 2. Projectの箱を右クリックしてmxmlを追加
   さらに
   ・ 追加したmxmlを右クリックしてAlwaysCompileにチェック
   ・ プロジェクトのプロパティ(右クリック or メニューから)で
    「No output~」のチェックを外し、ファイル名を適当に入力

FlashDevelopがちゃんとインストールされていれば、
これでコンパイルでき、Flashでおなじみのswfファイルが作成されるはずです。
(参考サイトにもありますが、External Playerの設定大事)

あとはASなりCSSなりサブのmxmlなりをガシガシ追加していくだけです。

SWFObject

もう駄目だ…長文すぎる…。
というわけで、ソース以外はこれで最後です。

Flashを公開する時はHTMLに埋め込むことになります。
しかしこれが、objectタグやらembedタグやら実にややこしい。

そこで、swfobjectです。
このライブラリを使えばid指定とjs1行で済みます。

詳しくは、

 ・ 八角研究所 : FlashをHTMLに貼るライブラリ swfobject 2 を使う
 ・ SWFObject v2.0 ドキュメント日本語訳 : Media Technology Labs (MTL) : メディアテクノロジーラボ ブログ
 ・ nondelion.com - 続・swfobject で flash を Window 内に全画面表示

等をどうぞ。

Flexな人工無脳

ようやく本題です。
もう説明する気力は残ってないのでコメントを参照してください。

僕の試行錯誤の結果です…。

動くサンプルはここに置いときます→Flexで人工無能 - tnantoka.net
(はじめは空っぽですが、会話を覚えていきます。
またstudyタブからテキストをaddすれば賢くなるかもしれません。)

プロジェクトファイル一式も置いとくのでどうぞ。

Main.mxml

画面構造

<?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>

init.as

イベントを設定したり、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

Munou.as

人工無脳(簡易形態素解析+マルコフ連鎖)で会話する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

style.css

見た目を調整。
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;
}

index.html

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>

読んだ本

photo
Flex3プログラミング入門
宮田 亮
秀和システム 2008-08
おすすめ平均 star
star思わず続編を探してしまいました。
starこれからFlexを触る方へ

by G-Tools , 2009/03/04

だいぶ前に読んだ時はイマイチと思ったんだけど、
AIRプログラミング入門と内容を使い回しすぎだし)
今回作るにあたってリファレンスとして結構役に立った。
初Flexのお供に是非。

photo
ActionScript3.0のドリル (Workbook in Programming)
佐藤 信正
ソシム 2009-02

by G-Tools , 2009/03/04

ホントは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の方を使ってます。

PR

Comments:0

Comment Form

Trackback+Pingback:

TrackBack URL for this entry
Listed below are links to weblogs that reference
ActionScript再挑戦!Flexで人工無脳作ってみた from Born Neet

Home > Flash・Flex・AS > ActionScript再挑戦!Flexで人工無脳作ってみた

Search
Loading
Feeds
Links
スポンサードリンク

Page Top