忍者ブログ

Home

Born Neet

[PR]

  • 2025-02-26 (Wed)
×

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

  • Comments (Close):
  • TrackBack (Close):

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

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

GoogleのTwitter初発言をJavaScriptで読めるように

遅い(※)。しかもしょうもない。
が、自分が読むために作っちゃったので公開しとく。
※ googleがじゃなく僕がブログのネタにするのが…ね、一応。

2進表記を文字に直すのは、

String.fromCharCode(parseInt('01100110', 2)); // f

でOK。

というわけで、Googleの発言を読めるようにしましょう。




できました。

答えは…
最近何かと話題のGoogle日本のトップ画面からいつのまにか消え去ったあの機能です。

あぁあのシンプルな画面がなつかしい。

一応ソース

<textarea id="decodeGoogle" cols="30" rows="3"></textarea><br />
<input type="button" value="変換" onclick="(function(){ 
var chars = document.getElementById('decodeGoogle').value.split(/\s/);
for(var i = 0; i < chars.length; i++) {
	if (!isNaN(chars[i])) chars[i] = String.fromCharCode(parseInt(chars[i], 2));
	else chars[i] = chars[i] + ' ';
}
document.getElementById('decodeGoogle').value = chars.join('');
 })()" />

以上です。

WEB+DB PRESSを1000円引きで定期購読(ブロガー限定!?)

WEB+DB PRESS (ウェブDBプレス)(技術評論社) WEB+DB PRESS

出版社:技術評論社

発売日:隔月(毎偶月)24日

サイズ:B5

最新刊の情報はこちら

ついに購読しちゃいました。
まぁ見かけるたびに買ってる気がするし、
隔月って忘れがちだからちょうどいいんだけど…

月の書籍用予算(10000円と設定)が吹っ飛んだorz

あ、釣りっぽいタイトルの件ですが、ウソじゃないですよ。
ブロガーじゃなくWebサイト持ってる人全般OKですが。

というわけで以下にその方法を。

利用するのは
Fujisan.co.jpのアフィリエイト登録者全員に1000円引きギフト券プレゼント
なキャンペーン。

はい、もうおわかりですね。
というわけで、通常9,324円のWEB+DB PRESSが8,324円で買えました。

1冊あたりに換算すると1,554円→1,387.333...円ということでわりと安くなります。

以上、ブログ・Webサイトを持ってる人は是非。

良ければこの記事のリンクから飛んで下さい^^

LighediTorをSourceForge.jpで公開しました

ここ最近いじり続けてたエディタですが、SourceForge.jpでホスティングすることにしました。
名前はLighediTor。スペルミス注意です。

SF.jpにしたのは、比較的自由に使えるサーバスペースが手に入るから。
先日の障害の際、xrea一極集中はやばいと感じたので調度良かったのです。

以下が主なページです。

プロジェクト概要
プロジェクトページ(サンプル)
ソース(Subversion)

というわけで改めてよろしくお願いします。

当面の課題は補完候補を充実させることと、
Ctrl+Enterでの閉じタグ補完をうまく動くようにすることです。
※ IE6でとてつもなく重いのはとりあえず見なかったことにします。。。

皆さんもよければコミッタになってください!

SF.jpの使い方(SVN/シェルサーバ/FTP)

わりとつまづいたのでメモ。

TortpiseSVNで接続

基本的に以下の記事を参考にやればOK。
cl.pocari.org - TortoiseSVN で公開鍵を使う方法
ただ、

2. 公開鍵をサーバに登録
Public key for pasting into OpenSSH authorized_keys file の部分をコピーして $HOME/.ssh/authorized_keys に貼り付けます.

の部分は、
ユーザ設定 » アカウント基本情報設定 » [鍵の編集]から貼り付ければOK。
あと、パスフレーズは空白でOK。

未だにディレクトリとかコピーしながら開発してるので、これを気に活用していこうと思います。
せっかく環境が用意されてるようなので、Gitも使ってみたいところ。

Tera Termでシェルサーバに接続

上でputtygenをもう1回使います。

1. Conversions » Import keyからさっき作った秘密鍵をインポート。
2. Conversions » Export OpenSSH keyで変換。(identityっていう名前にしとくと楽)
※ 鍵を作る時にOpenSSH形式でExportもしておけば、importを省ける。
3. Teratermでshell.sourceforge.jpにSSHでログイン。
4. RSA/DSA鍵を使うを選択し、identityを読み込み。
  (ユーザ/パスは、SF.jpアカウントのもの。)
5. あとは普通にシェルを使える。

参考。
SF.jpのsvnリポジトリへのアクセス設定(亀用) - つくば日記 (仮)

WinSCPでSFTP接続

これは特につまづくところはない。

ユーザ名/パスはSF.jpアカウント。
秘密鍵は、.ppkの方を指定。
プロトコルはSFTP。

あとは普通にFTPできる。

以上、SF.jpはホスティング環境としてかなりいい感じ。
(アドセンスも簡単に使えるしね。)
ソースの公開とかにはgoogle codeの方が向いてそうだけど。

JavaScriptで非WYGIWYGな軽量HTMLエディタを作ろう(最終回)

What You Code Is What You Get.

実は地味に進めてました。
めんどくさいのでまとめて投稿、すいません。。。

[実装2-1 入力補完候補表示]

手始めにカーソル位置の文字を取得して、補完候補を選ぶとこまでやりました。
結果がこちら→Editor2.1

<aと入力すれば、<a>、<adress>等と表示されます。
※ 候補が貧弱なのはキーワードを少ししか登録していないからです。

お世話になったサイトをあげておきます。

textareaの選択範囲を取得し、前後に文字列を挿入する - Archiva
前回以上にこのエントリに頼りっぱなしでした。

上のエントリを理解するために見たMSDN達。
duplicate
moveToElementText
setEndPoint

[実装2-2 カーソル座標にBOX表示]

2-1の候補をカーソル位置に表示しなくちゃだめなので、
まずはただのdivを表示してみることにしました。

結果→Editor2.2

textarea内で入力すれば、そのすぐ右下にBOXが移動します。

参考サイトはこちら。
テキストエリア内のキャレット座標を取得する - Webと文字
getBoundingClientRect()を使って要素の絶対座標を求める - 素人がプログラミングを勉強するブログ

[実装3 入力補完実装]

パーツは揃ったのでいよいよ実装。
ついでにjQueryプラグイン化。
必要なDOM要素は動的に作成するようにし、
複数のtextareaに対応しました。

※ あわせてツールバーを整理。
  選択範囲変換、置換機能も実装しました。

Editor3

参考。
jQuery のプラグインを作成する : ブログの新着記事を表示:Goodpic

[実装4 リファクタリング]

ソースコードがあまりにもひどくなっていたので、書き直し。
が、大して変わらず。

他のjQueryプラグインを参考に何とかしようと思います。
※ 何がいいかなぁ…。
  uiはちょっとでかすぎるし。

ここまでの成果がこれ↓
Editor4
Editor4-a
(4-aはボタンでエディタ化するサンプル。
上のtextareaの入力内容はすぐ下のdivに反映。
下のtextareaはツールバーなしバージョン。)

[まとめ]

補完候補が少なさを筆頭に不具合はまだまだありますが、ある程度できてきました。
今は、微調整を繰り返している状況です。(Editor5で公開)

そろそろ管理も煩雑になってきたので、どこかにhostingしようと思います。
というわけで連載風ブログでの公開は今回で最後です。

まさか2回で終わるとは思いませんでしたが…;

以上、今回はこの辺で。

Home

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

Page Top