一个PASCAL程序

Like
Like Love Haha Wow Sad Angry
5

自己编的

program sequence(input,output);
{$r-,s-,q-}
var
       a:array[1..10] of 0..1;
       input,output:text;
       x,y,n,w:longint;
       i:longint;
       s:longint;
function xny(a,b,c:longint):longint;
       var
           tv:integer;
       begin
           c:=1;
           for tv:=1 to b do
               c:=c*a;
       xny:=c;
       end;
begin
       for i:=1 to 10 do
           a[i]:=0;
       s:=0;
       assign(input,'sequence.in');
       reset(input);
       readln(input,n,w);
       close(input);
       i:=10;
       while w>0 do
           begin
               a[i]:=w mod 2;
               w:=w div 2;
               i:=i-1;
           end;
               for i:=1 to 10 do writeln(a[i]);
       for i:=10 downto 1 do
               begin
                   if a[i]=1 then s:=s+xny(n,10-i,y);
               end;
        assign(output,'sequence.out');
        rewrite(output);
        writeln(output,s);
        close(output);
end.

哪位大虾优化一下input: [‘input] n. 输入

2006-12-20
Like
Like Love Haha Wow Sad Angry
5

你的计算机启蒙是谁?

Like
Like Love Haha Wow Sad Angry
71

后续:两年后,我写了《记孙正威老师 | 黃河青山


感觉好像没什么值得说道的,对大家来讲。我个人觉得比较有意义的倒是有一件。在五年级的时候,有一个信息老师选拔数学比较好的人去学计算机竞赛,一共选了六个人。那个年代,不要说计算机竞赛了,就是计算机(对我来说)也是很遥远的东西。我还没有自己的电脑呢,只是偶尔会对着电脑店的广告单垂涎。

这个老师在小学很有名,叫孙正威,我经常在机房的电脑上看到以他为名的文件夹,或者是他创建的文件等。但是之前并没有上过他的计算机课,只是听说他很严厉。

Continue reading “你的计算机启蒙是谁?”

Like
Like Love Haha Wow Sad Angry
71

快乐

Like
Like Love Haha Wow Sad Angry

某天,一个小孩出生了。

他出生在一个知识分子家庭。

从他记事开始,他就在接受教育。

人们教他认字,教他读书。小孩觉得很没意思,他对外面充满了向往,因为他从未出去过。当接触到“快乐”这个词的时候,他无法理解那是什么东西。

上小学了,小朋友们都在一起玩,他却不。别人邀请他一起玩,他却不敢答应。

渐渐地他开始适应学校生活,然而就在这时,他才接触到了真正的教育。1、2年级时的考试十分简单,家长、老师也并不在意。可是之后,考试的分量陡增。他重又回到了如“童年”般的日子。他渐渐在考试中取得领先,同学们都很羡慕他,而他却不快乐。他期望像别的孩子一样尽情玩耍。

他考上了重点中学,结交了很多朋好友。中学的教育是更加残忍的。尽管孩子们不在意考试的分数,社会的主流人群却还是在意的。但就在这样的压迫下,孩子还是学会了玩。中学时光是叛逆的日子。在那时逃课打篮球、夜不归宿去KTV对他来说是多么快乐啊!但好景不长,家长很快注意到了这一点,并开始控制他的活动。无奈,孩子最终还是选择了屈服。

他的天资很高,高中又考上了重点学校。父母很快乐,可他依然不。一次作文课,作文题目是”快乐“,他根本无从下手。老师对这样优秀的学生写不出文章很诧异,问他,他不敢说为什么,敷衍了几句。高中的时光本应是自由、快乐的,而他却从未曾体会到。在父母的思想教育下,他似乎开始认识考试的重要性,并为之付出了不少的努力。

不出所料,他考上了重点大学。他想,我终于可以体会快乐了吧,于是他与同学一起出去游乐。可不知为什么,他怎么也体会不到初中时的感觉。而且,他的成绩也大不如从前,几乎被退学。这时他似乎又开始觉悟,改变自己的态度,度过了4年充实的大学时光。

毕业后,他被分配到某机关工作。他想起了学生时代学过的,他决定做一个清官,并认为那样一定会快乐。可是现实和理想总是有差距的,他非但没有快乐,还几乎丢掉工作。看着其他人快乐的样子,他开始顺应潮流。但这也没有使他快乐,反而使他觉得生活是压抑的。

他有了儿子,他依照父母的方法教育孩子。孩子成绩很好,但看着孩子阴沉的面孔,他也快乐不起来。

度过了几十年时光,他退休了。他竭尽全力寻找快乐,可是却始终没有能找到,至死也没有找到。他很疑惑,本曾拥有的东西,为何现在却如此隐秘。

临死时,他问道:“快乐到底在哪儿呢?!”

其实快乐本就在他身边,他也曾接触过。他却自发地逃避快乐,直到快乐已不复存在。

2008-10-26

Like
Like Love Haha Wow Sad Angry

用 Angular 弄了一个背单词的网站——eliseos.org

Like
Like Love Haha Wow Sad Angry
14211

弄了一个背单词的网站——eliseos.org,或者叫 jingtu.io。(这俩名字其实是一个意思。当然这个网站不主要是为了背单词而开发的,不过目前只有背单词的还能用。)


它是 Angular 开发的,同时用了一些时新的技术,比如前端的 redux-observable, graphql, apollo client,后端的 inversify, sequelize-typescript,另外我还自己搞了一些用于自动生成 graphql schema 的 decorator——

@Table
export class Language extends NoPrimaryOrdinaryModel<Language> {

  @Default(DataType.UUIDV1)
  @Column
  @GraphQLFieldToType
  id: string;

  @PrimaryKey
  @Column
  @GraphQLFieldToType
  name: string;

  @GraphQLFieldJsonLike(() => Kv)
  @Column(DataType.JSONB)
  namesInLang: KvInterface;

  @HasMany(() => LanguageOfLanguage, 'languageName')
  languageOfLanguages: LanguageOfLanguage[];
}

 

是不是有点像 Java 了?这么写就会生成一个叫 Language 的表,有这么些 column 和 association,这部分是 sequelize-typescript 的功能,还会生成一个叫 Language 的 graphql schema,这部分是我自己写的。难也不难,主要是提供一种思路。

另外写的过程中我也理解了为什么 sequelize-typescript 的 decorator 参数里,类型是 lazy 的(即以上代码里的 () => LanguageOfLanguage。这是因为如果不 lazy,出现类的循环引用的时候,有一方会变成 undefined。我碰到了这个问题,所以我自己也用了 thunk 形式作为参数。

然后对于 query 也有这么些个 decorator,比如——

@GraphQLQueryField(userGraphqlType, {
  token: {
    type: new GraphQLNonNull(GraphQLString)
  }
}, 'Checks if a token is valid. Returns the validated user.')
async checkToken(parentValue: any, {token}: {
  token: string
}, context: ContextInterface) {
  return await context.services.userService.checkToken(token);
}

 

其实也没什么学问,主要是我看着原来 graphql-js 的 object literal 结构太不稳当了,嵌套一深,随便哪里类型写错了,TypeScript 就抛一大堆错(其实挺稳当的,只要你把 object literal 拆分开来,每一级都标注类型,报错就不会大规模传播)。

用上了 decorator,顺带用了 inversify——一个依赖注入管理器,以及 TypeScript 的一套东西,谁说 Node.js 不可以工程化开发呢?

至于前端,也是从 TypeScript 中获益良多。Angular 原生就是依赖 TS 的,也是原生就依赖 decorator 的,也是原生就依赖注入的。这么看 JS 生态系统前后端的技术选型已经趋同了,我相信这是好的趋势。

还有什么要说的话,就是我把以前答过的Axurez:如何评价 TypeScript 最新加入的 Discriminated union type?这个定义 tagged union 的简便语法,真的给用到了实战里——不仅仅是定义 redux actions,而且我写了一个可以深度 get 和 set 的 Map,因为要用递归指涉自身,还必须用到 tagged union。这个类型如下:

export type RecMap<K, V> = Map<K, { type: 'V', value: V } | { type: 'M', map: RecMap<K, V> }>;

 

整个弄下来的感想就是,Angular 是真的好用,Angular 生态是真的不错,universal 完全按官方走一遍就活了,现在线上运行的版本就是 universal 的,右键查看源码可以看到是渲染好的页面发过来的。angular cli 一路可以 generate 到底,基于 NgModule 的路由懒加载也是开箱即用,不需要任何配置,非常美妙。

还有一点就是,还是纯 css 库比较稳妥,带 JS 的反而不行,我用了 material design components 和 material design lite(因为前者没实现 chip……),还是把 js 拆了用的。一方面是它带的 JS 不一定合你的意,另一方面是它哪怕是用了你用的框架,它的 API 设计也不一定合你意(这也是我不用 Angular Material 的原因)。另外用了 Angular 这样的框架,它封装的那点功能你自己封装也要不了多久。

如果说还有一点感想,那就是我好像有点达成以前的目标了。以前总是感觉 sequelize 要写一套定义,要写一套接口,graphql 还要写一套定义,来来回回同样的东西要写好多遍。现在借助 decorator 真的实现了只写一遍。现在还有 sequelize-auto-migrations 这样的东西,可以自动根据模型的更改生成 migration,简直不要太省劳动力。


说了这么多关于开发的功能,那么这个网站怎么用呢?(推荐桌面使用,虽然移动端也完全可用)

关于背单词功能,如下图,点击右侧的「巴别」(巴别,用 wikipedia 的人应该见过,典出巴别塔,我用来指代和语言相关的模块)中的「学习」,就来到了学习界面(同时在线统计是用 socket.io 实现的,不过用户数量目前并不对,页面是对的。这里有个彩蛋,没网的时候 logo 就会黑掉):

你可以在右侧的「语料」里粘贴进英文文章,然后点击「使用这篇文章」:

它会把文章跟服务器同步,解析出你认识的、不认识的、没决定过的词汇,分别标上白色、红色和绿色:

正如提示所说的

在左边粘贴文章,并点击按钮,来提取文章中的单词。
绿色表示状态未知的单词,划过标记为认识,单击标记为不认识,再单击标记为认识,以此类推。
你可以在概览中回顾不认识的单词。

照着做就行了。我还弄了一个功能就是添加和查看单词释义。把鼠标悬停在不认识的(即红的)单词上,会出现悬浮框:

点击加号就会出现文本框,可以添加释义,以及选择释义的语言(这个网站处于我个人的恶趣味,是支持了四种语言的,用右上角的语言选单可以极速切换语言)。添加完之后,或者本来就已经有人添加过,就会是这个样子:

本来应当是可以代理一个其他网站的 API,或者干脆服务器上搞一个词库的,实际上应该是可行的,但我还是想先试试 UGC 一段时间(估计效果不好)。添加释义的另一个好处就是可以在个人主页上显示……比如我的主页

个人主页怎么进?登陆之后右上角的用户名可以直接点击:

或者鼠标悬停,在下拉菜单里选「个人档」也行。

如果你误操作了,一方面你可以再次点击单词,在白色和红色之间切换,另一方面也可以在右下角看到所有红色、白色词汇的列表,点击就可以复归「未确认」状态,即绿色。

确认单词为未知之后,不仅单词会被同步到服务器,单词所在的句子也会被同步到服务器,在右侧的「巴别—概览」中可以回看:

未知单词在句子中的未知也会标红。(这里本来是给单词加上 html 标签,然后渲染 html 的,但是会有注入的危险,所以最后强行把句子 split 成一个结构体,用 ngFor + ngIf 渲染了)

以上大概就是目前能用的内容。设置的个人档也可以更新

还可以生成邀请链接,推广注册。

如果遇到什么 bug,请一定联系我。

至于为什么要做这个网站?这个网站除了背单词之外,还是干什么的?就如关于页面所说:


Eliseos 就是「极乐净土」的西班牙语形式。我用西班牙语是因为其他语种类似的域名都注册了(elysium, elysian, elysion 之类的)。其实我原来有个 elysion.tech,但是 .tech 太冷门了,很多地方识别不出来。这网站还有个域名,叫「净土」—— jingtu.io

根据维基百科:

至福乐土(Elysium)或是乐土平原(Elysian Fields)(古希腊语:Ἠλύσιον πεδίον,Ēlýsion pedíon,音译:伊利西恩、伊利西昂。中文翻译上亦可名为归静乐土或是归净乐土,意为回归安静或回归纯净的乐土。)是一个来世观的理念,随著时间的推移并由一些希腊的宗教教派的仪式与哲学流派所延续发展。

我最早是在《圣斗士星矢》里接触到这概念的。在这里,我想用它指代这个网站,是因为我想做一个能进行深刻思想交流(包括语言、知识)的地方。

Like
Like Love Haha Wow Sad Angry
14211

Linux 下使用 Nvidia 显卡和 Virtualbox 遇到的一些坑

Like
Like Love Haha Wow Sad Angry
31

nouveau 显卡驱动,并不好。

Virtualbox 的问题

Virtualbox 安装完毕 Windows 10,却莫名其妙卡在了登陆之后应该出现桌面的地方。而且它不仅仅是客户机卡死,宿主机也一并卡死了。

我没太注意这个问题。大不了暂时不用 QQ 好了。

Nvidia 显卡

无独有偶,另一个问题的出现使整个事情出现了转机。

使用 Linux 后不久,就发现了问题。桌面环境(xfce4)经常无故完全卡死,甚至连 Ctrl+Alt+Fn 切换 tty 都没有用。偶尔出现还能忍,但是在短短的两三天就数次出现,呈现一定规律。我决定一探究竟。还好直接看日志就能发现问题——journalctl -xe里面出现了红红的nouveau sched_error ctxsw_timeout,几乎能让人确信是 nouveau显卡驱动的问题。

查了一下,貌似是一个普遍的问题:Bug 93629 – [NVE6] complete system freeze, PGRAPH engine fault on channel 2, SCHED_ERROR [ CTXSW_TIMEOUT ],而且看不到被解决的趋势。

对症下药,我赶紧卸载 nouveau,切换了 Nvidia 的官方驱动,至今运行良好:

sudo pacman -S nvidia

Virtualbox 和 Nvidia 显卡

这时我突然想起,会不会 Virtualbox 的问题,也是 nouveau显卡驱动的问题呢?我激动地打开了 Virtualbox,登陆,一切如期。看来真的是缘起这个显卡驱动。

我还没激动多久,又出现了一个问题。用 Windows 的目的之一,是测试 Angular 对 IE11/Edge 的 polyfill 管不管用。所以我打开 Edge,加载最近在写的 www.zjuqsc.com/m,却发现整个图形界面都在不停闪烁。起初我以为是 UWP 的 bug,然而换了 IE 之后依然如此,安装了 QQ 之后依然如此。我又一次失望起来——这事情就搞不好了吗?

还好,搜索 “virtualbox windows10 flickering” 直接给出了答案:SCREEN FLICKERING IN VIRTUALBOX WITH 3D ENABLED [UPDATED SEP 21, 2017]

看起来,是 Nvidia 显卡的 3D 加速驱动的问题。根据文中内容,虽然只要改动一行代码,但是由于会「破坏一位付费用户用的某些功能」,所以官方不会修改,只能用户自己动手。

好在作者和一位评论者,分别提供了 5.1.85.1.30 编译好的、要打补丁的那个文件VBoxOGLrenderspu.so,只要用它替换/usr/lib/virtualbox/里的同名文件就行了。后者经过我测试,是可以在 ArchLinux 下的 Virtualbox 5.2.* 下正常工作的。

后记

Linux 下的桌面环境,还存在种种问题。还好这些问题现在基本是可以修复的。尤其是相比 Windows 下不可忍受的效率问题,还是早日切换到 Linux 的好。

Like
Like Love Haha Wow Sad Angry
31

什么是 Haskell 中的 GADT(广义代数数据类型)?

Like
Like Love Haha Wow Sad Angry
3612

先看看没有 GADT 的时候我们在做啥。最简单的,比如定义一个列表:

List a = Nil | Cons a (List a)

它是在做啥呢?

  • 先看等号左边,它首先定义了一个叫 List 的 type constructor,它接受一个类型,并返回一个新的类型。其实就是类型的函数。
  • 再看右边,它告诉我们有两种方式获得一个类型为 List a 的值,一个叫 Nil,一个叫 Cons a (List a)。
    • Nil 的话,你直接写 Nil,它就是一个 List a 类型的值,至于这个 a 具体是啥,需要结合上下文推导才知道。
    • 而 Cons a (List a) 呢,它是接受两个参数,一个类型是 a,一个类型是 List a,然后返回一个 List a 类型的值。至于这个 a 是啥,我们同样是需要推导才能知道的,不过是这里的推导比较显著罢了,因为直接就是第一个参数的类型。

那么我们可以用函数形式给这俩表示出来: Continue reading “什么是 Haskell 中的 GADT(广义代数数据类型)?”

Like
Like Love Haha Wow Sad Angry
3612

例说 C 语言类型声明

Like
Like Love Haha Wow Sad Angry
621
C 语言的类型声明,由于某些历史局限性,在某些情况下显得相当复杂。下面让我们来渐渐深入 C 语言类型声明的谜团,一探究竟。

 

指针和数组

一重声明

以下这些问题,我相信即使是最基本的初学者也不会有太大困难:

你会声明数组吗?

int a[5]; // 包含 5 个元素。

你会声明指针吗?

int *a;

二重声明

你会声明双重指针吗?

Continue reading “例说 C 语言类型声明”

Like
Like Love Haha Wow Sad Angry
621

【C++ 模板元编程入门】在编译期实现 Peano 数

Like
Like Love Haha Wow Sad Angry
2

基本知识

类型的函数

我们都知道模板可以接受类型作为「参数」。同样地我们也可以有「返回值」,从而构造类型的函数。基本的范式是:

template<class T>
struct Computed {
  using type = T;
}

这就构造了一个名为 Computed 的,接收一个类型参数,返回这个类型本身的函数,用法如 Computed<float>::type,这个类型应当还是 `float`。
为什么要包一层 struct?这是因为 C++ 不支持对 using 的特化。这样的代码是不行的:

template <class T>
using computed<T> = T;

template<>
using computed<int> = double;

至于为什么不支持,我没有了解。

特化

什么是特化?你可以理解为模式匹配,就像 Haskell 中的写法一样。

template<class T>
struct Computed {
  using type = T;
}

template<>
struct Computed<int> {
  using type = double;
}

这样当你调用 Computed<bool>::type 时,得到的结果是 bool,而调用Computed<int>::type得到的结果却是double。当然这种匹配是遵循一定规则的,比如更「具体」的特化优先匹配,这跟 Haskell 谁在前谁先试着匹配不太一样。在 Haskell 中就好比:

data Type = Bool | Double | Int

computed :: Type -> Type
computed Int = Double
computed t = t

实际上有了这层对应,如果你知道怎么在 Haskell 中实现 Peano 数,那么 C++ 中的实现基本就是无脑翻译了。如果你不知道怎么在 Haskell 中实现 Peano 数,那你知道 Peano 数是什么,也能大差不差知道答案了。

Peano 数

Peano 数是什么?Peano 数是归纳定义的自然数,准确地说应该是一个表现形如直觉中「自然数」的公理系统,也就是「自然数」的形式化。这个系统里只有两个符号,Zero——表示 0,以及 Succ——表示后继。那么 1 就是 Succ<Zero>2 就是 Succ<Succ<Zero>>,以此类推(归纳,其实就是「以此类推」的形式化)。
我们可以在 C++ 中如此表述:

struct Peano {};
struct Zero: Peano {};
template<class T>
struct Succ: Peano {};

那么加法又是什么呢?从例子出发,我们需要定义一个两个类型参数的模板:

template<class T1, class T2>
struct Add {
  using type = ???;
}

满足直觉中的运算规律,比如 2+1=3,翻译成 C++ 就是 Add<Succ<Succ<Zero>>, Succ<Zero>>::type = Succ<Succ<Succ<Zero>>>。当然类型之间没有等于号,准确地说应该用 std::is_same<T1, T2>,这其实也是通过特化实现的,比如(示意,非官方实现):

template<class T, class U>
struct is_same {
  static constexpr bool value = false;
};
 
template<class T>
struct is_same<T, T> {
  static constexpr bool value = true;
};

那么如何定义加法呢?对于有限的元素,我们当然可以为每一个实例做特化,比如:

template<>
struct Add<Succ<Succ<Zero>>, Succ<Zero>> {
  using type = Succ<Succ<Succ<Zero>>>;
}

也就是打表。C++ 编译器的模板深度一般都是有限的,所以这理论上是可以在实际操作中覆盖所有用例的。但是这明显太傻了。其实加法的定义只需要两条规则就可以覆盖:0 + b = b, (Succ a) + b = Succ (a + b)。翻译成 C++ 就是:

template<class T1, class T2>
struct Add;

template<class T>
struct Add<Zero, T> {
  using type = T;
};

template<class T1, class T2>
struct Add<Succ<T1>, T2> {
  using type = Succ<typename Add<T1, T2>::type>
};

注意那个 typename,gcc 并不知道后面那个 ::type 成员是类型还是变量,所以需要 typename关键字的提示。
这就算写完了,你可以测试看看,是不是满足 std::is_same<Add<Succ<Succ<Zero>>, Succ<Zero>>::type, Succ<Succ<Succ<Zero>>>>::value == true(需要 <type_traits> 头文件,或者上面自己写的那个模板(那就不用加 std::)。这么嵌套着写 Succ 太繁琐了,也不方便看,你可以简单地写一个模板来从整数生成类型:

template<int v>
struct peano {
  using type = Succ<typename peano<v - 1>::type>;
};

template<>
struct peano<0> {
  using type = Zero;
};

然后就可以去验证 Add<<peano<2>::type, peano<1>::type>::type 是不是等于 peano<3>::type 了。
至于加减乘除的其他运算,比较啊奇偶性啊其他的函数,只要你懂得了加法,恐怕就不难了。

练习:

Peano numbers | Codewars 完成加减乘除、奇偶性和比较大小的撰写,并通过测试。

广告时间:

Codewars.com 是一个很好的综合性、游戏化 OJ,除了算法(多是入门级的)之外,考察语言特性(较为深入)是其一大亮点,同时有很多 Haskell 方面的内容,包括我们喜闻乐见的读论文然后完形填空。题图是 Codewars 上上述练习的界面截图。

后记

当然我们还可以进一步「证明」我们印象中的结论,比如加法是满足交换律的,加法和乘法是满足分配率的,等等。这就是后话了。

Like
Like Love Haha Wow Sad Angry
2

记孙正威老师

Like
Like Love Haha Wow Sad Angry
622

今天是教师节,我研究了一夜 OCaml,早上六点才睡。醒来已是下午两点。对这个节日,向来没有什么感受,可能是我在学校比较独立,和老师交流较少。师者,所以传道授业解惑,但是老师既没传给我道,也没怎么授过业,我更没有仰仗老师解惑。也从小到大,我都是在孤军奋战。这可能也是我学习不大好的重要因素之一。

但是今天水着工信群,突然想起了些什么。我一个学数学的,为什么会在工信群呢?为什么我会对编程有执念呢?

虽然我进大学的时候,确实是在几乎不会编程的状态,但我之前确实学过编程。它甚至是我开始拥有自己电脑的契机。那是在五年级升六年级的暑假开始前不久(2005 年)。有一个叫孙正威的信息学老师选了 6 个人去学习“信息学竞赛”(没有人知道怎么选的,只知道被选中了)。那时候我连个人电脑都没有,唯一能接触电脑的机会是去姑姑家,而唯一做的事情就是玩 PowerPoint 的剪贴画,然后用彩色打印机打出来。这样的我当然不知道「信息学竞赛」是什么东西。

得知这个消息,是下午快放学的时候(或者在那之前)。并且我们被叫去了他在新教学楼 6 楼的办公室。向来不喜欢和老师有过多牵扯(因为我老是害怕是不是我犯什么事了)的我,被通知的那一刻还有些慌乱,因为觉得很麻烦。我当时还不认识这个老师,不过「孙正威」这个名字倒是见过不少次,因为机房里很多文件上都署着。这倒还在其次,最主要的是,虽然不认识,但是见过几次,印象是这个老师颇为严厉,经常训斥学生 。当然最终还是得去,没有理由逃掉。

那个办公室是内外两间,外间有一台电脑,装的是 98 还是 XP 我不记得了,又或者是 2000。似乎没有什么准备地,课程就这么开始了。先是导论,教学方式颇为朴素。有一本官方教材,老师按照教材的顺序给我们过内容,先开始就是什么是编程、什么是 QBASIC、如何使用 QBASIC 的 IDE 云云。因为有电脑的缘故,倒是可以实时做一些演示。虽说是很朴素,但只有 6 个学生,教学效果很好,而且内容全新,第一次让我在学校有了被教学的感觉。

导论课没多久,之后我们必须接触真正的算法和程序了。我们要到机房去练习。机房也在 6 楼,就在办公室门外走道的尽头。当然在机房里不仅有练习,也有《上古神器》Flash 小游戏和金山打字通(或者是另外的打字练习软件)。经过了不懈的练习,我把按顺序按 A-Z 的速度提高到了 500 个字母每分钟(后来就没涨过了,现在打字也是 500 kpm)。

有的时候我们不在老师办公室上课,而是找空教室。老师就坐在桌子上,十分随意,我们围坐在桌子上,可以自由走动,从一个桌子爬上另一个桌子。虽然经过观察,孙老师为人确实很严厉,但是课堂氛围也着实很随意。或许这就是小班化教学的最大好处吧。我从前没有享受过,后来也没有。

我对待学习一向是一丝不苟的,课内是这样,课外也是这样。当然更多是一种「义务」范围内的一丝不苟,比如作业认真做,考试好好考,但是从来不会去自己不喜欢的科目做额外的事情,比如找练习题来做,或者探究答题的原理。虽然在考语文的时候我总是对如何答题一无所知,但一到有空的时候,我还是不会想起去钻研怎么答题。当时对信息学竞赛,并不算得很有兴趣,但是我想我要做好。为了课后的练习,我软磨硬泡父母给我买了一台电脑,是当时在电视上做广告的「四千八百八十八,笔记本电脑抱回家」的神舟笔记本。

虽然有了电脑就不免玩游戏,但我也花了相当的时间摆弄 QBASIC。我始终记得有一次和我爸去打乒乓球,我打累了就在球馆的吧台上研究编程,好象是在写一个一百多行的程序。

除此之外,我还摆弄过些别的。阴差阳错地,我在书店买了一本关于「ACCESS」的书,然后就照做了起来。对着它的图形化窗体设计器,我最终完成了一个保险单管理系统(我妈是做保险的)。我把这个系统展示给(信息竞赛的)老师和同学看,得到了特别好评,被老师树立为「钻研」的典型。虽然这可能不是我在这个「班」里表现好的唯一地方。

暑假前,暑假中,课是照样地上。平时有其他课,只能放学后抽时间开课。暑假里时间多了些。即使是中考放假都没有阻断我们的课。我们混进学校的时候,还被家长当成是参加中考的小学生呢。此外还有一次到滨海还是哪里,去找另外的老师教。那个老师上来就问高精度除法,结果最后只有我一个人答上来。看起来其他同学对这个事情不怎么上心。

最后要比赛了,它是一个夏令营的形式。在盐城一小南小区办的。有 3 个名额,我在列。整个夏令营下来,我认识到了南京、常州还有大丰在这项事业上的深厚实力。考试很神奇,是在纸上写运行结果的(4 个题,每个题 10 个点),(回想起来很神奇,为什么会这样。难道是 QBASIC 的基础设施太不完善了?可是基于 stdio 的判题,总归是不依赖语言,只依赖可执行文件的吧?)我骗了一些分,最后考了 180/400,二等奖,说是差一点点就一等奖了。另外两个同学考了 10 分和 0 分。

这就是我上大学之前关于编程最好的记忆。第二年临近比赛,我被告知今年我们县不参加了,因为孙正威老师考上了公务员,不当小学老师了。实际上对孙正威老师,至今我都知之甚少。他怎么知道这个比赛的?他又怎么会这个比赛的?他是自学的吗?他也是现学现卖的吗?但他应当是一位很有能力的人,一位知道自己想做什么、也会去做的人。

虽然只有短短的两三个月,但回想起来,我总觉得有很久很久。为什么会印象这么深呢?为什么会感觉这么好呢?是因为老师教得好吗?还是因为只有 6 个学生,体会更深?又或者是因为这真的是全新的内容,不仅不是我预习过的,而且完全超出了我的认知范围?或是兼而有之呢?

在我平淡的中小学生活里,如此这般轰轰烈烈的事情,仅此一次。其后,这段记忆就被封印起来。每天是无聊的普通课程,从初中到高中。每天早上上学的时候,我都会仰望天空。我会不停地问自己:「这样的苦日子什么时候会结束呢?」

到大学以后,通过各种渠道,见识到了各种各样的人,我才知道有老师是多么的好,没有老师是多么的不好。但是老师岂是想有就能有的呢?这也是需要机缘的呀。我曾经是不怎么善于和人交流,也不怎么愿意和人交流。但这到底是因是果呢?

其后我又自学过编程,但是效果不怎么好。尤其是在卡在一本叫多少天入门 Visual Basic .NET 2005 的书上——实际上直到近些年我才成功装上 Visual Studio 2005。IDE 都没装上,实践就更都无从谈起了。我当时也不理解什么 eventArgs,什么回调函数。只是经常无聊地翻着。后来我的兴趣点基本完全主要在数学上。

虽然我可以自称是一个 power user,但着实对编程不怎么在行。大一大二的时候,我发觉自己迫切地需要一个在网页上渲染数学公式的扩展,但市面上的都很死,迫不得已就学着开发了一个 Chrome 插件,支持对任意域名的匹配(概念可能来自于 Stylish),还了解到回调函数、异步等概念。大三的时候,我又凭借这次的经验混进了求是潮技术研发中心。

在那里,我认识了很多可爱的人,比如森森,比如好厉害,比如大爷,比如叶子哥哥。我经常围观他们操作电脑,或者和他们做奇怪的探险。我从他们那里学到了 Chrome 开发者工具的高级使用,学到了 Linux 的高级使用,学到了一些信息安全操作。在我看来,这是才是理想的师生关系。我就像是他们的学徒,他们都是我的老师,他们把我引进了软件开发的大门。

qlbf 也是我的老师,他向我介绍了 Codewars 的,帮我入门了 parser。

现在我比以前不菜一些了,虽然还是很菜。

有时候我会想,我为什么这么菜呢?如果当时有很好的老师,我会不会好一点呢?如果我不是这么晚才遇见了这些可爱的老师,会不会好一点呢?可是,没有如果。好的老师,哪里是想有就有的呢?世间万事,哪里都能如意呢?分明都是机缘巧合。

尽管如此,我还是希望事情能好一些。所以我搞了编程团,搞了很多其他群,我还想搞社区(虽然拖了两年了,但那时确实太菜了)。也许是出于补偿心理或者感同身受,我总是好为人师,热衷于传播我知道的各种东西。因为我觉得这样是有帮助的,是对的。我不想别人也有我这种痛苦、失落而遗憾的经历。

而这一切的一切的起点,我对编程的执念、我对建群的执念,这些执念的缘起,就是 2005 年暑假前后,我们被孙正威老师讲授小学信息学竞赛的经历。

这就是我今天想说的。

Like
Like Love Haha Wow Sad Angry
622

关于游戏王全卡档的几点注解

Like
Like Love Haha Wow Sad Angry

正文:

问:为什么我下了游戏王全卡档文件,也拷到了存档目录,却无法在游戏里解锁全卡档?

答:原因可能是多样的,但本质上都是由于游戏读取到的校验码和存档文件不匹配导致的。

问:那么会有哪些原因呢?怎么知道我是哪个原因呢?

答:首先,我们要了解这个校验码是放在哪里的。答案是——注册表。这也是网上很多教程会让你导入注册表文件的原因,也是它们说“要备份存档文件,必须要备份 flcrc”的原因。准确地讲,这个校验码是放在注册表某个节点下的 \KONAMI\Yu-Gi-Oh! Power Of Chaos\system 节点下的 flcrc 键值,是一个 13 字节的二进制。在我的电脑上,它长这样:

游戏王的注册表
游戏王的注册表

在同样的节点下,CommonDir 这个字符串键值则记录着存档文件的位置。我相信,如果之前你没有手动创建/导入这个键,它应该会在游戏开始时被设定为“当前工作目录”的父目录(这是因为游戏王不仅有城之内篇,还有游戏篇和海马篇,默认状态下,它们会被分别安装在 %PROGRAMFILES%\KONAMI 目录下的三个子目录中,但是它们的存档是可以共享的——这也正是这个目录名为 Common 的原因)。

在很多情况下,这不会有问题

你是什么版本的操作系统?是 Win XP, Win 7 还是 Win 10 呢?是 32 位还是 64 位呢?

问:那我应该怎么做呢?怎么才比较稳妥?

答:比较稳妥的做法是,不要导入网上的注册表文件,直接先打开一次游戏再退出。这时候它会自动创建存档文件,以及注册表中的键值。你只要在注册表中搜索 flcrc 这个键,就会知道正确的地方在哪了。

问:我下到的存档文件,它的 flcrc 不符合你说的这些,怎么办呢?

答:最好的方法是去下一个符合这个 flcrc 的文件。你可以直接在这里下载。

问:那这个 flcrc 到底是怎么生成的?它的内容是什么意思?

答:我目前只发现了这些。等到我有时间、有机会的时候,也许能了解它的真相。

后记:

昨晚把游戏王城之内篇又翻出来玩。

当初还是数学竞赛培训时,季泽推荐给我的。

前一阵子也有一次动了玩游戏王的念头,配置好之后却发现不能解锁全卡。当时没有深究,打了几局就不想打了。

这回再次安装,我心里有了阴影。安装好之后,一看,果然按照它里面的说明配置全卡档,并不能解锁全卡。这下我就慌了。毕竟我只想打几局,可不想浪费时间在配置文件上面。

 

定下心来,我开始研究到底怎么回事。它的操作,无非是两件事,一件事是复制存档文件到指定位置,名为 system.dat。另一件事则是导入一个注册表文件。

 

汇总了一些资料,都大同小异。

 

第一个难点是。

 

关键的问题是,在我的系统中(其实是 64 位系统中),这个键的位置变了,原来是在\HKEY_CLASSES_ROOT\VirtualStore\MACHINE\SOFTWARE\WOW6432Node\KONAMI\Yu-Gi-Oh! Power Of Chaos\system,现在是在\HKEY_CLASSES_ROOT\VirtualStore\MACHINE\SOFTWARE\WOW6432Node\KONAMI\Yu-Gi-Oh! Power Of Chaos\system

 

 

Like
Like Love Haha Wow Sad Angry

一个不正确的 TypeScript 类型定义引发的血案

Like
Like Love Haha Wow Sad Angry
2

Mongoose 的 TypeScript 类型定义并不完全正确!

昨天晚上在 bgs 研究了(或者说调试了)XGS 写的 nodejs 服务器项目。他在用 koa 作为服务器,mongodb 作为数据存储,写一个不知道什么项目(似乎名为「写作者平台」/ “Write’s Platform”)。反正当时还处于很初级的阶段,只有两个路由,一个 get,一个 post,后者是用来向 mongodb 提交一篇文章的。在测试过程中,他发现了一个问题——他在保存文章的回调中更改了响应的内容(如下),但是实际测试得到的响应内容却是 koa 默认的 OK。

router.post('/path', (ctx, next) => {
    const article = new Article( /* something */ );
    article.save((err, article) => {
      if (err){
        ctx.body = err;
      } else {
        ctx.body = "success";
      }
    });
})

起初我发现,他的代码中,router.post('/path', (ctx, next) => { /* body */ });/* body */这段中并没有返回 next(),这应该会导致异步的回调没有被阻塞。

接着我想,可能又是 koa 的版本搞混了什么的,因为 koa v2,koa router 什么的版本管理都很混乱,长期处于虽然大家都想使用最新版,但是默认的却一直是旧版的情况。后来又出现了 koa 是新版,router 是旧版的情况,曾经我为别人解决过这个问题。

但是这次却不是。并且把返回 promise 切换为使用 async/await之后(如下),情况依然没有好转。

router.post('/path', (ctx, next) => {
    const article = new Article( /* something */ );
    return article.save((err, saved) => {
      if (err){
        ctx.body = err;
      } else {
        console.log(saved);
        ctx.body = "success";
      }
      // or `return next();` here.
    }).then((thing) => {
        console.log(thing);
        return next();
    });
})

(过程中我们发现这个传给回调的 thing居然是undefined,这是个伏笔)

渐渐地我被各种函数的签名(比如究竟应该返回一个什么,是 next() 还是一个 promise,而 next 的类型又是什么?)搞得烦躁起来。于是我提议使用 TypeScript 来辅助检查。

我们开始怀疑 article.save这个函数。因为在 koa 官方(仅有)的、涉及到等待异步动作的 router 代码样例里,完全类似的代码是可以工作的:

router.get(
  '/users/:id',
  function (ctx, next) {
    return User.findOne(ctx.params.id).then(function(user) {
      ctx.user = user;
      return next();

    });
  },
  function (ctx) {
    console.log(ctx.user);
    // => { id: 17, name: "Alex" }
  }
);

于是我们着重检查了 mongoose 的 TypeScript 类型定义文件。这个 articleArticle的实例,而Article实际上是 mongoose 动态构造出来的一个类(应该是通过了某种元编程技术)。在类型定义中是这么反映的:

interface Model<T extends Document> extends NodeJS.EventEmitter, ModelProperties {
    new(doc?: Object): T;
    /* other things */
}

而 article 就是那个<T extends Document>,而 Documentsave方法是这么写的:

    /**
     * Saves this document.
     * @param options options optional options
     * @param options.safe overrides schema's safe option
     * @param options.validateBeforeSave set to false to save without validating.
     * @param fn optional callback
     */
    save(options?: SaveOptions, fn?: (err: any, product: this, numAffected: number) => void): Promise<this>;
    save(fn?: (err: any, product: this, numAffected: number) => void): Promise<this>;

(取自 npm install @types/mongoose的结果,不知为何与 DefinitelyTyped 上的有所不同。)看到这,特别是Promise<this>,我就确信了,这个函数没有问题。可是上面返回的thing又确乎是一个undefined,难道是我们的使用姿势有问题?

万般无奈之中,TypeScript 也不靠谱之际,我们只能诉诸源码了。鉴于 mongoose 的代码风格,直接搜索 .prototype.save就能找到。它实际上是在这里,但是看到这里让人更崩溃了:

Model.prototype.save = function(options, fn) {
  if (typeof options === 'function') {
    fn = options;
    options = undefined;
  }

  if (!options) {
    options = {};
  }

  if (fn) {
    fn = this.constructor.$wrapCallback(fn);
  }

  return this.$__save(options, fn);
};

它返回的是this.$__save的结果,但这个函数并没有返回值!日志显示,这里的this就是这个article实例(一个Document)。然而线索到这里似乎断了。怎么能凭空从一个没有返回值的函数返回一个 promise 呢?

我们又想到了一招:查看调用栈。但是 node 的调试器在这时却不好使了。我们只能用原始粗暴的console.trace手动搞出调用栈。虽然没有直接的线索,这个调用栈给了我们一些提示——save并不是直接调用的,而是经过了某种hook的封装。

这时,我想到了直接console.log(article.save),它居然是一个wrappedPointCut出来的结果!再在代码里搜索wrappedPointCut就非常接近真相了。关键的代码在这里

model.prototype[pointCut] = (function(_newName) {
      return function wrappedPointCut() {
        var Promise = PromiseProvider.get();

        var _this = this;
        /* something omitted for simplicity */
        var promise = new Promise.ES6(function(resolve, reject) {
          args.push(function(error) {
            if (error) {
              /* something omitted for simplicity */
              reject(error);
              return;
            }
            $results = Array.prototype.slice.call(arguments, 1);
            resolve.apply(promise, $results);
          });
          _this[_newName].apply(_this, args);
        });
        if (fn) {
          /* something omitted for simplicity */
          return promise.then(
            function() {
              process.nextTick(function() {
                fn.apply(null, [null].concat($results));
              });
            },
            function(error) {
              process.nextTick(function() {
                fn(error);
              });
            });
        }
        return promise;
      };
    })(newName);

注意到如果没有fn,那么会在第 33 行返回第 7 行定义的 promise,如果有fn,就会直接在第 21 行返回接续之前的 promise 的另一个 promise,这个接续(.then())里面利用了fn处理了结果,却没有返回。也就是说,这时候的返回值是Promise<undefined>而不是Promise<this>——我们被这样的 TypeScript 类型定义坑惨了!如果它一开始就告诉我们会这样,那该多好呀,就像这样:

    save(options: SaveOptions, fn: (err: any, product: this, numAffected: number) => void): Promise<undefined>;
    save(fn: (err: any, product: this, numAffected: number) => void): Promise<undefined>;
    save(options?: SaveOptions): Promise<this>;
    save(): Promise<this>;

2017 年 5 月 4 日

Like
Like Love Haha Wow Sad Angry
2

一次隨機騎行

Like
Like Love Haha Wow Sad Angry
1

本来去讨论“英国历史与经典文献选读”的展示,完了之后突然想去沃爾瑪買奶酪,中途發現沒錢,索性騎到市區玩玩好了,結果卻騎到了萬象城。當然鑒於一分錢沒帶,就只能拍拍照啦。。。

Ralf Lauren的童裝櫥窗,擺設得有點意思。
Ralf Lauren的童裝櫥窗,擺設得有點意思。

途中本想在慶春路的書店停下逛逛,奈何拖延糾結中就過去了。好在萬象城也有家實體書店,Page One。它售賣的淨是些小資情調的書,什麼室內設計啦、烹飪飲食啦、文史哲啦,有很多英文書。

Continue reading “一次隨機騎行”

Like
Like Love Haha Wow Sad Angry
1

这些无法翻译的外语单词有哪些故事/典故?

Like
Like Love Haha Wow Sad Angry

tumblr的舶來品?原文英語,譯作中文更爲冗長,但真地要這麼多字才能表達嗎?原作恐有故意嘮叨博取噱頭之嫌。

再者很多詞(包括但不限於我認識的)也並不神奇。

waldeinsamkeit = wald + einsamkeit = forest + loneliness = 林中孤獨(孤感?)
почемучка = почему + чка = 爲什麼 + 指小的後綴,實則專指小孩,《简明俄汉词典》的“小問號”之譯乃至勝過原詞。
木漏れ日 = 木(樹) +漏れ(漏れる)+ 日(太陽),譯作漢語也許去掉假名即可。
dépaysement = dépayse(r) + ment,化dépayser(離鄉,或者「遷」我看就行)爲名詞。有的詞典作好感,有的詞典作不適,還有一「流放」的廢意。「離鄉」之類也是古意。

Continue reading “这些无法翻译的外语单词有哪些故事/典故?”

Like
Like Love Haha Wow Sad Angry

读《云图》的俄语台词 (4)

Like
Like Love Haha Wow Sad Angry

ОБЛАЧНЫЙ АТЛАС

Острова Тихого Океана, 1849 год.

Дело сделано, мистер Юинг, теперь сей контракт свят для исполнения… почти как Десять Заповедей.

сделано: 完成
сей: 这个
свят: 神圣的
исполнения: 执行, 完成
почти: 几乎
Заповедей: 戒律

Благодарю, Преподобный Хоррекс, мой тесть с нетерпением ждёт завершения этой сделки.
Преподобный: Reverend教士
тесть: 继父
нетерпением: 不耐烦
ждёт: 等待,期待
завершения: 完成,补完
сделки: 交易 Continue reading “读《云图》的俄语台词 (4)”

Like
Like Love Haha Wow Sad Angry

读《云图》的俄语台词 (3)

Like
Like Love Haha Wow Sad Angry

– Здравствуйте.
– Ваш пропуск.
Смотрю вы начеку?

пропуск: pass, admission
начеку: on the alert


Я был издателем Дермонта Хоггинса, а не психоаналитиком или астрологом, и это чёртова, чёртова правда, я и понятия не имел, что он сделает в тот вечер.

издателем: publisher
психоаналитиком: psychoanalyst
астрологом: astrologer
понятия: idea
имел: have
тот: that
вечер: evening

Continue reading “读《云图》的俄语台词 (3)”

Like
Like Love Haha Wow Sad Angry

《云图》中的一句话 (I)

Like
Like Love Haha Wow Sad Angry

Теперь я понимаю, что границы между шумом и звуком условный. Любые границы условный, и созданный, чтобы их переступать. Всё условности преодолимый, стоит лишь поставить для себя эту цель.

граница: limit, confine
между: between
шум: noise Continue reading “《云图》中的一句话 (I)”

Like
Like Love Haha Wow Sad Angry

多项式和幂级数 (I)

Like
Like Love Haha Wow Sad Angry

今天我们讨论多项式

交换环上

Nilpotents and units are closely related. In a commutative unital ring R, if x nilpotent, a unit, then a+x is again a unit. If 1+x y is a unit for every y\in R, then x\in\mathfrak{R}, the Jacobson radical, approximately nilpotent. Continue reading “多项式和幂级数 (I)”

Like
Like Love Haha Wow Sad Angry

读《云图》的俄语台词 (2)

Like
Like Love Haha Wow Sad Angry

Вот тогда-то я и свёл знакомство с доктором Генри Гуссом, с человеком, который, как я надеялся, сможет излечить мой недуг.
Вы что-то ищите?


тогда-то: then, at that time
свёл (свести): took; свёл знакомство с: made the acquaintance of
который: who
надеялся: hope
сможет: be able to
излечить: cure
недуг: ailment, illness
что-то: something
ищите: look for, search after

Continue reading “读《云图》的俄语台词 (2)”

Like
Like Love Haha Wow Sad Angry

《交换代数》习题研讨 (I)

Like
Like Love Haha Wow Sad Angry

  1. Units
    , nilpotents, and idempotents lift from A/\mathfrak{N} to A.Proof: Units and nilpotents are obvious. In fact they lift to any of their representatives.
    For idempotents, if x^2=x\in A/\mathfrak{N}, then (1-x)x=0 \in A/\mathfrak{N}, so (1-x)^kx^k=0\in A for sufficiently large k. And (1-x)^k+x^k=1-x+x=1\in A/\mathfrak{N}, so lifts to a unit (1-x)^k+x^k. Moreover, its inverse u=1\in A/\mathfrak{N}. So (ux)^k(u(1-x))^k=0,ux^k+u(1-x)^k=1\in A and ux=x,u(1-x)=1-x\in A/\mathfrak{N}.
    This can be interpreted by sheaf theory, which is to be discussed in later posts. Continue reading “《交换代数》习题研讨 (I)”
Like
Like Love Haha Wow Sad Angry

一个简单的组合问题及相关的思考

Like
Like Love Haha Wow Sad Angry

Problem: If the decimal expansion of a contains all 10 digits (0,...,9), then the number of length n strings (shorted as n-strings) is greater than n+8.

If you’ve established the simple lemma, the solution is instant. Otherwise very impossible.

Lemma: The number C_n of n-strings is strictly greater than C_{n-1}, that of n-1-strings.
Actually,  we always have C_n \ge C_{n-1}: Every n-1-string corresponds to an n-string by continuing 1 more digit. The map is clearly injective. If C_n=C_{n-1}, it is bijective, meaning we have a way to continue uniquely, which means rationality. Rigidly, at least one of the n-1-strings occurs infinitely, but all digits after some n-1-string is totally determined by it. So if an n-1-string appears twice, it must appear every such distances, and so do the digits between. Continue reading “一个简单的组合问题及相关的思考”

Like
Like Love Haha Wow Sad Angry