プログラミング所感 - 前へ 目次次へ


08/01/07(月)

仕事始め だ。
いざ、キーボードにさわろうとしたらほこりだらけだ。年末年始もPCを使っていたのに、 マウスにしかさわっていなかった。

LSA(http://www.ingeniatechnology.com/jp/faqs.php)は RFIDより面白そうだ。医薬品向けのようだが、 バッグなどのブランド品にも広がるだろう。


08/01/10(木)

寝不足 なのに眠れない。体のリズムと頭のリズムがずれている。
天文学の素人だが、ビッグバンを考えてみた。

我々は3次元に生きている。時間を4次元目としてみよう。5次元目は素粒子の特性か何かとしてみる。
我々のいる5次元座標と別の座標は、例えば反物質だ。宇宙はエネルギーに満ちている。 我々は5次元軸を(たぶん)移動できないが、エネルギーは移動できるとしよう。
あるとき、我々のいる座標にエネルギーが漏れ出した。ビッグバンだ。この瞬間から4次元の軸である時間も始まった。 もれ方が一瞬でなければ、ビッグバンは計算されるほど高温じゃなかったかもしれない。
5次元空間を移動できる存在があるとすれば、通常物質では構成できない。 エネルギーの一種か何かで構成されているのかもしれない。


08/01/21(月)

最適化プロジェクトで、 熟練者の作業をアルゴリズムで行うことによる利点は2つ挙げられる。
1つは、作業時間が短くなることだ。もう1つは、熟練者以外の作業者が行ってもある程度の結果が出せることだ。
では、熟練者はいらないかというと、そんなことはない。全ての作業をアルゴリズムで行うことは、 通常できない。現時点でベストの方法は、アルゴリズムでたたき台を作成し熟練者がそれを修正する方法だろう。 修正をしやすいように支援することも大切だ。

08/01/22(火)

DataGridViewで BindingSourceを使うと、自作のUndoRedoクラスとうまく連携しなかったので、 あきらめて、Undo/Redo機能を実装しなかった。 よく考えると、一旦DataSourceを外せばうまくいくかもしれない。

08/02/12(火)

構造体をコンテナに入れると、 値の変更が面倒くさい。例えば、以下は最後の行でコンパイルエラーになる。
  List<Point> l = new List<Point>();
  l.Add(new Point());
  l[0].X = 1;
NullableみたいなValueRefを使えば、PointをValueRef<Point>に変更して、値の変更ができるようになる。
[Serializable]
public sealed class ValueRef<T> where T : struct
{
  public T Value;
  public ValueRef() { }
  public ValueRef(T t)
  {
    Value = t;
  }
  public override string ToString()
  {
    return Value.ToString();
  }
  public override bool Equals(object obj)
  {
    return Value.Equals(obj);
  }
  public override int GetHashCode()
  {
    return Value.GetHashCode();
  }
  public static implicit operator ValueRef<T>(T t)
  {
    return new ValueRef<T>(t);
  }
}

08/02/14(木)

2/13にWindowsUpdateを してから、explorerとかが固まったりする。明日客先でデモなのに困った。

08/02/15(金)

読書録。
isbn:4103052511 サクリファイス:やられたという感じ。isbn:4817192488 「企業・行政のためのAHP事例集」。 isbn:4796650792 チーム・バチスタの栄光:こういうのは好きだ。isbn:479421071X 「ファストフードが世界を食いつくす」:これから読む。 isbn:453231366X 雲を掴め:こんなことがあったとは。ぜひ読むべき。isbn:4309650627 「面白いほどよくわかる宇宙の大疑問」。 isbn:4035401501 精霊の守り人シリーズ。面白い。一気に10冊読んだ。
「雲を掴め」より交渉について。
  • 人に好かれたいと思っている人は交渉に向いていない。好かれたいと思っている人は心が弱い。
  • 自己顕示欲の強い人は交渉に不適。
  • 交渉役は非情でなければいけない。
  • 交渉時に非公式なメモを受け取ったら、さっと見てつき返すべきである。受けとってはいけない。
  • 交渉では自分の自由度を最大限に、相手の自由度を最小限にする。追い詰めたらスパッと斬る。
  • 合意文書のドラフトは自分で作る。
  • ハウスキーピングといってワーディングを争う。囲碁で言う寄せ。
私は交渉には向いていないと思う。

08/03/03(月)

24日も死にそうだったが、 今日も鼻水がとまらない。もしかして、黄砂?

08/03/11(火)

ファイルを読み書きできるソフトを 更新して、ファイルフォーマットが変わったときにも容易に上位互換を保つ方法。
ファイル形式をXMLにしておけば、要素が増えても減っても対応できるが、構造が変わるとダメだ。
以下のようにすれば、古い型 DataDoc1のファイルでも新しい型 DataDocのファイルでもそのまま読める。
[Version(1)]
[XmlRoot("DataDoc")]
public class DataDoc1
{
	public int Num;
	public DataDoc Create()
	{
		DataDoc dd = new DataDoc();
		dd.NumList.Add(Num);
		return dd;
	}
}
[Version(2)]
public class DataDoc
{
	public int Version
	{
		get
		{
			VersionAttribute[] va = (VersionAttribute[])GetType().
				GetCustomAttributes(typeof(VersionAttribute), false);
			return va[0].Version;
		}
		set { }
	}
	[XmlArrayItem("Num")]
	public List<int> NumList;
	public DataDoc() { NumList = new List<int>(); }
	public static DataDoc Load(string fnam)
	{
		DataDoc dd = null;
		string s;
		int version = -1;
		using (StreamReader sr = new StreamReader(fnam))
		{
			while ((s = sr.ReadLine().Trim()) != null)
				if (s.StartsWith("<Version>")) break;
			if (string.IsNullOrEmpty(s)) return dd;
			version = int.Parse(s.Substring(9, s.IndexOf('<', 1) - 9));
		}
		using (StreamReader sr = new StreamReader(fnam))
		{
			XmlSerializer xs = new XmlSerializer(VesionedType(version));
			object o = xs.Deserialize(sr);
			MethodInfo mi = o.GetType().GetMethod("Create");
			dd = (DataDoc)mi.Invoke(o, new object[] { });
		}
		return dd;
	}
	public static Type VesionedType(int version)
	{
		Assembly asm = Assembly.GetExecutingAssembly();
		foreach (Type typ in asm.GetTypes())
		{
			VersionAttribute[] va = (VersionAttribute[])typ.
				GetCustomAttributes(typeof(VersionAttribute), false);
			if (va.Length > 0 && va[0].Version == version) return typ;
		}
		return null;
	}
}
/// <summary>バージョン付与</summary>
[AttributeUsage(AttributeTargets.Class)]
public class VersionAttribute : Attribute
{
	/// <summary>バージョン</summary>
	public int Version;
	/// <summary>コンストラクタ</summary>
	public VersionAttribute(int v) { Version = v; }
}
  • バージョンはint型で管理しているが、stringでもよい。
  • クラスごとにVersionAttributeでバージョンを付ける。
  • 古い型から新しい型に変換するCreateメソッドを用意する。

08/03/24(月)

最小費用流問題を 最短路を使って解く方法。
LPで解けるが、LPソルバを使いたくないときに使える。
  • 最短路を求めて、流せるだけ流す。
  • 流したら、減らせるので逆向きのアークにもなるが、コストは負になる。
  • コストが負だとDijikstraが使えないので、開始ノードからのコストで補正する (補正コスト=コスト+元ノードのP値ー先ノードのP値)。P値は開始ノードからのコストの累積値。
  • ロジックがシンプルになるので、開始用のノード(st)と終了用のノード(en)を追加した。
  • 計算速度よりわかりやすさを優先。
Graphクラスは、ORToolBoxより。
using McfGraph = Graph<McfNode, McfArc>;
using McfNTag = NodeTag<McfNode, McfArc>;
using McfATag = ArcTag<McfNode, McfArc>;
/// <summary>
/// MinCostFlowProblem用
/// </summary>
public sealed class McfNode
{
	public int Request; // 要求量(正なら供給、負なら需要)
	public int Result; // 結果量(正なら供給、負なら需要)
	/// <summary>コンストラクタ</summary>
	public McfNode(int r) { Request = r; }
}
/// <summary>
/// MinCostFlowProblem用
/// </summary>
public sealed class McfArc
{
	public int Capa; // 容量
	public int Flow; // 流量(結果)
	public double Cost; // コスト
	/// <summary>コンストラクタ</summary>
	public McfArc(int cap, double cst)
	{
		Capa = cap;
		Flow = 0;
		Cost = cst;
	}
	public int Residue(bool b)
	{
		return b ? Capa - Flow : Flow;
	}
}
public static class MinCostFlowProblem
{
	/// <summary>
	/// 最小費用流問題を解く
	/// </summary>
	/// <param name="g">グラフ</param>
	/// <param name="cost">コストの総和</param>
	/// <returns>全て流せたか</returns>
	public static bool Calc(McfGraph g, out double cost)
	{
		foreach (McfATag at in g.ArcTags)
			if (!at.IsDirected) throw new ApplicationException("Must be directed");
		// ダミーノード追加
		McfNTag st = g.AddNode(new McfNode(0)); // 供給ノード
		McfNTag en = g.AddNode(new McfNode(0)); // 需要ノード
		int n = g.NodesCount; // ノード数
		// ダミーアーク追加
		foreach (McfNTag nt in g.NodeTags)
		{
			if (nt == st) break;
			nt.Node.Result = 0;
			if (nt.Node.Request > 0)
			{
				st.Node.Request += nt.Node.Request;
				g.AddArc(new McfArc(nt.Node.Request, 0), st.Index, nt.Index, true);
			}
			else if (nt.Node.Request < 0)
			{
				en.Node.Request += nt.Node.Request;
				g.AddArc(new McfArc(-nt.Node.Request, 0), nt.Index, en.Index, true);
			}
		}
		double[] p = new double[n]; // 供給点からの最短値の累積
		while (st.Node.Request > 0)
		{
			List<KeyValuePair<McfATag, bool>> minrt
				= MinRoute(g, p, st.Index, en.Index);
			if (minrt == null) break;
			// 流量計算
			int flow = int.MaxValue;
			foreach (KeyValuePair<McfATag, bool> pr in minrt)
				flow = Math.Min(flow, pr.Key.Arc.Residue(pr.Value));
			foreach (KeyValuePair<McfATag, bool> pr in minrt)
				pr.Key.Arc.Flow += pr.Value ? flow : -flow;
			st.Node.Request -= flow;
			en.Node.Request += flow;
		}
		// コスト計算
		bool bCan = st.Node.Request == 0 && en.Node.Request == 0;
		foreach (McfATag at in st.OutArcTags)
			at.RightTag.Node.Result = at.Arc.Flow;
		foreach (McfATag at in en.InArcTags)
			at.LeftTag.Node.Result = -at.Arc.Flow;
		g.DelNode(en.Index);
		g.DelNode(st.Index);
		cost = 0;
		foreach (McfATag at in g.ArcTags)
			cost += at.Arc.Cost * at.Arc.Flow;
		return bCan;
	}
	private static List<KeyValuePair<McfATag, bool>> MinRoute
		(McfGraph g, double[] p, int n1, int n2)
	{
		if (n1 == n2) return null;
		McfATag[] prev = new McfATag[g.NodesCount];
		double[] dist = new double[g.NodesCount];
		for (int k = 0; k < dist.Length; ++k) dist[k] = double.PositiveInfinity;
		dist[n1] = 0;
		bool[] found = new bool[g.NodesCount];
		int nxt = n1, nfound = 1;
		while (nfound < found.Length)
		{
			found[nxt] = true;
			++nfound;
			foreach (McfATag at in g.NodeTag(nxt).OutArcTags)
			{
				int k = at.AnotherID(nxt);
				if (found[k] || at.Arc.Residue(true) == 0) continue;
				McfNTag nt = g.NodeTag(k);
				double d = at.Arc.Cost + p[at.LeftID] - p[at.RightID];
				d += dist[nxt];
				if (d < dist[k] || (d == dist[k] && prev[k] != null))
				{
					prev[k] = at;
					dist[k] = d;
				}
			}
			foreach (McfATag at in g.NodeTag(nxt).InArcTags)
			{
				int k = at.AnotherID(nxt);
				if (found[k] || at.Arc.Residue(false) == 0) continue;
				McfNTag nt = g.NodeTag(k);
				double d = -at.Arc.Cost - p[at.LeftID] + p[at.RightID];
				d += dist[nxt];
				if (d < dist[k] || (d == dist[k] && prev[k] != null))
				{
					prev[k] = at;
					dist[k] = d;
				}
			}
			double min = double.PositiveInfinity;
			for (int i = 0; i < dist.Length; ++i)
			{
				if (!found[i] && dist[i] < min)
				{
					min = dist[i];
					nxt = i;
				}
			}
			if (min == double.PositiveInfinity) break;
		}
		if (dist[n2] == double.PositiveInfinity) return null;
		for (int i = 0; i < p.Length; ++i) p[i] += dist[i];
		List<KeyValuePair<McfATag, bool>> res
			= new List<KeyValuePair<McfATag, bool>>();
		int m = n2;
		while (m != n1)
		{
			res.Add(new KeyValuePair<McfATag, bool>
				(prev[m], prev[m].RightID == m));
			m = prev[m].AnotherID(m);
		}
		res.Reverse();
		return res;
	}
	public static void Test()
	{
		string[] ss = {
			"1,-1,-1,1/1,5,0,1;1,3,0,2;1,2,3,1;1,1,3,2/5",
			"1,0,0,-1,0/1,2,0,1;1,2,1,2;1,2,2,3;1,2.5,0,4;1,2.5,4,3/5",
			"70,0,0,0,-70/30,3,0,1;50,7,1,3;60,7,3,4;40,5,1,2;20,8,2,3;60,9,0,2;50,6,2,4/1080",
		};
		foreach (string t in ss)
		{
			McfGraph g = new McfGraph();
			string[] tt = t.Split('/');
			string[] nn = tt[0].Split(',');
			string[] aa = tt[1].Split(';');
			double cost, exp = double.Parse(tt[2]);
			foreach (string s in nn)
				g.AddNode(new McfNode(int.Parse(s)));
			foreach (string s in aa)
			{
				string[] a = s.Split(',');
				g.AddArc(new McfArc(int.Parse(a[0]), double.Parse(a[1])),
					int.Parse(a[2]), int.Parse(a[3]), true);
			}
			bool b = MinCostFlowProblem.Calc(g, out cost);
			Console.WriteLine("{0}, {1}", b, cost == exp);
		}
	}
}

08/04/14(月)

3月納品分の顧客からの フィードバック。
  • 一部、英語ではなく日本語にして欲しい。
  • 操作の説明が早い。
英語にしていたのは、測地系と色名。測地系は、Googleで見る限り一般に使用されている雰囲気だったのでProAtlasの名称をそのまま用いた。 今後は日本語表記も併記しよう。色名は、.NetFrameworkの列挙体Colorの名称をそのままコンボボックスから選択可能にしていた。 これを和名に直すのはつらい。名称と同時に色自体も表示しているので、それほど困るとも思えない。
説明が早いのは毎度のことなので、気をつけるようにしよう。

08/04/16(水)

数年ぶりにC++の開発だ。 開発環境は Visual Studio 2005だ。
やっぱり、C#の方が生産性が倍ぐらいいいと感じる。gccファミリにC#が入れば、移行組みも増えるのだろうか。

VS2008はライセンス持っていてインストール済みだが、ほとんど使っていない。 VSは全バージョン利用してきたが、 最新バージョンが出ても、メインの開発環境にしていないのは、VS2008 だけだ。 理由は、特にないが、私の周りも皆VS2005 だ。新人の演習もVS2005の予定。

最近は、CAPTCHAも役にたたないらしい。個人の認証ならば、 サイン方式がいいと思う。
機械をはじいて人を識別するのに猫認証というのもある。これは、普通の人があいまいな猫を識別できるの対し、 機械では困難でることを利用している。しかし、特定の画像ばかり出していれば、対策できてしまう。 例えば、ねこ認証ツールキットとして画像も出回ってしまえば、ボット作成者も容易に認証できてしまう可能性がある。 動画にしてしまえば、機械的に認識するのはより難しくなる。最近なら動的にCGを作成するのもできるだろう。 技術的には可能でも認証システムとしては大掛かりになる。しかし、どこかのベンダーが作れば、皆が利用できる。 例え、ボット作成者がツールを入手してもCGが動的にできれば、認証を機械的に作るのは困難だ。イメージとしては、 CGで動物を数匹だして、猫だけ何匹かクリックしてもらう。


08/04/17(木)

子供に特殊相対性理論を説明している。 喜んで聞いているようだが、理解しているかどうかあやしい。説明する方もあやしいのだが。 要は、早く動くと、時間がゆっくりになり、縮んで、重くなるよ、それは、観測者から見た 光の速度は一定ということから説明できるよということだ。

08/04/18(金)

401Kの運用実績を 見たら、年利-20%より悪かった。元に戻るだけでも+25%以上必要だ。目減りした額でそこそこいい車買えるね。

08/04/27(日)

囲碁の対局サーバを作った。 作ったばかりなのでバグはあるかも。
http://plaza.harmonix.ne.jp/~fakira/turedure/KomiGo.zip
使い方と特徴
  • サーバマシンでKomiGoServerを起動。
  • クライアントマシンでKomiGo.exe.configのServerNameをサーバマシンにし、KomiGoを起動。
  • 2人以上接続すれば、対局できる。途中でやめて後日再開できる。
  • 対局を観戦したり、過去の棋譜の閲覧や検討ができる。
  • 対局ごとにチャットできる。

08/06/05(木)

顧客価値
  • 私は顧客価値創造のために働いている。 自分の時間を売っている自覚はあるが、1時間いくらというわけではない。 「XXX万貰ったから、YYY時間働きます」とはしたくない。
  • たとえ、私が1時間しか作業していなくても、それで顧客が100万の利益を得る見込みがるのなら、 対価として50万円を望む。(双方の働きで100万を得たとして)
  • 逆に、ほとんどの作業は終わったとしても、 「ZZZができないと顧客価値が1銭も増えない」というのであれば、無償で作業する。 ただし、「双方に責任あり」と思われる場合は、費用の半分を請求する。
  • それは、「顧客の価値創造」に責任を持ちたいからである。
  • これらは理想ではあるが、私も所属組織もビジネスはうまくないので、上記の通りに進むことは少ない。
  • また、上記の思想を全面にアピールしているわけではない。やはり、見積は人月である。
  • 私の強みは、組合せ最適化を代表とする数理的解決方法の提供と、対応業種の幅広さである。
  • 社内では人材育成に心血を注いでいる。

08/07/01(火)

今日から 新年度。PCを変えた。Vistaなのでよくわからない。 ノートPCでスコア5だ。Expression Blendがサクサク動く。

08/07/14(月)

EeePC901を買った。 子供にあげた。結構いい。WindowsUpdateとJavaのUpdateをしたら、いきなりCドライブが足りない。 しょうがないので、Javaは消して、仮想メモリをDドライブにした。 あとは、Avira AntiVirを入れて、AcrobatReaderを消してFoxitReaderにした。

前歯が欠けた。ショック。


08/07/25(金)

1週間ほど、Willcom D4を 使っている。モバイルでは、全く使えない。 バッテリが持たないとか、でかいとか、遅いとか、熱いとか、うるさいとか、ワンセグが入らないとかいろいろあるが、 致命的なのがフリーズしまくることだ。1時間のうち10分もまともに動かない。 初期不良だろうか?どうしようもないので、リカバリした。

08/08/06(水)

ストリートビューすごいね。 30年以上前に住んでいたアパートを見たら、まだ建物が残っていた。なつかしー。 事前にこれで調べれば、初めての場所でも迷わないね。

08/08/13(水)

WPFの画像ビューアサンプル。
  • クリックで回転。
  • スライダで回転。
XAML
<Window x:Class="WpfApplication1.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera FieldOfView="50"
  LookDirection="0,-40,300" 
  Position="0,40,-200" UpDirection="0,1,0"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
  <Model3DGroup x:Name="gr">
  <AmbientLight/>
  </Model3DGroup>
  </ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
<Slider Name="slider1" VerticalAlignment="Bottom" 
  ValueChanged="slider1_ValueChanged" Maximum="360" />
<TextBox VerticalAlignment="Top" 
  Text="{Binding ElementName=slider1,Path=Value}" />
</Grid>
</Window>
CS
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
    private MyDoubleValue ta = new MyDoubleValue();
    public Window1()
    {
      InitializeComponent();
      string dir = @"C:\Users\Public\Pictures\Sample Pictures";
      List<ImageBrush> br = new List<ImageBrush>();
      foreach (string f in Directory.GetFiles(dir, "*.jpg"))
        br.Add(new ImageBrush(new BitmapImage(new Uri(f))));
      int[] ii = { 0, 3, 1, 0, 2, 3 };
      Point[] pp = { new Point(1, 1), new Point(0, 1), 
            new Point(1, 0), new Point(0, 0), };
      int n = 9;
      for (int i = 0; i < n; ++i)
      {
        GeometryModel3D gm = new GeometryModel3D();
        gr.Children.Add(gm);
        gm.Material = new DiffuseMaterial(br[i%br.Count]);
        MeshGeometry3D mg = new MeshGeometry3D();
        gm.Geometry = mg;
        double r = 2 * Math.PI * i / n;
        double x = Math.Sin(r), x1 = x * 100, x2 = x * 20;
        double z = Math.Cos(r), z1 = z * 100, z2 = z * 20;
        mg.Positions.Add(new Point3D(x1 - z2,  0, z1 + x2));
        mg.Positions.Add(new Point3D(x1 + z2,  0, z1 - x2));
        mg.Positions.Add(new Point3D(x1 - z2, 30, z1 + x2));
        mg.Positions.Add(new Point3D(x1 + z2, 30, z1 - x2));
        foreach (int j in ii) mg.TriangleIndices.Add(j);
        foreach (Point p in pp) mg.TextureCoordinates.Add(p);
      }
      gr.Transform = new RotateTransform3D();
      Binding bnd = new Binding();
      bnd.Source = ta;
      bnd.Path = new PropertyPath("MyValue");
      slider1.SetBinding(Slider.ValueProperty, bnd);
      MouseDown += new MouseButtonEventHandler(Window1_MouseDown);
    }
    void Window1_MouseDown(object sender, MouseButtonEventArgs e)
    {
      DoubleAnimation da1 = new DoubleAnimation(
        slider1.Value, slider1.Value + 40 - slider1.Value % 40, 
        new Duration(TimeSpan.FromSeconds(0.3)));
      ta.BeginAnimation(MyDoubleValue.MyValueProperty, da1);
    }
    private void slider1_ValueChanged(object sender, 
      RoutedPropertyChangedEventArgs<double> e)
    {
      RotateTransform3D rt = (RotateTransform3D)gr.Transform;
      rt.Rotation = new QuaternionRotation3D(
        new Quaternion(new Vector3D(0, 1, 0), slider1.Value));
    }
  }
  public class MyDoubleValue : UIElement
  {
    public static readonly DependencyProperty MyValueProperty
      = DependencyProperty.Register("MyValue", typeof(double), 
      typeof(MyDoubleValue), new PropertyMetadata(0.0, cb1, cb2));
    private static void cb1(DependencyObject d, DependencyPropertyChangedEventArgs w) { }
    private static object cb2(DependencyObject d, object o)
    {
      double dd = (double)o;
      return dd % 360;
    }
  }
}
解説
  • 画像は、サンプルから9個とってきている。(PathはVistaのもの)
  • 3Dモデルは、プログラムで生成している。ただの四角だけど。
  • Sliderを動かすと、絵を回転する。絵のTransfrormを予め、RotateTransform3Dにしておき、 そのRotation(QuaternionRotation3D)を置き換えている。
  • DoubleAnimationでSliderを直接アニメーションさせると、スライダが手動で動かないので、 アニメーション用データ(MyDoubleValue)を作成して使っている。このMyValueをアニメーションさせている。
  • プログラムで、MyValueとスライダをBindingしている。
  • TextBoxはXAMLでSliderとBindingしている。
  • MyDoubleValueの値は角度なので、360のModを取るようにCoerceValueCallback を定義している。
  • StoryBoardをプログラムで追加するには、Storyboard.SetTargetProperty を使えばよい。

08/08/17(日)

WPFのサンプルゲーム。
http://plaza.harmonix.ne.jp/~fakira/turedure/GAME.zip
TennisGameは、ブロックを解除して、2つ起動すると始まる。 XAMLは手書きなので、Blendでは編集できないかも。

08/08/19(火)

VS 2008 SP1を 入れた。
http://www.microsoft.com/downloads/details.aspx?FamilyId=FBEE1648-7106-44A7-9649-6D9F6D58056E&displaylang=ja

プロパティがアルファベット順だ。イベントも登録できる。いいね。 ちなみに、「Visual Studio 2008 Service Pack 準備ツール」をやらないとうまくいかなかった。
http://www.microsoft.com/downloads/details.aspx?familyid=A494B0E0-EB07-4FF1-A21C-A4663E456D9D&displaylang=ja

BlendSenseを入れると、Blendでもインテリセンスが効く。
http://d.hatena.ne.jp/Yamaki/20080806/1217998860


08/08/22(金)

メモを自分宛に メールするんだけど、届かないときがある。 フィルタリングされているようだ。

08/08/23(土)

WPFのボタン用 テンプレート3種。
<Window.Resources>
  <ControlTemplate x:Key="BtnTmplElp1" TargetType="{x:Type Button}">
    <Grid Loaded="BtnTmplElp1_Grid_Loaded">
      <Ellipse RenderTransformOrigin="0.4 0.4">
        <Ellipse.RenderTransform>
          <TransformGroup>
            <ScaleTransform ScaleX="1.05" ScaleY="1.05"/>
            <TranslateTransform X="2" Y="2"/>
          </TransformGroup>
        </Ellipse.RenderTransform>
        <Ellipse.Fill>
          <RadialGradientBrush>
            <GradientStop Color="Black" Offset="0.7"/>
            <GradientStop Color="White" Offset="1"/>
          </RadialGradientBrush>
        </Ellipse.Fill>
      </Ellipse>
      <Grid x:Name="BtnTmplElp1Grid" RenderTransformOrigin="0.5,0.5">
        <Grid.RenderTransform>
          <TranslateTransform X="0" Y="0"/>
        </Grid.RenderTransform>
        <Ellipse>
          <Ellipse.Fill>
            <RadialGradientBrush GradientOrigin="0.5,0.7">
              <GradientStop Color="#A0A0FF" Offset="0"/>
              <GradientStop Color="#273367" Offset="1"/>
            </RadialGradientBrush>
          </Ellipse.Fill>
        </Ellipse>
        <Ellipse Margin="4 0 4 24">
          <Ellipse.Fill>
            <RadialGradientBrush GradientOrigin="0.5,0.36">
              <GradientStop Color="#80FFFFFF" Offset="0.4"/>
              <GradientStop Color="#1071AB5C" Offset="1"/>
              <GradientStop Color="#FFFFFFFF" Offset="0"/>
            </RadialGradientBrush>
          </Ellipse.Fill>
        </Ellipse>
        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
      </Grid>
    </Grid>
    <ControlTemplate.Resources>
      <Storyboard x:Key="BtnTmplElp1OnPreviewMouseLeftButtonDown">
        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="BtnTmplElp1Grid" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.X)">
          <SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="5"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="BtnTmplElp1Grid" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.Y)">
          <SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="5"/>
        </DoubleAnimationUsingKeyFrames>
      </Storyboard>
      <Storyboard x:Key="BtnTmplElp1OnPreviewMouseLeftButtonUp">
        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="BtnTmplElp1Grid" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.X)">
          <SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="BtnTmplElp1Grid" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.Y)">
          <SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
      </Storyboard>
    </ControlTemplate.Resources>
    <ControlTemplate.Triggers>
      <EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonDown">
        <BeginStoryboard Storyboard="{StaticResource BtnTmplElp1OnPreviewMouseLeftButtonDown}"/>
      </EventTrigger>
      <EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonUp">
        <BeginStoryboard Storyboard="{StaticResource BtnTmplElp1OnPreviewMouseLeftButtonUp}"/>
      </EventTrigger>
    </ControlTemplate.Triggers>
  </ControlTemplate>
  <x:Code>
    <![CDATA[  
private void BtnTmplElp1_Grid_Loaded(object sender, RoutedEventArgs e)
{
var gr = sender as Grid;
var gr2 = gr.Children[1] as Grid;
var btn = gr.TemplatedParent as Button;
var el1 = gr.Children[0] as Ellipse;
double d = Math.Min(gr.ActualWidth, gr.ActualHeight);
el1.Margin = new Thickness(0, 0, d / 20, 0);
var tg = (el1.RenderTransform as TransformGroup).CloneCurrentValue();
tg.Children[1] = new TranslateTransform(d / 12, d / 12);
el1.RenderTransform = tg;
var el2 = gr2.Children[0] as Ellipse;
var br = el2.Fill.CloneCurrentValue() as RadialGradientBrush;
Color c1 = ((SolidColorBrush)btn.Background).Color;
Color c2 = Color.FromRgb((byte)(c1.R / 2), (byte)(c1.G / 2), (byte)(c1.B / 2));
br.GradientStops[0] = new GradientStop(c1, 0);
br.GradientStops[1] = new GradientStop(c2, 1);
el2.Fill = br;
var el3 = gr2.Children[1] as Ellipse;
el3.Margin = new Thickness(d / 15, 0, d / 15, d * 0.4);
}
]]>
  </x:Code>
  <ControlTemplate x:Key="BtnTmplElp2" TargetType="{x:Type Button}">
    <Grid Loaded="BtnTmplElp2_Grid_Loaded">
      <Rectangle Stroke="#FF111E4D" RadiusX="40" RadiusY="40">
        <Rectangle.Fill>
          <RadialGradientBrush  GradientOrigin="0.5,0.7">
            <GradientStop Color="#FFB6D0FF" Offset="0"/>
            <GradientStop Color="#FF6083dC" Offset="0.75"/>
            <GradientStop Color="#FF0043BC" Offset="1"/>
          </RadialGradientBrush>
        </Rectangle.Fill>
      </Rectangle>
      <Rectangle RadiusX="40" RadiusY="40" Margin="25,7,25,0" Height="24" VerticalAlignment="Top">
        <Rectangle.Fill>
          <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="#A0FFC0C0" Offset="0"/>
            <GradientStop Color="#10FFFFFF" Offset="0.7"/>
          </LinearGradientBrush>
        </Rectangle.Fill>
      </Rectangle>
      <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
      <Rectangle x:Name="BtnTmplElp2Rect" Fill="Black" Opacity="0"/>
    </Grid>
    <ControlTemplate.Resources>
      <Storyboard x:Key="BtnTmplElp2OnPreviewMouseLeftButtonDown">
        <DoubleAnimation Duration="00:00:00.1" Storyboard.TargetName="BtnTmplElp2Rect" Storyboard.TargetProperty="Opacity" To="0.2"/>
      </Storyboard>
      <Storyboard x:Key="BtnTmplElp2OnPreviewMouseLeftButtonUp">
        <DoubleAnimation Duration="00:00:00.1" Storyboard.TargetName="BtnTmplElp2Rect" Storyboard.TargetProperty="Opacity" To="0"/>
      </Storyboard>
    </ControlTemplate.Resources>
    <ControlTemplate.Triggers>
      <EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonDown">
        <BeginStoryboard Storyboard="{StaticResource BtnTmplElp2OnPreviewMouseLeftButtonDown}"/>
      </EventTrigger>
      <EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonUp">
        <BeginStoryboard Storyboard="{StaticResource BtnTmplElp2OnPreviewMouseLeftButtonUp}"/>
      </EventTrigger>
    </ControlTemplate.Triggers>
  </ControlTemplate>
  <x:Code>
<![CDATA[
private void BtnTmplElp2_Grid_Loaded(object sender, RoutedEventArgs e)
{
var gr = sender as Grid;
double d = Math.Min(gr.ActualWidth, gr.ActualHeight);
var re1 = gr.Children[0] as Rectangle;
var re3 = gr.Children[3] as Rectangle;
re1.RadiusX = re1.RadiusY = re3.RadiusX = re3.RadiusY = d * 0.4;
var br1 = re1.Fill.CloneCurrentValue() as RadialGradientBrush;
var btn = gr.TemplatedParent as Button;
var sc = btn.Background as SolidColorBrush;
Color c1 = sc != null ? sc.Color : SystemColors.WindowFrameColor;
Color c2 = Color.FromRgb((byte)(c1.R * 0.75), (byte)(c1.G * 0.75), (byte)(c1.B * 0.75));
Color c3 = Color.FromRgb((byte)(c1.R * 0.5), (byte)(c1.G * 0.5), (byte)(c1.B * 0.5));
br1.GradientStops[0] = new GradientStop(c1, 0);
br1.GradientStops[1] = new GradientStop(c2, 0.7);
br1.GradientStops[2] = new GradientStop(c3, 1);
re1.Fill = br1;
var re2 = gr.Children[1] as Rectangle;
re2.RadiusX = re2.RadiusY = d * 0.4;
re2.Height = d * 0.24;
re2.Margin = new Thickness(d * 0.24, d * 0.08, d * 0.24, 0);
var br2 = re2.Fill.CloneCurrentValue() as LinearGradientBrush;
Color c4 = Color.FromArgb(160, (byte)(c1.R * 0.2 + 204), (byte)(c1.G * 0.2 + 204), (byte)(c1.B * 0.2 + 204));
br2.GradientStops[0] = new GradientStop(c4, 0);
br2.GradientStops[1] = new GradientStop(Color.FromArgb(16,255,255,255), 0.7);
}
]]>
  </x:Code>
  <ControlTemplate x:Key="BtnTmplElp3" TargetType="{x:Type Button}">
    <Grid Loaded="BtnTmplElp3_Grid_Loaded">
      <Ellipse Stroke="#FF2C3366">
        <Ellipse.Fill>
          <LinearGradientBrush EndPoint="0.909,-0.085" StartPoint="0.1,1">
            <GradientStop Color="#F03D71CE" Offset="0.0"/>
            <GradientStop Color="#F7CFD9EB" Offset="0.5"/>
            <GradientStop Color="#FF0F3F97" Offset="1"/>
          </LinearGradientBrush>
        </Ellipse.Fill>
      </Ellipse>
      <Ellipse Margin="8,8,8,8">
        <Ellipse.Fill>
          <LinearGradientBrush EndPoint="0.3,1.5" StartPoint="0.7,-0.4">
            <GradientStop Color="#F03D71CE" Offset="0.0"/>
            <GradientStop Color="#F7CFD9EB" Offset="0.5"/>
            <GradientStop Color="#FF0F3F97" Offset="1"/>
          </LinearGradientBrush>
        </Ellipse.Fill>
      </Ellipse>
      <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
      <Ellipse x:Name="BtnTmplElp3Elps" Fill="Black" Opacity="0"/>
    </Grid>
    <ControlTemplate.Resources>
      <Storyboard x:Key="BtnTmplElp3OnPreviewMouseLeftButtonDown">
        <DoubleAnimation Duration="00:00:00.1" Storyboard.TargetName="BtnTmplElp3Elps" Storyboard.TargetProperty="Opacity" To="0.2"/>
      </Storyboard>
      <Storyboard x:Key="BtnTmplElp3OnPreviewMouseLeftButtonUp">
        <DoubleAnimation Duration="00:00:00.1" Storyboard.TargetName="BtnTmplElp3Elps" Storyboard.TargetProperty="Opacity" To="0"/>
      </Storyboard>
    </ControlTemplate.Resources>
    <ControlTemplate.Triggers>
      <EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonDown">
        <BeginStoryboard Storyboard="{StaticResource BtnTmplElp3OnPreviewMouseLeftButtonDown}"/>
      </EventTrigger>
      <EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonUp">
        <BeginStoryboard Storyboard="{StaticResource BtnTmplElp3OnPreviewMouseLeftButtonUp}"/>
      </EventTrigger>
    </ControlTemplate.Triggers>
  </ControlTemplate>
  <x:Code>
<![CDATA[
private void BtnTmplElp3_Grid_Loaded(object sender, RoutedEventArgs e)
{
var gr = sender as Grid;
double d = Math.Min(gr.ActualWidth, gr.ActualHeight);
var btn = gr.TemplatedParent as Button;
var el1 = gr.Children[0] as Ellipse;
var el2 = gr.Children[1] as Ellipse;
el2.Margin = new Thickness(d * 0.12);
var br1 = el1.Fill.CloneCurrentValue() as LinearGradientBrush;
var br2 = el2.Fill.CloneCurrentValue() as LinearGradientBrush;
var sc = btn.Background as SolidColorBrush;
Color c1 = sc != null ? sc.Color : SystemColors.WindowFrameColor;
Color c2 = Color.FromRgb((byte)(c1.R * 0.3 + 180), (byte)(c1.G * 0.3 + 180), (byte)(c1.B * 0.3 + 180));
br1.GradientStops[0] = br2.GradientStops[0] = new GradientStop(c1, 0);
br1.GradientStops[1] = br2.GradientStops[1] = new GradientStop(c2, 0.5);
br1.GradientStops[2] = br2.GradientStops[2] = new GradientStop(c1, 1);
el1.Fill = br1;
el2.Fill = br2;
}
]]></x:Code>
</Window.Resources>

08/09/02(火)

「さらば財務省!」 isbn:4062145944 を読んだ。日本国民は、須く読むべきだろう。 その上で、改革が進むことを切に願う。政党が政策によって選ばれ、政策が政治家によって決定される本来の姿への改革を。

08/09/04(木)

パンの販売が低迷しているらしい。 サンドイッチの販促の一提案。 パンと中身を別にして売る。デメリットは食べる手間がかかることだが、以下のメリットがある。
  • パンを窒素充填、中身を気密パックにするなどして賞味期限が延びる。これにより需要の変動を吸収しやすい。
  • サンドイッチ販売における最大の懸案事項である「見た目と中身の不一致」問題を解決できる。 サンドイッチ製造業界の良心を取り戻せ。
  • 賞味期限終了後に、パンをパン粉にしたり中身をコロッケの具にしたりなど、再利用しやすい。
  • パンと中身の組み合わせのバリエーションを作りやすい。
  • 食べる人が、創造の喜びを味わえる。
  • 増量キャンペーンやサンドイッチマンによる広告など。

08/09/06(土)

3目並べについての 強化学習(Q学習)の例。
http://plaza.harmonix.ne.jp/~fakira/turedure/Q-Learning.zip
更新は e-greedy。Q学習が先手で後手は以下のルールのAI。
  • 自分のリーチならそこに置いて勝つ。
  • 上記以外で、相手のリーチならそこに置いて邪魔をする。
  • 上記以外で、置くとリーチになる場所の中からランダムに選ぶ。
  • 上記以外なら、ランダムに置く。
Q学習の勝率は9割。epsを0にすれば、敗率は0。

08/10/02(木)

昨日、Vistaで突然 ブルースクリーンになって、外付けHDDが壊れていた。 何度か再起動すると、とりあえず使えるので、新しいHDDにデータを移したが、30MBぐらい足りない。 何が消えたかは、わからない。新しいHDDは、懲りずに、壊れたのとほぼ同じものを買った。

08/10/03(金)

健康診断、 精密検査になった。今までで最悪だ。初胃カメラ。視力半分だし。

08/10/06(月)

最大値の分布。 正規分布(N(a, s^2))に従うn個の乱数の最大値の密度関数は、「BPDF(n,1,NCDF((x-a)/s)) / n」を微分したものになる。 ただし、BPDFはβ分布の密度関数、NCDFは正規分布の累積密度関数である。 実際に、a=2,s=3,n=7でグラフを書くと、微妙に違う。計算誤差? 元が正規分布でなくても同様。最小値の分布は、β分布の「n,1」を「1,n」にすればよい。

08/10/09(木)

.NET Framework 3.0以上で 開発するのが多くなってきた。使えるところはほとんど var にしているが、 わかりにくくなったりはしていないように感じる。 データベースは使っていないが、LINQも使いまくっている。 Vistaをターゲットにしていると、3.0にするときもあり、そのときはLINQが使えないが。 WPFの開発も初めている。

08/10/20(月)

ちょっとでも 関係あるプロジェクトや営業案件やらが22件もある。

08/10/24(金)

提案書と仕様書4件分作った。

08/11/11(火)

今日は一並びの日だ。 11年前にもそう言ってブログを始めた。 いつまで続くやら。

08/11/14(金)

.Net Remotingで クラサバを作ったが、バックアップがうまくいかなかった。
データは、編集後、5分何もせずにいるとサーバオブジェクトがメモリアウトしてしまう。 このタイミングがとれない。(ちなみに、LifetimeService.LeaseTime を0にすればメモリアウトしない) しょうがないので、サーバが再起動するタイミング(コンストラクタ)で データのフラグをみてバックアップするようにした。 (ちなみにサーバソフトの終了時にもバックアップする)

08/11/27(木)

最小二乗法を作った。 ついでに、Excelの近似式で検証してみたら、Excelがおかしい。 (1)小数点4桁以下が丸めでなく切り捨て。(2)R2が合ってない。(3)y切片を指定すると、合わない。

08/12/05(金)

Vistaでは、UNIXと同様にシンボリックリンクを mklink で作れる。しかし、コマンドプロンプトでしかできないので不便だ。 以下のようにすれば、マウスで作れるようになる。 以下のプログラムを作成する。
if (args.Length > 0)
  Process.Start("cmd", string.Format("/c mklink {0} \"{1}_\" \"{1}\"",
    Directory.Exists(args[0]) ? "/d" : "", args[0]));
マニフェストを作成し、requestedExecutionLevel の level を requireAdministrator にする。 コンパイルしたexeを SendToに置く。これで、右クリックして「送る」メニューで作成できるが、 UACを有効にしていると、うっとおしい。UACを切るのがいやならば、Norton UAC Toolを 入れる手もある。これだと、最初の1回だけしか聞かれないようにできる。
http://www.nortonlabs.com/inthelab/uac.php

ちなみに特定のフォルダをカレントにしてコマンドプロンプトを開くのは、Shiftを押しながら フォルダを右クリックして選べばできる。


プログラミング所感 - 前へ 目次次へ