2011年8月10日水曜日

GAE/Pのtemplateのextendsでちょっとはまった

Google App Engine (Python) のdjangoのテンプレートを使っていてちょっと躓いたことがあった。

私は、 http://www.aaharu.com/ というサイトを持っていますが、これはGAEで作っていて、DNSもGoogle Appsで設定しています。
お金がかかっているのはドメインだけ。

以前まではテンプレートを使わないでHTMLを表示していたわけですが、更新のたびにすべてのHTMLを変更するのが面倒になったので、テンプレートを使ってみることにしました。
GAEには標準でDjangoのテンプレートエンジンが入っていて、テンプレート継承の仕組みがあります。
http://djangoproject.jp/doc/ja/1.0/topics/templates.html
http://d.hatena.ne.jp/griefworker/20091028/gae_inherit_template

それで、テンプレート継承を使ってみたわけなのですが、HTMLの表示がくずれる現象が起きました。
HTMLのソースを表示させても問題は見当たらない。そしてなぜかOperaだけは正しく表示してくれる。

Chromeの『要素を検証』で確認してみると、どうやらbase.htmlの内容の前に空文字が挿入されているようだったので原因をいろいろ調べると、原因はUTF-8のBOMだった。
base.htmlがBOMありのUTF-8だったため、先頭の1文字を変な風に解釈していたようです。

というわけで、PythonでUTF-8扱うときはBOMは消そうと思いました。

2011年7月24日日曜日

ドリキャスの怪しげな商品購入してみた

社会人になって多少懐にも余裕が出たので、ネタ商品を購入してみた。

今回買ったのはこれです。

私が購入した時はAmazonでは品切れだったので、Yahoo!ショッピングを利用しました。
Dreamcast SDL/TF(microSD) / ドリームキャスト専用 バックアップツール
Dreamcast SDL/TF(microSD) / ドリームキャスト専用 バックアップツール


今現在(2011年7月)は4千円程度が相場でしょうか。
以前はオークションで8千円以上はしたドリームキャストのブロードバンドアダプターも、この方法ができてから値下がり傾向にあるっぽい?です。

商品説明に『※玄人専用』って書いてあるのがなんかアレゲです。

少し知識があればこちらのサイトを参考に自作できるようなもので、結構安く仕上がるものらしいです。
でも道具も知識もないのでとりあえず買ってみることにした。

使うもの
DC本体(MIL-CD対応版)
上の商品
microSD
CD

手順
dcsdripを http://f17.aaa.livedoor.jp/~takotako/dcserial_ft232bm.php からDL

CDに焼く
参考: http://ayasuke.exblog.jp/14771039/
私も上のサイトと同じようにDir2bootを使用しましたが、DiscJugglerがなかったので代わりにImgBurnを使用しました。dllファイルがないと言われたのでそこは適当にやっつけた。
ImgBurnでよくわからないアラートが出たけど無視しても問題なかった。

CDをDCにセットして吸出し
参考: http://ayasuke.exblog.jp/14773019/
ちなみに同じファイル名があった場合上書きされる仕様なので、2枚分のデータを1つのSDにやりたいときは名前変えるとよろし。
実機ではプレイできても、少しでも傷がついているものはリードエラーになるものが多かったです。

nulldcをDL
http://code.google.com/p/nulldc/
上のページにあるように、Visual C++ 2010 RuntimesDirectX 9c Runtimesが必要。
データフォルダにflashとbiosを名前を変えて置けば準備完了。

nulldcはShiftがスタートで、xcvbがABCD、asがLRとかでした。キーボードよりも360コントローラーでやるとやりやすそうですね。
しかし、nulldcの開発自体は去年から止まっているっぽい?
寄付も募集していたようですけど、今はどうなっているのかよくわらかないです。
あと、日本語フォルダ読めないようなので注意。

nulldcの完成度はそこそこですが、これ以上のアップデートもなさそうだし、互換が完璧というわけでもないので、やはりVGAボックスと実機でプレイというのが今のとこ一番かなぁ。

2011年4月26日火曜日

アイマス2 ファーストレビュー

最近プログラミングしてなくてネタがないのでゲームレビューする。

『アイドルマスター2』
まだクリアしてないので、ファーストレビューです。セカンド以降はあるか微妙ですが。


過去シリーズは、360版、L4U、SP(ミッシングムーン)、DSってプレイしてます。つまりAC版以外だいたいやってる。

アイマス待望の続編ってことで期待されてた作品ですが、発売前からネットで騒ぎ(?)を起こして、悪い意味で話題にもなった作品です。

プレイ時間は今のところ5時間程度。中盤なのかな?
あくまで今の時点でのレビューです。

・良い点
グラフィック
新曲
新キャラ(響と貴音)
S4U

良い点は上で挙げた通り。
S4Uはこれだけで楽しめるし自分は好きです。

・良くない点
曲の数
序盤
テンポ
ステージ

曲の数は特別少ないわけではありませんが、前作であった曲がないというのはさみしい。
容量的に厳しいのかもしれませんが、あったほうがよかったなーって思います。
また、今回はトリオを組むのが基本なのですが、序盤はメンバー内の仲が悪かったりします。
正直アイドル同士の仲が悪いのを見たくないw
やよいが、「今日も仲良し2人組で、、あっ! すみません! 3人組 で・・・」なんて言うとか耐えられないぉ(´;ω;`)

あと相変わらずテンポが悪いです。
もうこれはシリーズ通してそう感じてるんで半分諦めてますが・・・
「突風アイドル・・・」とかいらねーから。
ついでに言うとレッスンもいらないと個人的に思う。中途半端なアクションとかいらない、シミュレーションでいい。

最後にステージについてですが、残念だと思うことが2つ。
1つは歌うパートが選べないということ。ユニットのポジションで決まってるっぽい?
もう1つはカメラ。これも選べなくなっているんですが、自分はむしろそれよりもDSにあった視点がなくなってるのが残念です。
DSでは、アイドル後方から観客席を移すカメラアングルがあったんですよね。
こんなの
自分はこれが気に入っていて、DSで一番良かったものだと思ってるくらい。

まだやりこんでないので、間違ってたらごめんなさい。
悪い点ばかり長く書いてますが、つまらないってわけじゃないです。
中盤以降はやることもわかってきて、アイドルもギスギスしてないので面白いです。


というか2でサイネリアが1位とかどういうことなの・・・

DSってゲーム性がなくて、あまり評価されてない面もありますが、自分は好きです。
変態的な(主に涼ちん)シナリオが目立ちますが、システムも頑張ってたんだなーと。まあグラフィックと音質はDSなんであれなんですが。

2011年4月23日土曜日

FlexのBase64Decoder

DC startup generatorのソースコードを少し修正した。
んで、mx.utils.Base64Decoderを使うときにちょっと躓いたのでメモ。

修正個所は、zlib圧縮をやめたのと、
修正前はライブラリを使ってBase64を扱っていたのですが、どうやらFlex4には最初から
mx.utils.Base64Decoder
なるものがあるらしいので使ってみることにした。

*自分はFlash Builder 4で開発してます。

まず、普通にAS3プロジェクトを作ってもBase64Decoderをインポートできない。
「framework.swc」というswcファイルが必要になります。
Base64Encoder/Base64Decoderを使う
これはSDKがあるディレクトリの、[frameworks/libs]の中にあります。

しかしまだエラーが残るので厄介。
Base64Decoder 使おうとしたら「リソースバンドルutilsを解決できません」とか言い出したのでやっつけた
なぜかダミーのフォルダを作らないといけないようです・・・

あとは問題なく使えます。
設定さえ終われば便利です。

以下ソースコード。
package
{
 import flash.display.Sprite;
 import flash.display.StageScaleMode;
 import flash.events.Event;
 import flash.filters.BlurFilter;
 import flash.net.URLRequest;
 import flash.net.navigateToURL;
 import flash.text.TextField;
 import flash.text.TextFormat;
 import flash.utils.ByteArray;
 
 import mx.utils.Base64Decoder;
 
 import org.libspark.betweenas3.BetweenAS3;
 import org.libspark.betweenas3.easing.Cubic;
 import org.libspark.betweenas3.easing.Quad;
 import org.libspark.betweenas3.tweens.ITween;
 
 public class DC extends Sprite
 {
  private function Base64toByteArray(data:String):ByteArray
  {
   var byteArray:ByteArray;
   var base64Decoder:Base64Decoder = new Base64Decoder();
   base64Decoder.decode(data);
   try {
    byteArray = base64Decoder.toByteArray();
    byteArray.position = 0;
   } catch (e:Error) {
    return null;
   }
   return byteArray;
  }
  
  private const R:uint = 60;
  private const W:Number = stage.stageWidth / 2;
  private const H:Number = stage.stageHeight / 2;
  private var _letter:Array = [];
  private var _ball:Ball;
  private var _temp:TextField = new TextField();
  private var _bounceTiem:Number = 0.36;
  
  public function DC()
  {
   stage.scaleMode = StageScaleMode.SHOW_ALL;
   stage.frameRate = 60;
   
   var param:Object = loaderInfo.parameters;
   var word:String = param["w"];
   if(word == null)
    word = "Dreamcast";
   else {
    var ba:ByteArray = new ByteArray();
    ba = Base64toByteArray(word);
    if(!ba) {
     navigateToURL(new URLRequest("/dc/"));
    } else {
     word = ba.readUTFBytes(ba.length);
    }
   }
   _temp.text = word;
   var format:TextFormat = new TextFormat(null, R);
   _temp.setTextFormat(format);
   
   for(var i:int = 0; i < _temp.text.length; i++)
   {
    var tf:TextField = new TextField();
    tf.text = _temp.text.charAt(i);
    tf.selectable = false;
    tf.setTextFormat(format);
    
    if(i)
     tf.x = _letter[i-1].x + _letter[i-1].textWidth;
    else
     tf.x = W - _temp.textWidth / 2;
    tf.y = H + R/2;
    _letter.push(tf);
   }
   
   _ball = new Ball();
   _ball.filters = [new BlurFilter()];
   _ball.x = _letter[0].x - R*2.2;
   _ball.y = _letter[0].y - R*4;
   addChild(_ball);
   
   var tween:ITween = BetweenAS3.bezierTo(_ball, {x: _letter[0].x + _letter[0].textWidth, y: _letter[0].y + 35}, {x: _letter[0].x + R, y: _letter[0].y - R}, 2, Cubic.easeIn);
   tween.onComplete = bounce;
   tween.onCompleteParams = [1];
   tween.play();
  }
  
  private function bounce(n:uint):void
  {
   character(n-1);
   var tween:ITween = BetweenAS3.bezierTo(_ball, {x: _letter[n].x + _letter[n].textWidth, y: _ball.y}, {x: _letter[n].x + _letter[n].textWidth / 4, y: _letter[n].y - 10}, _bounceTiem);
   if(_bounceTiem >= 0.22) {
    _bounceTiem -= 0.02;
   }
   if(n < _temp.text.length - 1)
    tween.onComplete = function():void
    {
     bounce(n+1)
    };
   else
    tween.onComplete = ぴょーん;
   tween.play();
  }
  
  private function character(index:uint):void
  {
   addChild(_letter[index]);
   BetweenAS3.tween(_letter[index], {y: _letter[index].y, alpha: 1}, {y: _letter[index].y + 20, alpha: 0}).play();
  }
  
  private function ぴょーん():void
  {
   character(_temp.text.length - 1);
   
   var tween:ITween = BetweenAS3.bezierTo(_ball, {x: W, y: _letter[0].y - R*0.8}, {x: (W + _ball.x) / 2, y: _letter[0].y - R*5}, 1.2, Quad.easeOut);
   tween.play();
   tween.onComplete = ぐるぐる;
  }
  
  private function ぐるぐる():void
  {
   var sp:Sprite = new Sprite();
   sp.filters = [new BlurFilter()];
   addChild(sp);
   sp.graphics.lineStyle(6, _ball.color);
   sp.graphics.moveTo(_ball.x, _ball.y);
   
   addEventListener(Event.ENTER_FRAME, onEnterFrame(sp));
   
   var tweenArray:Array = [];
   for(var i:int = 0; i < 900; i++)
   {
    var toX:Number = _ball.x - R * i / 720 * Math.cos(i * Math.PI / 180);
    var toY:Number = _ball.y - R * i / 720 * Math.sin(i * Math.PI / 180);
    tweenArray.push(BetweenAS3.to(_ball, {x: toX, y: toY}, 0.002));
   }
   var tween:ITween = BetweenAS3.serialTweens(tweenArray);
   tween.onComplete = function():void
   {
    removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    sp.graphics.lineTo(_ball.x, _ball.y);
    removeChild(_ball);
   };
   tween.play();
  }
  
  private function onEnterFrame(sp:Sprite):Function
  {
   return function(e:Event):void
   {
    sp.graphics.lineTo(_ball.x, _ball.y);
   };
  }
 }
}

import flash.display.Sprite;

class Ball extends Sprite
{
 private var _color:uint;
 
 public function get color():uint
 {
  return _color;
 }
 
 public function Ball(j:Boolean = true) {
  if(j)
  {
   graphics.beginFill(0xea5504);
   _color = 0xea5504;
  } else {
   graphics.beginFill(0x0000FF);
   _color = 0x0000FF;
  }
  graphics.drawCircle(0, 0, 4);
  graphics.endFill();
 }
}

2011年4月18日月曜日

BottomCoder SRM398 DIV2

下書きのままだったので公開する。

昔過ぎてもう問題覚えてない。
たしかこれはどっちも解けたはず。

import java.util.Arrays;

public class MinDifference {
 public double EPS = 1e-6;
 
 public int closestElements(int A0, int X, int Y, int M, int n) {
  int[] a = new int[n];
  a[0] = A0;
  for(int i = 1; i < n; i++) {
   a[i] = (a[i - 1] * X + Y) % M;
  }
  Arrays.sort(a);
  int res = Integer.MAX_VALUE;
  for(int i = a.length - 1; i > 0; i--) {
   res = Math.min(res, a[i] - a[i - 1]);
  }
  return res;
 }
 
 public void tr(Object... o) { System.out.println(o.length > 1 || o[0].getClass().isArray() ? Arrays.deepToString(o) : o[0]); }
}


激しい。
こんなことしなくても解ける・・・
import java.util.Arrays;
import java.util.LinkedList;

public class CountExpressions {
 public double EPS = 1e-6;
 
 private LinkedList list = new LinkedList();
 private int res = 0;
 private int ans;
 
 public int calcExpressions(int x, int y, int val) {
  ans = val;
  
  list.add(x);
  list.add(x);
  list.add(y);
  list.add(y);
  dfs("+", 0, list.poll(), 0);
  
  list = new LinkedList();
  list.add(x);
  list.add(y);
  list.add(x);
  list.add(y);
  dfs("+", 0, list.poll(), 0);

  list = new LinkedList();
  list.add(x);
  list.add(y);
  list.add(y);
  list.add(x);
  dfs("+", 0, list.poll(), 0);

  list = new LinkedList();
  list.add(y);
  list.add(y);
  list.add(x);
  list.add(x);
  dfs("+", 0, list.poll(), 0);

  list = new LinkedList();
  list.add(y);
  list.add(x);
  list.add(x);
  list.add(y);
  dfs("+", 0, list.poll(), 0);

  list = new LinkedList();
  list.add(y);
  list.add(x);
  list.add(y);
  list.add(x);
  dfs("+", 0, list.poll(), 0);
  
  tr(res);
  return res;
 }
 
 private void dfs(String s, long val, int v, int n) {
  if(s.equals("+")) {
   val += (long)v;
  } else if(s.equals("-")) {
   val -= (long)v;
  } else {
   val *= (long)v;
  }
  
  if(n > 2) {
   if(val == ans) {
    res++;
   }
   list.add(0, v);
   return;
  }

  dfs("+", val, list.poll(), n + 1);
  dfs("-", val, list.poll(), n + 1);
  dfs("*", val, list.poll(), n + 1);
  list.add(0, v);
 }
 
 public void tr(Object... o) { System.out.println(o.length > 1 || o[0].getClass().isArray() ? Arrays.deepToString(o) : o[0]); }
}

2011年3月8日火曜日

零の軌跡クリアした

先日やっと『零の軌跡』をクリアしました。



それなりに面白かったです。いい意味でも悪い意味でもシステム面で過去作からの大きな変化はない。
個人的には、戦闘システムをちょっと変えて欲しい。

プレイ時間はセーブデータを見ると、79時間39分(ハード)。RPGとしてはたぶん一般的な長さだと思う。
ただ今の自分にとってはちょっと長い・・・買ったのは去年の10月だからクリアまで半年ぐらいかかってる。
英雄伝説の空の軌跡シリーズは全部PSPでプレイしてますが、各作品のプレイ時間は
FC 53時間22分(ノーマル)
SC 90時間36分(ノーマル)
3rd 58時間43分(ノーマル)
となっていて過去作と比べても長めなのかも。

今回は初回プレイからハードにした。
戦闘は銀戦が一番苦労した。ラスボスより面倒だよね、あれ。