<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Unlock Particle</title>
	<atom:link href="http://catouse.com/feed" rel="self" type="application/rss+xml" />
	<link>http://catouse.com</link>
	<description>Game &#38; Graphics Programing, AI &#38; Algorithm Exercises</description>
	<lastBuildDate>Thu, 17 Mar 2011 09:13:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>追逐与拦截</title>
		<link>http://catouse.com/ai/chase-and-intercept.html</link>
		<comments>http://catouse.com/ai/chase-and-intercept.html#comments</comments>
		<pubDate>Sat, 17 Jul 2010 09:14:08 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[下载]]></category>
		<category><![CDATA[人工智能]]></category>
		<category><![CDATA[拦截]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[追逐]]></category>

		<guid isPermaLink="false">http://catouse.com/programming/%e8%bf%bd%e9%80%90%e4%b8%8e%e6%8b%a6%e6%88%aa.html</guid>
		<description><![CDATA[小时候玩过叫“打蜜蜂”的游戏。当然只是我们一厢情愿的称呼，游戏的名字叫“Galaga”。游戏的目的就是操作一架只能左右移动的战机，消灭成群的“小蜜蜂”，并且还有躲避不停非向战机的子弹和“蜜蜂”。我最喜欢里面的“嗡嗡”声。不过能及时躲过“跟踪弹”的追击才是我引以为豪的事情。可以想象如果游戏中的敌人不能跟踪我的位置，游戏将变得多么乏味。 追逐 追逐有很多种方式，这里仅讨论自然环境中的视线追逐，即追击者在看到猎物所在方位进行跟踪。这种方式很符合真实情况。 假设场景中有一个追击者A和猎物B，某时刻，追击者以速度向量u运动，猎物以速度向量v运动，B为追击者速度向量的末端点。 从追击者A的角度来看，猎物C在向量AB的左侧，向量AB与向量AC夹角为θ，追击者A只需要将自己的速度向量u逆时针旋转角度θ，即可将自身面对猎物C并向其靠近。如果C在向量AB的右侧，则需要将u顺时针旋转一定角度。由此，面临的问题就是判断猎物是在追击者速度向量左侧还是右侧。 上面的问题可以简化为判断平面上向量某一点在已知向量左侧还是右侧。当然这个问题已经有一个很好的解法。定义平面上的三点P1(x1,y1),P2(x2,y2),P3(x3,y3)的面积量为： 当P1,P2,P3逆时针时S为正的，当P1,P2,P3顺时针时S为负。 对于上图三点A，B，C，可以判断C与向量AB的位置关系： 如果S（A，B，C）为正数，则C在矢量AB的左侧； 如果S（A，B，C）为负数，则C在矢量AB的右侧； 如果S（A，B，C）为0，则C在直线AB上。 class PursueSimulator:Simulator { private PointF preyPos = new PointF(BGC.WindowSize.Width, BGC.WindowSize.Height/5);//猎物位置 private PointF predatorPos = new PointF(0, 10);//追击者位置 private PointF purposePos = PointF.Empty;//目的点 private Vector3 u = new Vector3(0.7, 0.7,0);//追击者速度向量 private Vector3 v = new Vector3(-1, 0.6,0);//猎物速度向量 private Vector3 vectorAC = new Vector3();//猎物C与追击者A方位向量 private Vector3 <p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/ai/chase-and-intercept.html">追逐与拦截</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p><!--   h3 { padding:1px 0 1px 10px; margin:0; display:block; background-color: #dfdfdf; } p { text-indent:2em; } -->小时候玩过叫“打蜜蜂”的游戏。当然只是我们一厢情愿的称呼，游戏的名字叫“<a href="http://en.wikipedia.org/wiki/Galaga">Galaga</a>”。游戏的目的就是操作一架只能左右移动的战机，消灭成群的“小蜜蜂”，并且还有躲避不停非向战机的子弹和“蜜蜂”。我最喜欢里面的“嗡嗡”声。不过能及时躲过“跟踪弹”的追击才是我引以为豪的事情。可以想象如果游戏中的敌人不能跟踪我的位置，游戏将变得多么乏味。</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/07/TheGame634149537647187500.png"><img style="display: inline; border-width: 0px;" title="The Game 634149537647187500" src="http://catouse.com/particle/wp-content/uploads/2010/07/TheGame634149537647187500_thumb.png" border="0" alt="The Game 634149537647187500" width="500" height="400" /></a></p>
<h3>追逐</h3>
<p>追逐有很多种方式，这里仅讨论自然环境中的视线追逐，即追击者在看到猎物所在方位进行跟踪。这种方式很符合真实情况。</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog1.png"><img style="display: inline; border-width: 0px;" title="predator and prey[追逐和跟踪][博客][算法][Blog]-1" src="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog1_thumb.png" border="0" alt="predator and prey[追逐和跟踪][博客][算法][Blog]-1" width="500" height="200" /></a></p>
<p>假设场景中有一个追击者A和猎物B，某时刻，追击者以速度向量<em><strong>u</strong></em>运动，猎物以速度向量<em><strong>v</strong></em>运动，B为追击者速度向量的末端点。</p>
<p>从追击者A的角度来看，猎物C在向量AB的左侧，向量AB与向量AC夹角为<strong><em>θ</em></strong>，追击者A只需要将自己的速度向量<em><strong>u</strong></em>逆时针旋转角度<em><strong>θ</strong></em>，即可将自身面对猎物C并向其靠近。如果C在向量AB的右侧，则需要将<em><strong>u</strong></em>顺时针旋转一定角度。由此，面临的问题就是判断猎物是在追击者速度向量左侧还是右侧。</p>
<p>上面的问题可以简化为判断平面上向量某一点在已知向量左侧还是右侧。当然这个问题已经有一个很好的解法。定义平面上的三点P1(x1,y1),P2(x2,y2),P3(x3,y3)的面积量为：</p>
<p><a href="http://www.codecogs.com/eqnedit.php?latex=S(P_{1},P_{2},P_{3})=\begin{vmatrix} x_{1} &amp; x_{2} &amp; x_{3}\\ y_{1} &amp; y_{2} &amp; y_{3} \\ 1 &amp; 1 &amp;1 \end{vmatrix}=(x_{1}-x_{3})*(y_{2}-y_{3})-(y_{1}-y_{3})(x_{2}-x_{3})" target="_blank"><img title="S(P_{1},P_{2},P_{3})=\begin{vmatrix} x_{1} &amp; x_{2} &amp; x_{3}\\ y_{1} &amp; y_{2} &amp; y_{3} \\ 1 &amp; 1 &amp;1 \end{vmatrix}=(x_{1}-x_{3})*(y_{2}-y_{3})-(y_{1}-y_{3})(x_{2}-x_{3})" src="http://latex.codecogs.com/gif.latex?\bg_white S(P_{1},P_{2},P_{3})=\begin{vmatrix} x_{1} &amp; x_{2} &amp; x_{3}\\ y_{1} &amp; y_{2} &amp; y_{3} \\ 1 &amp; 1 &amp;1 \end{vmatrix}=(x_{1}-x_{3})*(y_{2}-y_{3})-(y_{1}-y_{3})(x_{2}-x_{3})" alt="" /></a></p>
<p>当P1,P2,P3逆时针时S为正的，当P1,P2,P3顺时针时S为负。</p>
<p>对于上图三点A，B，C，可以判断C与向量AB的位置关系：</p>
<ul>
<li>如果S（A，B，C）为正数，则C在矢量AB的左侧；</li>
<li>如果S（A，B，C）为负数，则C在矢量AB的右侧；</li>
<li>如果S（A，B，C）为0，则C在直线AB上。</li>
</ul>
<pre class="brush: csharp; ruler: true">class PursueSimulator:Simulator
{
    private PointF preyPos = new PointF(BGC.WindowSize.Width, BGC.WindowSize.Height/5);//猎物位置
    private PointF predatorPos = new PointF(0, 10);//追击者位置
    private PointF purposePos = PointF.Empty;//目的点
    private Vector3 u = new Vector3(0.7, 0.7,0);//追击者速度向量
    private Vector3 v = new Vector3(-1, 0.6,0);//猎物速度向量
    private Vector3 vectorAC = new Vector3();//猎物C与追击者A方位向量
    private Vector3 aRcSpeed = new Vector3();//追击者A对于猎物C的相对速度向量
    private double rollAngle = 0;//偏转角度
    private double rollDirection = 0;//偏转方向,&gt;0:逆时针偏

    private Pen pen1 = new Pen(Color.FromArgb(20, Color.Gray));//画笔1
    private Pen pen2 = new Pen(Color.FromArgb(20, Color.Yellow));//画笔2

    //每次刷新画面逻辑时调用
    public override void Render()
    {
        #region 猎物和追击者按照预计速度运动
        predatorPos.X += (float)u.X;
        predatorPos.Y += (float)u.Y;
        preyPos.X += (float)v.X;
        preyPos.Y += (float)v.Y;
        #endregion

        #region 保证猎物和追击者遇到边界方向反弹
	//...
        #endregion

        vectorAC.X = preyPos.X - predatorPos.X;
        vectorAC.Y = preyPos.Y - predatorPos.Y;
        vectorAC.Z = 0;

        purposePos = preyPos;//追击者目的点为猎物

	//
	// <strong>标记A</strong>
	//

	//获取追击者速度方向与猎物方位方向,便计算更真实的转角
        rollAngle = Vector3.Angle(u, vectorAC);
        rollDirection = (predatorPos.X - purposePos.X) * (predatorPos.Y + u.Y - purposePos.Y) - (predatorPos.Y - purposePos.Y) * (predatorPos.X + u.X - purposePos.X);

        if (rollDirection &gt; 0)
            u.Roll(Math.Max(rollAngle/3.0, Math.PI/360.0));
        else if (rollDirection &lt; 0)
            u.Roll(-Math.Max(rollAngle/3.0, Math.PI/360.0));
    }

    //每次重绘画面时调用
    public override void ReDraw(Graphics g)
    {
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.DrawEllipse(pen1, predatorPos.X - 4, predatorPos.Y - 2, 8, 8);
        g.DrawEllipse(pen2, preyPos.X - 4, preyPos.Y - 2, 8, 8);
    }
}</pre>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog2.png"><img style="display: inline; border-width: 0px;" title="predator and prey[追逐和跟踪][博客][算法][Blog]-2" src="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog2_thumb.png" border="0" alt="predator and prey[追逐和跟踪][博客][算法][Blog]-2" width="500" height="296" /></a></p>
<p>上图中，白色轨迹为追击者。可见追击者已经能很好的追逐猎物，而且过渡自然。</p>
<h3>拦截</h3>
<p>拦截是追逐的一种，不过有很大的不同。拦截是通过预测猎物的运动方向和速度大小，直接以预定位置为目标，达到目标后与猎物相遇。通常拦截是更明智的做法，即使追逐者的速度比猎物小，通过有效的拦截也能达到目标。</p>
<p>不过从编程来说实现拦截也是很简单。在追逐算法中，追击者只需要以猎物为目标，并调整自己的方向即可。而拦截中，追击者预测猎物位置，并以预测点位置为目标，调整自己的方向就可以到达预测地点。由此说来，仅需要解决的一个问题是计算猎物和追击者能够相遇的预测点。</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog3.png"><img style="display: inline; border-width: 0px;" title="predator and prey[追逐和跟踪][博客][算法][Blog]-3" src="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog3_thumb.png" border="0" alt="predator and prey[追逐和跟踪][博客][算法][Blog]-3" width="500" height="200" /></a></p>
<p>计算预测点可以通过下面的方法：</p>
<ol>
<li>计算追击者与猎物的相对速度，即猎物与追击者的速度向量差<strong><em>Vt=v-u</em></strong>；</li>
<li>计算两者间的距离向量<strong><em>S = AC</em></strong>；</li>
<li>由以上条件可以计算追击者与猎物相遇的时间<strong><em>T=|S|/|Vt|;</em></strong></li>
<li>相遇点距离追击者的向量<strong><em>St=OA+T*v</em></strong>;（O为坐标原点）</li>
</ol>
<p>在追逐的算法中，只需要在追逐角度计算之前将追逐的目标置为预测点。</p>
<p>将以下代码插入到上面的代码“标记A处”：</p>
<pre class="brush: csharp; ruler: true">	#region 拦截
	aRcSpeed = v - u;
	time = vectorAC.Magnitude / aRcSpeed.Magnitude;
	//计算预测点,并将追击者目的点置为预测点
	purposePos = new PointF((float)(preyPos.X + v.X * time), (float)(preyPos.Y + v.Y * time));
	#endregion</pre>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog4.png"><img style="display: inline; border-width: 0px;" title="predator and prey[追逐和跟踪][博客][算法][Blog]-4" src="http://catouse.com/particle/wp-content/uploads/2010/07/predatorandpreyBlog4_thumb.png" border="0" alt="predator and prey[追逐和跟踪][博客][算法][Blog]-4" width="500" height="264" /></a></p>
<h3>模拟程序下载</h3>
<p>下载地址： <a href="http://dl.dropbox.com/u/2951049/%E8%BF%BD%E9%80%90%E4%B8%8E%E6%8B%A6%E6%88%AA%E6%B5%8B%E8%AF%95.zip" target="_blank">Dropbox</a> | <a href="http://www.dbank.com/download.action?t=40&amp;k=NDEzOTMxMjE=&amp;pcode=LCwzMDU1NDIsMzA1NTQy&amp;rnd=4" target="_blank">DBank</a> | <a href="http://www.uushare.com/user/catouse/file/3282709" target="_blank">UUShare</a></p>
<p>最后附送模拟程序壁纸一张，点击图片查看大图（1280&#215;800）</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/07/TheGame6341498347884375001.png"><img style="display: inline; margin-left: 0px; margin-right: 0px; border: 0px;" title="The Game 634149834788437500" src="http://catouse.com/particle/wp-content/uploads/2010/07/TheGame634149834788437500_thumb1.png" border="0" alt="The Game 634149834788437500" width="244" height="154" align="left" /></a></p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/ai/chase-and-intercept.html">追逐与拦截</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/ai/chase-and-intercept.html/feed</wfw:commentRss>
		<slash:comments>232</slash:comments>
		</item>
		<item>
		<title>亦歌mini</title>
		<link>http://catouse.com/soft/1gmini.html</link>
		<comments>http://catouse.com/soft/1gmini.html#comments</comments>
		<pubDate>Sun, 09 May 2010 12:25:15 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[Beta]]></category>
		<category><![CDATA[Download]]></category>
		<category><![CDATA[下载]]></category>
		<category><![CDATA[亦歌mini]]></category>
		<category><![CDATA[软件]]></category>

		<guid isPermaLink="false">http://catouse.com/software/%e4%ba%a6%e6%ad%8cmini.html</guid>
		<description><![CDATA[亦歌mini是亦歌的又一个桌面扩展应用.一个透明可定制颜色的桌面浮动面板,可以显示歌词和进行播放操作,支持全局快捷键,自动检测到其他打开的亦歌客户端并配合其来使用. 亦歌mini包含了亦歌本身的所有功能,还具有以下特色功能: 简洁美观的交互界面,浮动桌面面板,可以显示歌词,支持鼠标控制播放. 随意更改面板颜色,可定制的背景透明度,拖动改变面板大小,个性搭配你的桌面环境. 全局快捷键响应,无需打断当前工作,随时切换和收藏歌曲. 内置亦歌桌面版,不用打开浏览器也可以享受亦歌,启动时可以跳过桌面版显示,仅显示亦歌mini. 多种使用模式,启动时自动检测已经打开的亦歌(用其他方式打开的亦歌,比如浏览器,亦歌桌面版,跨平台Air等),轻松搭配任意客户端使用亦歌. 绿色单文件程序,无需安装,还可以装进你的U盘使用. 下载: SkyDrive &#124; Dropbox &#124; UUShare &#124; box.net 现在可以去http://mini.1g1g.org下载最新版 注意:仅支持32位Windows操作系统,包括Windows7, Vista,  Xp Xp用户如果没有安装.net framework需要自行安装,可以从这里下载安装包(.net framework 2.0) 需要的其他组件:adobe flash player activeX 亦歌mini的创意得感谢airplay这么好的作品,还有@fatboy等热心朋友的大力帮助. 欢迎大家给我意见反馈,Gtalk: catouse[@]gmail.com. 本文:亦歌mini 发表自: Unlock Particle 提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/soft/1gmini.html">亦歌mini</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p><strong><a href="http://mini.1g1g.org/">亦歌mini</a></strong>是<a href="http://1g1g.com">亦歌</a>的又一个桌面扩展应用.一个透明可定制颜色的桌面浮动面板,可以显示歌词和进行播放操作,支持全局快捷键,自动检测到其他打开的亦歌客户端并配合其来使用.</p>
<p><img style="display: inline; border-width: 0px;" title="亦歌Mini2" src="http://catouse.com/particle/wp-content/uploads/2010/05/Mini2_thumb.png" border="0" alt="亦歌Mini2" width="500" height="420" /></p>
<p>亦歌mini包含了亦歌本身的所有功能,还具有以下特色功能:</p>
<ol>
<li>简洁美观的交互界面,浮动桌面面板,可以显示歌词,支持鼠标控制播放.</li>
<li>随意更改面板颜色,可定制的背景透明度,拖动改变面板大小,个性搭配你的桌面环境.</li>
<li>全局快捷键响应,无需打断当前工作,随时切换和收藏歌曲.</li>
<li>内置亦歌桌面版,不用打开浏览器也可以享受亦歌,启动时可以跳过桌面版显示,仅显示亦歌mini.</li>
<li>多种使用模式,启动时自动检测已经打开的亦歌(用其他方式打开的亦歌,比如浏览器,亦歌桌面版,跨平台Air等),轻松搭配任意客户端使用亦歌.</li>
<li>绿色单文件程序,无需安装,还可以装进你的U盘使用.</li>
</ol>
<p>下载: <a href="http://cid-9c09a4118a4899cb.skydrive.live.com/self.aspx/.Public/%E4%BA%A6%E6%AD%8Cmini-1.2.67.zip">SkyDrive</a> | <a href="https://dl.dropbox.com/u/2951049/%E4%BA%A6%E6%AD%8Cmini-1.2.67.zip">Dropbox</a> | <a href="http://www.uushare.com/user/catouse/file/2988608">UUShare</a> | <a href="http://www.box.net/shared/0cua1ed3fu">box.net</a> <strong> 现在可以去</strong><a href="http://mini.1g1g.org"><strong>http://mini.1g1g.org</strong></a><strong>下载最新版</strong></p>
<p><strong>注意</strong>:仅支持32位Windows操作系统,包括Windows7, Vista,  Xp</p>
<p>Xp用户如果没有安装.net framework需要自行安装,可以从<a href="http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&amp;FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5">这里下载安装包</a>(.net framework 2.0)</p>
<p>需要的其他组件:<a href="http://get.adobe.com/flashplayer/thankyou/activex/?installer=Flash">adobe flash player activeX</a></p>
<p>亦歌mini的创意得感谢<a href="http://www.podez.com/">airplay</a>这么好的作品,还有@fatboy等热心朋友的大力帮助.<br />
欢迎大家给我意见反馈,Gtalk: catouse[@]gmail.com.</p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/soft/1gmini.html">亦歌mini</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/soft/1gmini.html/feed</wfw:commentRss>
		<slash:comments>214</slash:comments>
		</item>
		<item>
		<title>制作亦歌mini</title>
		<link>http://catouse.com/soft/1gmini-develop.html</link>
		<comments>http://catouse.com/soft/1gmini-develop.html#comments</comments>
		<pubDate>Sat, 08 May 2010 10:02:00 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[亦歌]]></category>
		<category><![CDATA[亦歌mini]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[软件]]></category>

		<guid isPermaLink="false">http://catouse.com/software/%e5%88%b6%e4%bd%9c%e4%ba%a6%e6%ad%8cmini.html</guid>
		<description><![CDATA[亦歌是我喜欢的在线音乐播放器.美观的界面,简洁的操作,打开浏览器就能收听歌曲.最大的特色是无需维护播放列表,亦歌会根据用户听歌习惯源源不断的推送更符合口味的歌曲到播放列表.这很好的满足了像我这种懒人也能亲近音乐.我使用亦歌时要做的就一件事情:喜欢听的歌曲收藏,不喜欢听的直接pass,遇到讨厌的歌手加入黑名单.其他的交给亦歌吧. 亦歌通常需要打开浏览器使用.幸好亦歌开放了API,这得以让满足各种需要的扩展应用产生.比如亦歌桌面版就可以把亦歌搬到桌面上,不必打开浏览器就可以使用.不过对于我这种懒人,还不满足,我需要在桌面上显示歌词,并进行一些播放的操作,而且还有足够简洁.为了更懒,我决定自己重新做一个桌面扩展应用.这开始于那天我在亦歌扩展开发网页上乱逛.我把这个应用称为亦歌mini. 第一天,我编程测试了亦歌api在.net上的可行性,并且特意编写了一个控制1gCommander的对象. 第二天,我开始在Photoshop上设计我的mini界面了.开始时我也是按照常规的思路,左边是操作按钮,右边是歌词显示,不过我马上想到了Airplay的超酷交互模式.实际上操作按钮仅在鼠标接近时才起作用,为何不能仅在有可能用到时再显示呢.这样可以留出全新的空间为歌词显示所用.后来我遇到的问题是怎样合理配色,绘制阴影,边框,渐变背景,设定面板大小等.就反复测试不同的界面,并且编程实现,不过大多自己都不满意.这天几乎是通宵未睡. 为了更加完美,第三天差不多花了半天时间在界面上,剩下的时间就是完善程序配置,加入全局快捷键功能.还好这都很快.接下来我又对一些小错误进行了改正,总算是完成了第一个版本. 就这样整整花了三天时间,结果还算满意,自己用起来也很爽.我可以在桌面上看到歌词了.我的最初要求就是这些.我不用再去理会亦歌原来的播放器界面,我只需要喜欢的歌曲就收藏,不喜欢的Pass.这一切都可以通过亦歌mini的快捷键完成,或者直接在面板上通过鼠标完成.真是很方便! 后来我把这个发给我的朋友,没想到大家都喜欢.这鼓励我继续完善亦歌mini,并分享给大家. 大家可以到这里看到亦歌mini的最新信息. 本文:制作亦歌mini 发表自: Unlock Particle 提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/soft/1gmini-develop.html">制作亦歌mini</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/Mini2.png"></a></p>
<p><a href="http://1g1g.com">亦歌</a>是我喜欢的在线音乐播放器.美观的界面,简洁的操作,打开浏览器就能收听歌曲.最大的特色是无需维护播放列表,亦歌会根据用户听歌习惯源源不断的推送更符合口味的歌曲到播放列表.这很好的满足了像我这种懒人也能亲近音乐.我使用亦歌时要做的就一件事情:喜欢听的歌曲收藏,不喜欢听的直接pass,遇到讨厌的歌手加入黑名单.其他的交给亦歌吧.</p>
<p>亦歌通常需要打开浏览器使用.幸好亦歌开放了API,这得以让满足各种需要的扩展应用产生.比如<a href="http://www.1g1g.com/extensions.html#desktop_cbq">亦歌桌面版</a>就可以把亦歌搬到桌面上,不必打开浏览器就可以使用.不过对于我这种懒人,还不满足,我需要在桌面上显示歌词,并进行一些播放的操作,而且还有足够简洁.为了更懒,我决定自己重新做一个桌面扩展应用.这开始于那天我在亦歌扩展开发网页上乱逛.我把这个应用称为<strong><a href="http://catouse.com/software/1gmini.html">亦歌mini</a></strong>.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/Mini.png"><img style="display: inline; border: 0px;" title="亦歌Mini" src="http://catouse.com/particle/wp-content/uploads/2010/05/Mini_thumb.png" border="0" alt="亦歌Mini" width="500" height="374" /></a></p>
<p>第一天,我编程测试了亦歌api在.net上的可行性,并且特意编写了一个控制1gCommander的对象.</p>
<p>第二天,我开始在Photoshop上设计我的mini界面了.开始时我也是按照常规的思路,左边是操作按钮,右边是歌词显示,不过我马上想到了<a href="http://www.podez.com/">Airplay</a>的超酷交互模式.实际上操作按钮仅在鼠标接近时才起作用,为何不能仅在有可能用到时再显示呢.这样可以留出全新的空间为歌词显示所用.后来我遇到的问题是怎样合理配色,绘制阴影,边框,渐变背景,设定面板大小等.就反复测试不同的界面,并且编程实现,不过大多自己都不满意.这天几乎是通宵未睡.</p>
<p>为了更加完美,第三天差不多花了半天时间在界面上,剩下的时间就是完善程序配置,加入全局快捷键功能.还好这都很快.接下来我又对一些小错误进行了改正,总算是完成了第一个版本.</p>
<p>就这样整整花了三天时间,结果还算满意,自己用起来也很爽.我可以在桌面上看到歌词了.我的最初要求就是这些.我不用再去理会亦歌原来的播放器界面,我只需要喜欢的歌曲就收藏,不喜欢的Pass.这一切都可以通过亦歌mini的快捷键完成,或者直接在面板上通过鼠标完成.真是很方便!</p>
<p>后来我把这个发给我的朋友,没想到大家都喜欢.这鼓励我继续完善<a href="http://catouse.com/software/1gmini.html">亦歌mini</a>,并分享给大家.</p>
<p><a href="http://catouse.com/software/1gmini.html">大家可以到这里看到亦歌mini的最新信息.</a></p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/soft/1gmini-develop.html">制作亦歌mini</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/soft/1gmini-develop.html/feed</wfw:commentRss>
		<slash:comments>38</slash:comments>
		</item>
		<item>
		<title>到底有多少条路?</title>
		<link>http://catouse.com/c-sharp-coding/how-many-ways.html</link>
		<comments>http://catouse.com/c-sharp-coding/how-many-ways.html#comments</comments>
		<pubDate>Sun, 02 May 2010 19:40:09 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[C-Sharp]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[动态规划]]></category>
		<category><![CDATA[归纳法]]></category>
		<category><![CDATA[杨辉三角]]></category>
		<category><![CDATA[谜题]]></category>
		<category><![CDATA[路径]]></category>
		<category><![CDATA[递推]]></category>

		<guid isPermaLink="false">http://catouse.com/c-sharp-%e7%bc%96%e7%a8%8b/%e5%88%b0%e5%ba%95%e6%9c%89%e5%a4%9a%e5%b0%91%e6%9d%a1%e8%b7%af.html</guid>
		<description><![CDATA[今天(已经是昨天了)又翻了翻《啊哈,灵机一动》(马丁·加德纳著),有个排列组合的谜题是复杂的路.要求就是寻找在一个错综复杂的路径图里面从一个节点到另一个节点的所有可行路径数目.已规定每次我只能选择向右或者向上移动一个位置. 比如上图是一个棋盘形式的路径图,比较容易找规律,如果我愿意花一个钟头的时间的话,我可以把所有路径列举出来,如果顺利的话,我想可以给我更少的时间.我小时候总是为自己能很快而准确的列举找到答案而洋洋得意.我还记得小时候寻找一个笼子里面兔子和鸡的合适数目,我忙碌的在草稿纸上列举所有兔子的腿数和鸡的腿数. 虽然我知道很少有人愿意按照上面的方法去得到答案,但是如果去做了,我肯定能从中找到规律.不过下面从一个格子开始分析,这样也许是一个很不错的尝试.当我被迫要打开柜子所有抽屉找到所有装了纽扣的抽屉时,从第一个抽屉开始,是个明智的决定,这样不至于后来一团糟,想象一下,当你最后都不知道打开哪些抽屉而又不得不再次打开验证时是多么的令人沮丧. 显而易见,在一个格子里面,从左下角到右上角有两种路径.如上图A→C→B和A→D→B. 为了更好的表现每个节点上到达该节点的路径数目,可以及时的把数目标注上,如上图所示.这样看起来好极了,我开始迫不及待的按照这种方法在棋盘的每个格子的节点上开始标记. 我做的很快.我还不知道是否是正确的,但我很兴奋,没有什么能够阻止我继续写下这些数,不停计算100以内加法对我是一件很过瘾的事情.真不可思议,一分钟内我列举出了所有的数目,我认为肯定是正确的,我必须要证明.归纳法无疑是一个很不错的证明. 已知第一个格子里面,除右上角的节点,其他三个节点的数目已知全部为1,可知从第一个格子的左下角到右上角有两条不同路径.记值为2。有谁还怀疑1+1=2呢? 对于非十字型节点,也可以当做十字形节点处理,把节点左边和下边的十字分支数目定为0 参照下图,假如我已经知道某个节点左边节点和下面节点值的话,只要把这两个值做加法就是该节点值 再次回到这些棋盘上面的数字,总是相邻两个方向的数字做加法得到下一个节点值.把棋盘旋转45°.真难以置信,这不就是杨辉三角吗?这使我想到当把一个没有头脑的虫子放在棋盘左下角让其按照谜题规律移动,那么这些数字足以代表虫子到达某节点的可能性.在加德纳的《啊哈,灵机一动》书上,谜题本身是苏珊为了避免上学碰到讨厌的斯蒂克而需要每天走不同的路径.呵呵,如果加德纳进一步把这个故事扩展的话.我想苏珊可以完全有根据的选择那些斯蒂克选择可能性小的路径.当然我们得残忍的先认同斯蒂克像虫子一样.杨辉三角最重要的性质是第n行的所有数列式n次二项式展开式的系数列.这也很好的说明了到达节点的概率性. 现在我可以欢呼了.甚至像下图这种不规则格子地图也能用这种方法得到正确答案. 也许已经取得了很大的胜利了,不过我已经厌倦了在每个节点做加法.当有一个复杂的棋盘地图或者蜂窝地图时我就不能逼迫自己做着机械的加法.我需要计算机来帮助我得到一个简洁的答案. 我之所以在上面对这个谜题进行分析,是因为我在看书联想到上周上课时练习的几道动态规划问题.寻找路径问题,可以归结为一个简单的递推.而动态规划能够保正每个节点仅被计算一次,减少重复计算.实际上,我在上面的操作中,就是一个手工的动态规划演绎过程. 下面使用动态规划的方法来重新分析棋盘路径问题,并尝试给出算法. 不妨做如下定义:给棋盘上的每个节点定义坐标,最左下方的为f(0,0),最有上方的为f(M,N). 该问题子问题就可以描述为:从(0,0)走到(x,y),每次只能往右或者往上走一步(对应坐标值增1),一共有多少种走法,该点走法的数目记为f(x,y),原问题就是求解f(M,N) 要得到f(x,y)有两个方法,一个是从(x-1，y)往右走一步到(x,y),另一个就是从(x,y-1)走到(x,y).第一个方法有f(x-1,y)种走法,第二种有f(x,y-1)种走法.所以可以得到f(x,y)=f(x-1,y)+f(x,y-1),这个可以通过归纳法证明.由此得到递推公式为: 当x=0或y=0时,f(x,y) = 1; 当x&#62;0且y&#62;0时,f(x,y)=f(x-1,y)+f(x,y-1) /// 求解到坐标(m,n)的不同路径数目 public int HowManyWays(int m,int n) { //创建一个二维表来保存每个节点的路径数目值 int[,] answerMap = new int[m, n]; //初始化表中所有值为1 for (int i = 0; i &#60; m; i++) for (int j = 0; j &#60; n; j++) <p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/how-many-ways.html">到底有多少条路?</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p><span style="text-decoration: line-through;"><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog1.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-1" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog1_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-1" width="263" height="281" /></a> </span></p>
<p><span style="text-decoration: line-through;">今天</span>(已经是昨天了)又翻了翻《<a href="http://book.douban.com/subject/2249354/">啊哈,灵机一动</a>》(<a href="http://zh.wikipedia.org/zh-cn/%E9%A9%AC%E4%B8%81%C2%B7%E5%8A%A0%E5%BE%B7%E7%BA%B3">马丁·加德纳</a>著),有个排列组合的谜题是<strong>复杂的路</strong>.要求就是寻找在一个错综复杂的路径图里面从一个节点到另一个节点的所有可行路径数目.已规定每次我只能选择向右或者向上移动一个位置.</p>
<p>比如上图是一个棋盘形式的路径图,比较容易找规律,如果我愿意花一个钟头的时间的话,我可以把所有路径列举出来,如果顺利的话,我想可以给我更少的时间.我小时候总是为自己能很快而准确的列举找到答案而洋洋得意.我还记得小时候寻找一个笼子里面兔子和鸡的合适数目,我忙碌的在草稿纸上列举所有兔子的腿数和鸡的腿数.</p>
<p>虽然我知道很少有人愿意按照上面的方法去得到答案,但是如果去做了,我肯定能从中找到规律.不过下面从一个格子开始分析,这样也许是一个很不错的尝试.当我被迫要打开柜子所有抽屉找到所有装了纽扣的抽屉时,从第一个抽屉开始,是个明智的决定,这样不至于后来一团糟,想象一下,当你最后都不知道打开哪些抽屉而又不得不再次打开验证时是多么的令人沮丧.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog2.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-2" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog2_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-2" width="263" height="281" /></a></p>
<p>显而易见,在一个格子里面,从左下角到右上角有两种路径.如上图A→C→B和A→D→B.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog3.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-3" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog3_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-3" width="263" height="281" /></a></p>
<p>为了更好的表现每个节点上到达该节点的路径数目,可以及时的把数目标注上,如上图所示.这样看起来好极了,我开始迫不及待的按照这种方法在棋盘的每个格子的节点上开始标记.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog4.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-4" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog4_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-4" width="263" height="281" /></a></p>
<p>我做的很快.我还不知道是否是正确的,但我很兴奋,没有什么能够阻止我继续写下这些数,不停计算100以内加法对我是一件很过瘾的事情.真不可思议,一分钟内我列举出了所有的数目,我认为肯定是正确的,我必须要证明.归纳法无疑是一个很不错的证明.</p>
<ol>
<li>已知第一个格子里面,除右上角的节点,其他三个节点的数目已知全部为1,可知从第一个格子的左下角到右上角有两条不同路径.记值为2。有谁还怀疑1+1=2呢?</li>
<li>对于非十字型节点,也可以当做十字形节点处理,把节点左边和下边的十字分支数目定为0<br />
<a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog7.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-7" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog7_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-7" width="263" height="281" /></a></li>
<li>参照下图,假如我已经知道某个节点左边节点和下面节点值的话,只要把这两个值做加法就是该节点值<br />
<a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog8.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-8" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog8_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-8" width="263" height="281" /></a></li>
</ol>
<p>再次回到这些棋盘上面的数字,总是相邻两个方向的数字做加法得到下一个节点值.把棋盘旋转45°.真难以置信,这不就是杨辉三角吗?这使我想到当把一个没有头脑的虫子放在棋盘左下角让其按照谜题规律移动,那么这些数字足以代表虫子到达某节点的可能性.在加德纳的《<a href="http://book.douban.com/subject/2249354/">啊哈,灵机一动</a>》书上,谜题本身是苏珊为了避免上学碰到讨厌的斯蒂克而需要每天走不同的路径.呵呵,如果加德纳进一步把这个故事扩展的话.我想苏珊可以完全有根据的选择那些斯蒂克选择可能性小的路径.当然我们得残忍的先认同斯蒂克像虫子一样.杨辉三角最重要的性质是第n行的所有数列式n次二项式展开式的系数列.这也很好的说明了到达节点的概率性.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog6.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-6" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog6_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-6" width="263" height="281" /></a></p>
<p>现在我可以欢呼了.甚至像下图这种不规则格子地图也能用这种方法得到正确答案.</p>
<p><a href="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog5.png"><img style="display: inline; border-width: 0px;" title="How many ways[从A到B有多少条路][博客][算法][Blog]-5" src="http://catouse.com/particle/wp-content/uploads/2010/05/HowmanywaysABBlog5_thumb.png" border="0" alt="How many ways[从A到B有多少条路][博客][算法][Blog]-5" width="263" height="281" /></a></p>
<p>也许已经取得了很大的胜利了,不过我已经厌倦了在每个节点做加法.当有一个复杂的棋盘地图或者蜂窝地图时我就不能逼迫自己做着机械的加法.我需要计算机来帮助我得到一个简洁的答案.</p>
<p>我之所以在上面对这个谜题进行分析,是因为我在看书联想到上周上课时练习的几道动态规划问题.寻找路径问题,可以归结为一个简单的递推.而动态规划能够保正每个节点仅被计算一次,减少重复计算.实际上,我在上面的操作中,就是一个手工的动态规划演绎过程.</p>
<p>下面使用动态规划的方法来重新分析棋盘路径问题,并尝试给出算法.</p>
<p>不妨做如下定义:给棋盘上的每个节点定义坐标,最左下方的为<strong><em>f(0,0)</em></strong>,最有上方的为<em><strong>f(M,N)</strong></em>.</p>
<p>该问题子问题就可以描述为:从<em>(0,0)</em>走到<em>(x,y)</em>,每次只能往右或者往上走一步(对应坐标值增1),一共有多少种走法,该点走法的数目记为<em>f(x,y)</em>,原问题就是求解<em>f(M,N)</em></p>
<p>要得到f(x,y)有两个方法,一个是从<em>(x-1，y)</em>往右走一步到<em>(x,y)</em>,另一个就是从<em>(x,y-1)</em>走到<em>(x,y)</em>.第一个方法有<em>f(x-1,y)</em>种走法,第二种有<em>f(x,y-1)</em>种走法.所以可以得到<em><strong>f(x,y)=f(x-1,y)+f(x,y-1)</strong></em>,这个可以通过归纳法证明.由此得到递推公式为:</p>
<ol>
<li>当<em>x=0</em>或<em>y=0</em>时,<em>f(x,y) = 1</em>;</li>
<li>当<em>x&gt;0</em>且<em>y&gt;0</em>时<em>,f(x,y)=f(x-1,y)+f(x,y-1)</em></li>
</ol>
<pre class="brush: csharp; ruler: true">/// 求解到坐标(m,n)的不同路径数目
public int HowManyWays(int m,int n)
{
    //创建一个二维表来保存每个节点的路径数目值
    int[,] answerMap = new int[m, n];
    //初始化表中所有值为1
    for (int i = 0; i &lt; m; i++)
        for (int j = 0; j &lt; n; j++)
            answerMap[i, j] = 1;

    //使用递推来得到每个节点的解
    for (int i = 1; i &lt; m; i++)
        for (int j = 1; j &lt; n; j++)
            answerMap[i, j] = answerMap[i - 1, j] + answerMap[i, j - 1];

    //返回结果
    return answerMap[m - 1, n - 1];
}</pre>
<p>这个算法也就是计算了杨辉三角.如果要计算非规则的棋盘地图节点路径的话,就不能使用简单的二维表,可以考虑使用树形结构或者图来存储地图节点关系数据.不同的移动规则也影响算法过程.</p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/how-many-ways.html">到底有多少条路?</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/c-sharp-coding/how-many-ways.html/feed</wfw:commentRss>
		<slash:comments>519</slash:comments>
		</item>
		<item>
		<title>使用C#Lambda进行泛型参数的数值运算</title>
		<link>http://catouse.com/c-sharp-coding/genericparametersoperation.html</link>
		<comments>http://catouse.com/c-sharp-coding/genericparametersoperation.html#comments</comments>
		<pubDate>Sat, 20 Mar 2010 18:29:21 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[C-Sharp]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[泛型]]></category>
		<category><![CDATA[表达式树]]></category>

		<guid isPermaLink="false">http://catouse.com/?p=21</guid>
		<description><![CDATA[做天写了一个矩阵运算类,我尝试了用泛型来实现,很明显泛型能在我给我的矩阵应用带来更多的选择.矩阵运算在游戏及其AI运用很广泛.不过后来我一想,还是没有必要运用泛型实现.不过昨天的经历让我有兴趣和大家讨论一下C#泛型参数的值运算问题:泛型参数带来的好处的同时也不能忽视其局限性. 泛型参数应用的一个很老的例子就是交换两个数的值了,比如下面的方法实现了两个任意值类型参数的值交换: public void Swap(ref T a, ref T b) { T temp = a; a = b; b = temp; } 当然此方法不能应用于引用类型参数,为了防止泛型编程过程中,不恰当的调入应用参数增加隐性bug,C#对泛型增加了参数约束.在C#中参数约束是通过where关键字实现的,关于更多的泛型参数约束请参考MSDN 上面的方法中参数a,b肯定只能是值类型,所以修正程序第一行如下: public void Swap(ref T a, ref T b) where T:struct 现在我们讨论的不是泛型的概念,不妨考虑一下以下问题: 能否通过泛型实现一个方法来返回所有参数中最大的那个呢? 能否通过泛型实现一个方法来得到一个泛型参数的倒数呢? 能否计算方法中泛型参数的绝对值,或者取负呢? &#8230; 就拿第一个问题吧,很可能我们会写出下面的代码: public T GetTheGreater(T a, T b) where T:struct { if(a&#62;b) return a; else return b; <p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/genericparametersoperation.html">使用C#Lambda进行泛型参数的数值运算</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p>做天写了一个矩阵运算类,我尝试了用泛型来实现,很明显泛型能在我给我的矩阵应用带来更多的选择.矩阵运算在游戏及其AI运用很广泛.不过后来我一想,还是没有必要运用泛型实现.不过昨天的经历让我有兴趣和大家讨论一下C#泛型参数的值运算问题:<strong>泛型参数带来的好处的同时也不能忽视其局限性</strong>.</p>
<p>泛型参数应用的一个很老的例子就是交换两个数的值了,比如下面的方法实现了两个任意值类型参数的值交换:</p>
<pre class="brush: csharp; ruler: true">public void Swap(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}</pre>
<p>当然此方法不能应用于引用类型参数,为了防止泛型编程过程中,不恰当的调入应用参数增加隐性bug,C#对泛型增加了参数约束.在C#中参数约束是通过<strong>where</strong>关键字实现的,关于更多的泛型参数约束请参考<a href="http://msdn.microsoft.com/zh-cn/library/d5x73970.aspx">MSDN</a><br />
上面的方法中参数a,b肯定只能是值类型,所以修正程序第一行如下:</p>
<pre class="brush: csharp; ruler: true;highlight: [1]">public void Swap(ref T a, ref T b) where T:struct</pre>
<p>现在我们讨论的不是泛型的概念,不妨考虑一下以下问题:</p>
<ol>
<li>能否通过泛型实现一个方法来返回所有参数中最大的那个呢?</li>
<li>能否通过泛型实现一个方法来得到一个泛型参数的倒数呢?</li>
<li>能否计算方法中泛型参数的绝对值,或者取负呢?</li>
<li>&#8230;</li>
</ol>
<p>就拿第一个问题吧,很可能我们会写出下面的代码:</p>
<pre class="brush: csharp; ruler: true">public T GetTheGreater(T a, T b) where T:struct
{
    if(a&gt;b)
        return a;
    else
        return b;
}</pre>
<p>世界上的事情总是有倒霉的一半,程序的第三行不会通过编译检查,已经很明了了,泛型参数是不能进行逻辑判断运算,至少不能进行大于的比较运算.实际上包括所有的逻辑运算和算术运算.由此可见上面的问题在C#里面几乎是不可解决了.<br />
不过我们不要忘了倒霉的一半不是全部,C#3.0引入了表达式树,使得不同类型的值进行运算成为可能.表达式基类Expression提供了丰富的表达式运算方法来帮我们达到目的.我有点迫不及待的给出几行代码,下面是运用表达式树比较两个泛型参数的大小:</p>
<pre class="brush: csharp; ruler: true">///
/// 判断a是否小于b
/// 注意参数顺序,判断的是前一个参数是否小于后一个参数
///
public static bool LessThan(T num1, T num2) where T:struct
{
    //参数表达式树节点1
    ParameterExpression para1 = Expression.Parameter(typeof(T), "left");
    //参数表达式树节点2
    ParameterExpression para2 = Expression.Parameter(typeof(T), "right");
    //两个参数节点构成关系为比较大小的二叉树节点
    BinaryExpression expsLessThan = Expression.LessThan(para1, para2);
    //定义lambda表达式
    Expression&gt; exps = Expression.Lambda
        &gt;(expsLessThan, new ParameterExpression[] { para1, para2 });
    //转化为匿名函数指针
    Func myFunction = exps.Compile();
    //返回执行结果
    return myFunction(num1, num2);
}</pre>
<p>关于表达式树的更多概念请参见<a href="http://msdn.microsoft.com/zh-cn/library/system.linq.expressions(VS.95).aspx">System.Linq.Expressions 命名空间</a>这里不再重复MSDN的内容<br />
当然上面的是逻辑判断的例子,如果是算术运算呢?我们只要改变对Expression代理的封装就是.</p>
<pre class="brush: csharp; ruler: true">///
/// 将两个泛型参数做加法运算
///
public static T Add(T num1, T num2) where T:struct
{
    //参数表达式树节点1
    ParameterExpression para1 = Expression.Parameter(typeof(T), "left");
    //参数表达式树节点2
    ParameterExpression para2 = Expression.Parameter(typeof(T), "right");
    //两个参数节点构成关系为求和的二叉树节点
    BinaryExpression expsAdd = Expression.LessThan(para1, para2);
    //定义lambda表达式
    Expression&gt; exps = Expression.Lambda
        &gt;(expsLessThan, new ParameterExpression[] { para1, para2 });
    //转化为匿名函数指针
    Func myFunction = exps.Compile();
    //返回执行结果
    return myFunction(num1, num2);
}</pre>
<p>上面的都是二元运算,如果是一元运算呢?有点点不同就是注意对lambda表达式的中的代理参数封装,还有就是二叉树节点为UnaryExpression(包含一元运算的表达式),而不是BinaryExpression(包含二元运算的表达式)<br />
下面是一个求负的方法</p>
<pre class="brush: csharp; ruler: true">///
/// 求给定泛型参数的负数
///
public static T Negate(T num) where T:struct
{
    //创建一个参数表达式树节点
    ParameterExpression para1 = Expression.Parameter(typeof(T), "left");
    //构成一个求负的一元表达式
    UnaryExpression expsNegate = Expression.Negate(p1);
    //定义lambda表达式
    Expression&gt; exps = Expression.Lambda
        &gt;(expsLessThan, new ParameterExpression[] { para1});
    //转化为匿名函数指针
    Func myFunction = exps.Compile();
    //返回执行结果
    return myFunction(num);
}</pre>
<p>有了上面三个例子,基本上所有的逻辑运算和算术运算都不是问题了,不过我们如果在定义的泛型类中一个个定义这些方法肯定很别扭,不仅破坏泛型类本身的聚合性,而且重复写也麻烦,所以我们可以将这些运算方法封装为另外一个泛型类,比如取个名字就叫 CalculateGeneric,实际上我就是这么叫的.</p>
<pre class="brush: csharp; ruler: true">///
/// 泛型数值类型计算类
///
public static class CalculateGeneric where T:struct
{
    /// 返回此数值泛型的0值
    public static T Zero;

    /// 实现两个泛型变量的相加算术运算
    public static T Add(T num1, T num2);

    /// 判断两个泛型变量值是否相等
    public static bool Equal(T num1, T num2);

    /// 取倒数
    public static T Reciprocal(T num);

    ///更多丰富的计算类型....
}</pre>
<p>你可能会注意到上面的类中有一个访问器是返回0值,另外你还可能注意到取倒数的方法.所以我还要补充一个问题就是怎样解决泛型参数常量1和0的表示,比如我要通过泛型方法得到不同类型数值的倒数,我就要得到数值1.Expression类也没有提供取倒数的表达式运算方法.<br />
我还没有很好的办法来解决这个问题,不过我临时是这样来解决的:</p>
<ul>
<li>通过<a href="http://msdn.microsoft.com/zh-cn/library/xwth0h0d.aspx">泛型代码中的默认关键字default </a>来变相获取0值,这有泛型参数如果为值类型,则默认值为0</li>
<li>将一个不为0值的泛型参数和自身做除法运算则得到数值1</li>
</ul>
<p>我不能保证上面的解决方法适合所有情况,欢迎大家提出错误或者分享你的解决方案.<br />
另外说明,不能乱用这种方法来对泛型操作,毕竟这样修改了泛型的本意.<span style="color: #808080;">(2010-4-4 15:57:01更新)</span></p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/c-sharp-coding/genericparametersoperation.html">使用C#Lambda进行泛型参数的数值运算</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/c-sharp-coding/genericparametersoperation.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Hello world！</title>
		<link>http://catouse.com/%e6%9c%aa%e5%88%86%e7%b1%bb/hello-world.html</link>
		<comments>http://catouse.com/%e6%9c%aa%e5%88%86%e7%b1%bb/hello-world.html#comments</comments>
		<pubDate>Tue, 09 Mar 2010 15:45:46 +0000</pubDate>
		<dc:creator>Catouse</dc:creator>
				<category><![CDATA[Nothing]]></category>
		<category><![CDATA[about]]></category>

		<guid isPermaLink="false">http://catouse.com/?p=1</guid>
		<description><![CDATA[Hi,I am Catouse. This is my new Webblog,I would like share something about Game &#38; Graphics Programing, AI &#38; Algorithm Exercises,Perhaps  simple, but I am trying.I named it “Unlock Particle”,I think you’ll like this name. 本文:Hello world！ 发表自: Unlock Particle 提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/%e6%9c%aa%e5%88%86%e7%b1%bb/hello-world.html">Hello world！</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></description>
			<content:encoded><![CDATA[<p>Hi,I am Catouse. This is my new Webblog,I would like share something about <strong>Game &amp; Graphics Programing, AI &amp; Algorithm Exercises,</strong>Perhaps  simple, but I am trying.I named it “Unlock Particle”,I think you’ll like this name.</p>
<p><div style=" border-bottom:#CC3 1px solid; background:#CF9; padding:0px 5px 8px 15px">
本文:<a href="http://catouse.com/%e6%9c%aa%e5%88%86%e7%b1%bb/hello-world.html">Hello world！</a> 发表自: <a href="http://catouse.com">Unlock Particle</a>
<br/>提示:如果你在阅读器中不能正常识别文中的代码和图片,可以移步上面的链接查看原文.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://catouse.com/%e6%9c%aa%e5%88%86%e7%b1%bb/hello-world.html/feed</wfw:commentRss>
		<slash:comments>102</slash:comments>
		</item>
	</channel>
</rss>

