In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Unionしりとり

Unionフレームワークを使ったしりとりです。元の語の、全体以外何文字尻をとってもOKです。
「ん」で終わっても全然問題無いです。
次の制限を設けています。
・4文字以上であること。
・仮名以外の文字を含む場合、SocialIMEで読みがとれる単語であること。
・日本語でのGoogle検索で単語をクオーテーションで囲ったもので検索したときに、
ヒット数が10000件以上であること。
・「を」で終わる単語等、あまりに不適切な単語は勝手に除くようにしてます。
たまにSocialIMEの取得や同時投稿等でおかしな結果になることがありますが、
笑って見逃してください。
直前の単語をクリックすると、その単語のGoogle検索を別ウィンドウで開きます。
左上に各ユーザーの入力情報を載せたので、チャット欄としてもお使いください。
TODO
・ヒット数を履歴に?
・英語でも読めるように?
・UIを派手に
ご意見ご要望は twitter : @uwitenpen までどうぞ。
Kana.ASのソースコードを削って使っているので、New BSD Licenseです。
@see http://code.google.com/p/kanaxs/
Copyright 1994-2004 The FreeBSD Project. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and
Get Adobe Flash player
by uwi 30 Aug 2009

    Talk

    uwi at 29 Aug 2009 20:59
    4文字以上縛りと履歴追加しました。
    uwi at 30 Aug 2009 01:08
    チャット欄っぽいのつけました。

    Tags

    Embed
// Unionフレームワークを使ったしりとりです。元の語の、全体以外何文字尻をとってもOKです。
// 「ん」で終わっても全然問題無いです。
// 次の制限を設けています。
// ・4文字以上であること。
// ・仮名以外の文字を含む場合、SocialIMEで読みがとれる単語であること。
// ・日本語でのGoogle検索で単語をクオーテーションで囲ったもので検索したときに、
//  ヒット数が10000件以上であること。
// ・「を」で終わる単語等、あまりに不適切な単語は勝手に除くようにしてます。
// 
// たまにSocialIMEの取得や同時投稿等でおかしな結果になることがありますが、
// 笑って見逃してください。
// 
// 直前の単語をクリックすると、その単語のGoogle検索を別ウィンドウで開きます。
// 左上に各ユーザーの入力情報を載せたので、チャット欄としてもお使いください。
// 
// TODO
// ・ヒット数を履歴に?
// ・英語でも読めるように?
// ・UIを派手に
// 
// ご意見ご要望は twitter : @uwitenpen までどうぞ。
// Kana.ASのソースコードを削って使っているので、New BSD Licenseです。
// @see http://code.google.com/p/kanaxs/
//
// Copyright 1994-2004 The FreeBSD Project. All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// 
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project.

package {
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.KeyboardEvent;
  import flash.events.MouseEvent;
  import flash.text.TextFieldAutoSize;
  import flash.text.TextFormat;
  import flash.net.*;
  import flash.ui.Keyboard;
  import net.user1.reactor.*;
  import flash.utils.*;
  import flash.system.*;
  import flash.text.TextField;
  import com.adobe.serialization.json.JSON;
  
  public class Shiritori extends Sprite {
    protected var _reactor:Reactor;
    protected var _room:Room;
    
    private static const INFHIT : int = 10000;
    private static const MAXLEN_HISTORY : int = 10000;
    
    private var _tf : TextField;
    
    public function Shiritori() {
      buildUI();
      _reactor = new Reactor();
      _reactor.addEventListener(ReactorEvent.READY, readyListener);
      _reactor.connect("tryunion.com", 9100);
    }
    
    private const UPDATE : String = "UPDATE";
    private const STATEUPDATE : String = "STATEUPDATE";
    
    protected function readyListener (e:ReactorEvent):void {
      this.stage.focus = _tfinput;
        
      var rs : RoomSettings = new RoomSettings();
      rs.dieOnEmpty = false;
        
      _prev = null;
      _yomi = null;
      
      _room = _reactor.getRoomManager().createRoom("wonderfl.shiritori", rs);
      _room.addMessageListener(UPDATE, onUpdate);
      _room.addMessageListener(STATEUPDATE, onStateUpdate);
      _room.addEventListener(RoomEvent.SYNCHRONIZE, onRoomSynchronize);
      _room.addEventListener(RoomEvent.CLIENT_COUNT, onClientCount);
      _room.join();
    }
    
    private var _client : IClient;
    
    // 初回ログイン時
    private function onRoomSynchronize(e : RoomEvent) : void
    {
        _client = _reactor.getClientManager().self();
        _room.removeEventListener(RoomEvent.SYNCHRONIZE, onRoomSynchronize);
        _tfinput.text = "";
        onUpdate();
    }
    
    private var _tfhistory : TextField;
    private var _tfprev : TextField;
    private var _tfprevyomi : TextField;
    private var _tfprevhits : TextField;
    private var _tfinput : TextField;
    private var _tfstatus : TextField;
    private var _tfinfo : TextField;
    private var _tfhits : TextField;
    private var _tfcount : TextField;
    private var _btnsubmit : SimplestButton;
    
    protected function buildUI ():void {
      _btnsubmit = new SimplestButton("SUBMIT", 90, 20, 0xf3f3f3);
      _btnsubmit.x = 465 / 2 + 110; _btnsubmit.y = 350;
      _btnsubmit.addEventListener(MouseEvent.CLICK, onSubmitClick);
      addChild(_btnsubmit);
      
      var tfmtbig : TextFormat = new TextFormat("Gothic", 50);
      var tfmtnormal : TextFormat = new TextFormat("Gothic", 12);
      var tfmtsmall : TextFormat = new TextFormat("Gothic", 9);
      
      addChild(_tfhistory = new TextField());
      setParams(_tfhistory, {
        defaultTextFormat : tfmtsmall, 
        border : true,
        x : 350,
        y : 0,
        width : 100,
        height : 150
      });
      
      addChild(_tfprev = new TextField());
      setParams(_tfprev, {
        defaultTextFormat : tfmtbig, 
        autoSize : "center",
        selectable : false,
        x : 465/2,
        y : 200
      });
      _tfprev.addEventListener(MouseEvent.CLICK, onLink);
      
      addChild(_tfprevyomi = new TextField());
      setParams(_tfprevyomi, {
        defaultTextFormat : tfmtnormal, 
        selectable : false,
        autoSize : "center",
        x : 465/2,
        y : 180
      });
      _tfprevyomi.addEventListener(MouseEvent.CLICK, onLink);
      
      addChild(_tfprevhits = new TextField());
      setParams(_tfprevhits, {
        defaultTextFormat : tfmtnormal, 
        selectable : false,
        autoSize : "center",
        x : 465/2,
        y : 260
      });
      _tfprevhits.addEventListener(MouseEvent.CLICK, onLink);
      
      addChild(_tfinput = new TextField());
      setParams(_tfinput, {
        defaultTextFormat : tfmtnormal, 
        border : true,
        type : "input",
        text : "ここに入力!",
        restrict : "!-~、-ヾ一-龠!-゚",
        x : 465/2 - 200,
        y : 350,
        width : 300,
        height : 20
      });
      _tfinput.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
      _tfinput.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
      
      addChild(_tfinfo = new TextField());
      setParams(_tfinfo, {
        defaultTextFormat : tfmtnormal, 
        x : 465 / 2 - 200,
        y : 380,
        width : 400,
        height : 60
      });
      
      addChild(_tfhits = new TextField());
      setParams(_tfhits, {
        defaultTextFormat : tfmtnormal, 
        x : 465 / 2 + 110,
        y : 320,
        width : 90,
        height : 20
      });
      
      addChild(_tfcount = new TextField());
      setParams(_tfcount, {
        defaultTextFormat : tfmtnormal, 
        x : 10,
        y : 10,
        text : "接続中だよ。",
        width : 300,
        height : 20
      });
      
      addChild(_tfstatus = new TextField());
      setParams(_tfstatus, {
        defaultTextFormat : tfmtnormal, 
        x : 10,
        y : 40,
        width : 300,
        height : 150
      });
      
      _yg = new YomiGetter();
      _yg.addEventListener(Event.COMPLETE, onYomiGetComplete);
    }
    
    // 接続人数の表示
    private function onClientCount(e : RoomEvent) : void
    {
        _tfcount.text = e.getNumClients() + "人が接続しているよ。";
    }
    
    // 状態の更新。他の人が語を更新した場合も呼ばれる。
    private function onUpdate(c : IClient = null) : void
    {
        _prev = _room.getAttribute("curword");
        _prevyomi = _room.getAttribute("curyomi");
        _prevhits = int(_room.getAttribute("curhits"));
        _hist = _room.getAttribute("history");
        if(_hist == null)_hist = "";
        if(_prev == null){
            _tfprev.text = "";
            _tfprevyomi.text = "";
            _tfprevhits.text = "";
            _tfhistory.text = "";
            _tfinfo.text = "直前の単語がないのでなんでも入力できるよ!";
        }else{
            _tfprev.text = _prev;
            _tfprevyomi.text = _prevyomi;
            _tfprevhits.text = _prevhits.toString() + " hits";
            _tfhistory.text = _hist;
            _tfhistory.scrollV = _tfhistory.numLines - 1;
            _tfinfo.text = "";
        }
        onStateUpdate(c);
    }
    
    private function onStateUpdate(c : IClient = null) : void
    {
        var txt : String = "";
        for each(var cc : IClient in _room.getClients()){
            txt += cc.getClientID() + " : " + cc.getAttribute(null, "inputtext") + "\n";
        }
        _tfstatus.text = txt;
    }
    
    private var _yg : YomiGetter;
    private var _ul : URLLoader;
    private static const REKANJI : RegExp = /[一-龠]/;
    
    private function onSubmitClick(e : MouseEvent) : void
    {
        onSubmit();
    }
    
    // リンク処理。Google検索の画面へ。なぜかヒット件数が違う;
    private function onLink(e : MouseEvent) : void
    {
        navigateToURL(new URLRequest(
            "http://www.google.co.jp/search?q=\"" + escapeMultiByte(_tfprev.text) + "\"&lr=lang_ja"
            ), "_blank");
    }
    
    private var _input : String;
    private var _hist : String;
    private const PROHIBIT : RegExp = /[ーっッ][ーっッ]$|[をヲ]$/
    
    private function onSubmit() : void
    {
        _input = _tfinput.text;
        if(_input == ""){
            _tfinfo.text = "入力されてないよ!";
            return;
        }
        if(_input.length <= 3){
            _tfinfo.text = "4文字以上だよ!";
            return;
        }
        if(PROHIBIT.test(_input)){
            _tfinfo.text = "それはないわー";
            return;
        }
        if(_hist.indexOf(_input + "\n") != -1){
            _tfinfo.text = "前に出てるよ!";
            return;
        }
        // 漢字が含まれていた場合、SocialIMEで読みを得る。
        // そうでない場合、ひらがなに変換して読みとする。
        _tfinfo.text = "";
        if(REKANJI.test(_input)){
            _yg.get(_input);
        }else{
            _yomi = Kana.toHiraganaCase(Kana.toZenkanaCase(_input));
            validateYomi();
        }
    }
    
    private var _downKey : uint;
    private function onKeyUp(e : KeyboardEvent) : void
    {
        if(e.keyCode == Keyboard.ENTER && e.keyCode == _downKey){
            onSubmit();
        }
        _client.setAttribute("inputtext", _tfinput.text);
        _room.sendMessage(STATEUPDATE, true);
    }
    
    private function onKeyDown(e : KeyboardEvent) : void
    {
        _downKey = e.keyCode;
    }

    private var _prev : String;
    private var _prevyomi : String;
    private var _prevhits : int;
    private var _yomi : String;
    private var _hits : int;
    private const REYOMI : RegExp = /[ぁ-んー]$/;
    
    // SocialIMEで読みを得て、すこし加工する。
    private function onYomiGetComplete(e : Event) : void
    {
        _yomi = Kana.toHiraganaCase(Kana.toZenkanaCase(_yg.yomi));
        _tfinfo.appendText(_yomi + "\n");
        validateYomi();
    }
    
    private var _matchlen : int; // 一致長
    
    // 得た読みから、しりとりになっているかどうか等をチェックする。
    private function validateYomi() : void
    {
        if(_yomi == null || !REYOMI.test(_yomi)){
            _tfinfo.text = "読みが無効だよ!";
            return;
        }
        if(_prev != null){
            for(var i : int = Math.min(_prevyomi.length, _yomi.length) - 1;i >= 1;i--){
                if(_prevyomi.substr(_prevyomi.length - i, i) == _yomi.substr(0, i)){
                    _matchlen = i;
                    search();
                    return;
                }
            }
            _tfinfo.text = "しりとりになってないよ!";
        }else{
            search();
        }
    }
    
    // Google検索で世界を見る
    private function search() : void
    {
        _ul = new URLLoader();
        _ul.addEventListener(Event.COMPLETE, onGoogleComplete);
        _ul.load(new URLRequest(
            "http://ajax.googleapis.com/ajax/services/search/web?" + 
            "q=\"" + escapeMultiByte(_input) + "\"&v=1.0&lr=lang_ja"
            ));
    }
    
    // ヒット数だけ取り出して一般性のある語かチェックする
    private function onGoogleComplete(e : Event) : void
    {
        _ul.removeEventListener(Event.COMPLETE, onGoogleComplete);
        var obj : Object = JSON.decode(_ul.data as String);
        _hits = int(obj.responseData.cursor.estimatedResultCount);
        var inf : int = INFHIT;
        this.stage.focus = _tfinput;
        if(_hits < inf){
            _tfinfo.text = INFHIT + "件以上ヒットしないよ!\n" +  _hits + " hits";
        }else{
            submit();
        }
    }
    
    // 有効な語の場合、現在の語を更新する
    private function submit() : void
    {
        _room.setAttribute("curword", _input, true, true);
        _room.setAttribute("curyomi", _yomi, true, true);
        _room.setAttribute("curhits", _hits.toString(), true, true);
        _hist += _input + "\n";
        while(_hist.length > MAXLEN_HISTORY){
            var ind : int = _hist.indexOf("\n");
            if(ind == -1)break;
            _hist = _hist.substr(ind + 1);
        }
        _room.setAttribute("history", _hist, true, true);
        _tfinput.text = "";
        _client.setAttribute("inputtext", "");
        _room.sendMessage(UPDATE, true);
    }
    
    private static function setParams(o : Object, params : Object) : void
    {
      for (var key : String in params) {
        o[key] = params[key];
      }
    }
  }
}

import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;

class SimplestButton extends SimpleButton
{
  private var _tf1 : TextField;
  private var _tf2 : TextField;
  
  public function SimplestButton(str : String, w : Number, h : Number, color : uint) 
  {
    _tf1 = new TextField();
    _tf1.autoSize = TextFieldAutoSize.CENTER;
    _tf1.text = str;
    _tf1.x = w / 2 - _tf1.width / 2;
    _tf1.y = h / 2 - _tf1.height / 2;
    _tf1.mouseEnabled = false;
    
    _tf2 = new TextField();
    _tf2.autoSize = TextFieldAutoSize.CENTER;
    _tf2.text = str;
    _tf2.x = w / 2 - _tf2.width / 2 + 2;
    _tf2.y = h / 2 - _tf2.height / 2 + 2;
    _tf2.mouseEnabled = false;
    
    var s1 : Sprite = new Sprite();
    s1.graphics.beginFill(color);
    s1.graphics.lineStyle(1);
    s1.graphics.drawRoundRect(0, 0, w, h, 3, 3);
    s1.addChild(_tf1);
    
    var s2 : Sprite = new Sprite();
    s2.graphics.beginFill(color);
    s2.graphics.lineStyle(1);
    s2.graphics.drawRoundRect(2, 2, w + 2, h + 2, 3, 3);
    s2.addChild(_tf2);
    
    super(s1, s1, s2, s1);
  }
    
  public function changeText(str : String) : void
  {
    _tf1.text = str;
    _tf2.text = str;
  }
}

import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.system.Security;
import flash.utils.*;

class YomiGetter extends EventDispatcher
{
    private var _ul : URLLoader;
    private var _yomi : String;
    private var _str : String;
    
    public function YomiGetter()
    {
        Security.loadPolicyFile("http://5ivestar.org/proxy/crossdomain.xml");
    }
    
    public function get(str : String) : void
    {
        _str = str;
        
        _ul = new URLLoader();
        _ul.addEventListener(Event.COMPLETE, onLoadComplete);
        _ul.load(new URLRequest(
            "http://5ivestar.org/proxy/" + 
            "http://www.social-ime.com/api/?string=" + escapeMultiByte(str) + "&charset=UTF-8"
        ));
    }
    
    private function onLoadComplete(e : Event) : void
    {
        _ul.removeEventListener(Event.COMPLETE, onLoadComplete);
        var res : String = _ul.data;
        _yomi = null;
        if(res != null){
            var yomi : String = "";
            for each(var line : String in res.split("\n")){
                var words : Array = line.split("\t");
                var f : Boolean = false;
                for each(var word : String in words){
                    if(word.match(/^[ぁ-ゞー]+$/)){
                        yomi += word;
                        f = true;
                        break;
                    }
                }
                if(!f && words.length > 0){
                    yomi += words[0];
                }
            }
            _yomi = yomi;
        }
        dispatchEvent(new Event(Event.COMPLETE));
    }
    
    public function get yomi() : String { return _yomi; }
    public function get str() : String { return _str; }
}

// @see http://code.google.com/p/kanaxs/
class Kana
{
	private var $string:String;

	/**
	 * 半角仮名→全角仮名への変換テーブル
	 */
	private static var $H2Z:Object =
	{
		0xFF67:0x30A1, 0xFF68:0x30A3, 0xFF69:0x30A5, 0xFF6A:0x30A7, 0xFF6B:0x30A9,
		0xFF70:0x30FC, 0xFF71:0x30A2, 0xFF72:0x30A4, 0xFF73:0x30A6, 0xFF74:0x30A8,
		0xFF75:0x30AA, 0xFF76:0x30AB, 0xFF77:0x30AD, 0xFF78:0x30AF, 0xFF79:0x30B1,
		0xFF7A:0x30B3, 0xFF7B:0x30B5, 0xFF7C:0x30B7, 0xFF7D:0x30B9, 0xFF7E:0x30BB,
		0xFF7F:0x30BD, 0xFF80:0x30BF, 0xFF81:0x30C1, 0xFF82:0x30C4, 0xFF83:0x30C6,
		0xFF84:0x30C8, 0xFF85:0x30CA, 0xFF86:0x30CB, 0xFF87:0x30CC, 0xFF88:0x30CD,
		0xFF89:0x30CE, 0xFF8A:0x30CF, 0xFF8B:0x30D2, 0xFF8C:0x30D5, 0xFF8D:0x30D8,
		0xFF8E:0x30DB, 0xFF8F:0x30DE, 0xFF90:0x30DF, 0xFF91:0x30E0, 0xFF92:0x30E1,
		0xFF93:0x30E2, 0xFF94:0x30E4, 0xFF95:0x30E6, 0xFF95:0x30E8, 0xFF97:0x30E9,
		0xFF98:0x30EA, 0xFF99:0x30EB, 0xFF9A:0x30EC, 0xFF9B:0x30ED, 0xFF9C:0x30EF,
		0xFF9D:0x30F3, 0xFF9E:0x309B, 0xFF9F:0x309C, 0xFF66:0x30F2
	};

	public function Kana(s:String){
		$string = s;
	};

	/**
	 * 全角カタカナを全角ひらがなに変換します。
	 * @return {String}
	 */
	public static function toHiraganaCase(s:String):String
	{
		var c:Number;
		var a:Array = [];
		var i:uint = s.length
	
		while(i--)
		{
			c = s.charCodeAt(i);
			a[i] = (0x30A1 <= c && c <= 0x30F6) ? c - 0x0060 : c;
		};
	
		return String.fromCharCode.apply(null, a);
	};

	/**
	 * 半角のカタカナを全角のカタカナに変換します。
	 * @return {String}
	 */
	public static function toZenkanaCase(s:String):String
	{
		var c:Number;
		var a:Array = [];
		var m:Object = $H2Z;

		for(var i:uint=0,f:uint=s.length;i<f;i++)
		{
			c = s.charCodeAt(i);
			a[i] = m[c] || c;
		};

		return String.fromCharCode.apply(null, a);
	};

	public function toHiraganaCase():Kana
	{
		$string = Kana.toHiraganaCase($string);
		return this;
	};

	public function toZenkanaCase():Kana
	{
		$string = Kana.toZenkanaCase($string);
		return this;
	};

	public function toString():String{
		return $string;
	};
};