Windows Phone上打谱软件的坑挖好了,正在犹豫是否要跳填。
SGF解析部分来自于Super Go。昨天改掉了一些问题,但更大问题是Super Go实际上是对战类型,这个SGF解析只有最简单的功能。而作为打谱软件,要具备以下功能才行:
1.标记,例如下面这些(图片来自于http://senseis.xmp.net/?HowDiagramsWork):
2.分支。在棋局、死活题、变化等讲解时非常有用。
3.交互。做题时候可以根据落子不同进行解说。就像EidoGo那样。
4.棋谱库。维护棋谱,并可以做出修改。
简而言之就是尽量多支持sgf的Tag。另外本来想直接沿用Super Go的各种数据结构,但一来为了支持上面这些功能,二来如果都用了人家的自己就写点UI算什么?所以重写ing。现在大概就是这样:
如果决定填坑的话,保守估计一个月的业余时间要搭进去。
p.s:著名的XGoo(在移动平台的知名度不亚于Stonebase之于PC)最近出了iOS版本!这是个值得让人去买个pad的软件,不夸张。
11 4月 2012 in 程序
Comments [7]
最近做的是有关背景音乐播放(调用系统播放器)的活儿,其中牵扯到Microsoft.Phone.BackgroundAudio.BackgroundAudioPlayer播放本地或远程音频时候的播放列表改动问题。如果希望播放系统Music + Videos中存储的音乐,那么直接在UI利用Microsoft.Xna.Framework.Media传递和播放音乐即可。但如果是BackgroundAudioPlayer和AudioPlayerAgent就不太好办。
可能有人会说这种问题还用得着单写一篇文章吗,AudioPlayerAgent当然支持动态列表了。但很可惜MSDN的官方How-To的例子就是硬编码的列表(还是本地音频),不然也不会在App Hub Forum上出现这样的问题(1、2)。
一般来说将播放列表传递给Agent有这几种方式:
- IsolatedStorageSettings
- 静态方法或属性(作为BackgroundAgent,实例化它没有意义)
- IsolatedStorageFile
实验之后就会发现,前两种方法并不好用:虽然在UI线程中设置了列表或者通过静态方法、属性传递了列表,但启动后的Agent拿不到这些数据。就算是单写一个存储播放列表数据的静态类也是一样。那么留给我们的方法只有通过文件传递。
在上面提到的那个帖子中,一位微软员工Mark Chamberlain给出的方案也是如此(全文请看原帖):
This is how I did it:
In background audio agent code:
OnUserAction.Play/SkipNext/SkipPrevious: Check if BackgroundAudioPlayer.Instance.Track == null, if yes then load playlist from IsoStorage into m_playlist and start playing first track, if no then play current/next/previous song from m_playlist
In the album viewmodel code (each time a user selects an album a new viewmodel gets created for this app):
OnInitialization:…
Another developer who reviewed this suggested that instead of calling ..Instance.Close(), which also releases all the background audio resources, a better approach is to set BackgroundAudioPlayer.Instance.Track = null, which stops and clears, but keeps the background resources allocated.
基本思路即UI存好文件,Agent初始化时候载入。任何和播放相关操作前播放列表如果为null则再次载入。
具体到我手头的例子,文件格式我直接用的Xml序列化,写起来简单。由于需要和UI保持实时,那么每修改一次播放列表(添加、删除、改动)都要保存,同时在Agent一边,任何和播放相关操作前则不仅检查是否列表为null,而是直接全部重新载入。类似于:
protected override void OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param) {
var allTracks = TrackManager.GetAllTracks();
_playList = new List();
foreach ( TrackItem trackItem in allTracks ) {
_playList.Add(
new AudioTrack( null, trackItem.Title, trackItem.Album, null, null, trackItem.Url, EnabledPlayerControls.Pause ) );
}
//...
}
代码写出来非常愚蠢,但目前为止找不到更好的方法。
一直以来,有关dynamic_cast<>这个转换所读到的书和材料消化后,都觉得结论是“拥有带有继承关系的对象指针转换,安全,会抛异常”。但事实上真的如此吗?看下面的代码:
class B1{virtual void foo(){}};
class B2{};
class D{};
D* pD=dynamic_cast(new B1()); // (1)
cout<<*(int*)(&pD)<(new B2()); // (2)
cout<<*(int*)(&pD2)<
可以看到B1、B2和D三个类没什么继承关系,但(1)处通过编译,(2)处提示:
cannot dynamic_cast `(((main()::B2*)operator new(1u)), (((*) main()::B2()), ))' (of type `class main()::B2*') to type `class main()::D*' (source type is not polymorphic)
即来源类型非多态。所以实际上并非是“有继承关系的对象指针”可用dynamic_cast<>转换,而是有vtable的类都可以转——只不过没继承关系的话转出来为NULL。
那么再想一下,既然提示了“多态”,也就是说关键点不在“继承”这里,所以形如下面的代码:
class X {};
class Y : X {};
Y* y = dynamic_cast(new X()); // failed!
虽然两个类有继承关系,但必然通不过编译,因为基类子类并未表现出多态,编译器不会多费劲来生成vtable。在文章多继承的虚指针中提到了dynamic_cast的内部实现:
void *FindCompleteObject (void *ptr )
{
const _s_RTTICompleteObjectLocator *pCompleteLocator =GetCompleteObjectLocator (ptr );
ptr =ptr -pCompleteLocator ->offset ;
if (pCompleteLocator ->cdOffset ) ptr -=*(ptr -pCompleteLocator ->cdOffset );
return ptr ;
}
void *__RTCastToVoid (void *ptr )
{
if (!ptr ) return NULL ;
return FindCompleteObject (ptr );
}
可以看到只有vtable存在,寻找Complete Object Locator的行为才有意义——虚表的第一项就是RTTI Complete Object Locator(RTTI Info),其中包含RTTI类型描述(Type Descriptor)、RTTI继承关系(Class Hierarchy)[2]。故言C++的RTTI特性也是以vtable的存在为基础,没有虚函数或其他virtual特性,RTTI不生效。
当然一般使用中其实理解成dynamic_cast<>用于向下转换带有继承关系的指针也没错,上面提到的这两个特例应该很少会出现在实际代码中吧。但此处犯错足见俺基础太差,离C++对象模型的深入理解还差得远。
p.s:真想把之前这类因为基础差犯2B错误的文章集结起来。最近几个月就写了不少。
参考资料
- 多继承的虚指针,lw02nju
- 浅议 Dynamic_cast 和 RTTI,RocZhang
26 3月 2012 in 程序
Comments [3]
目录
- 构造和拷贝构造
- 动态特性和RTTI
- 内存管理和标准C区别
- 监视方式
- 数据持久化
- RTTI和动态特性2
- 容器类、Block和NSPredicate
04监视方式
Protocol
用protocol实现的delegate。其实我觉得这个就是观察者,只不过默认情况下是单一的观察者。具体方法不总结了。
有什么方法可以一次性存放多个delegate?这样就可以用数组方法一口气通知完:
[array makeObjectsPerformSelector:@selector(doSomething:) withObject:aObject];
如果写N个变量第一比较罗嗦第二也不知道运行时会有多少个观察者。但问题在于NSArray和NSMutableArray不能存指针之外的对象,protocol实例不认。
KVO
KVO,也就是Key-Value Observer,是除了protocol和notification之外的又一种属性监视方式
监视别人的类重载一个方法,用于观察值变化
- (void) observeValueForKeyPath:(NSString*)aPath ofObject:(id)anObject change:(NSDictionary*)aChange context:(void*)aContext {
NSLog( @"%@ has observered key %@ change in %@, from %@ to %@",
[self class], aPath, anObject, [aChange objectForKey:@"old"], [aChange objectForKey:@"new"] );
}
被监视的类不用特意修改。
发送消息时,需要用NSObject里面某Category已经定义好的add/removeObserver增删observer即可
Coder* me = [Coder personWithName:@"Si Wei" andAge:25];
[me setLanguage:@"C#"];
Computer* computer = [[Computer alloc] init];
[computer addObserver:me forKeyPath:@"workload" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionNew context:nil];
[computer setWorkload:10];
[computer setWorkload:50];
[computer removeObserver:me forKeyPath:@"workload"];
[computer release]; Read more >>>
10 2月 2012 in 程序
Comments [4]
这几天在刷PSV奖杯,结果看到这么个东西:微软的Visual Studio Achievements扩展。
作用就是在程序员完成一些“成就”后给予提示和记录,获取相应的称号。例如:
- 在一个类里面声明100个成员变量(Field Master)
- 一行代码写300个字符(Scroll Bar Wizard)
- 使用“Close All But This”10次(Obsessive Compulsive Disorder)
- ……
看来以后可以加班刷成就啦!
19 1月 2012 in 程序
Comments [2]