From 81a26e922c2997adc25f838e6227f831b443bb50 Mon Sep 17 00:00:00 2001 From: thinklive1 <469631989@qq.com> Date: Sun, 3 Dec 2023 23:55:29 +0800 Subject: [PATCH] Site updated: 2023-12-03 23:55:28 --- .../61a\346\200\273\345\222\214/index.html" | 4 +- .../index.html" | 8 +- .../index.html" | 8 +- .../index.html" | 8 +- .../index.html" | 8 +- .../index.html" | 4 +- .../index.html" | 25 +- archives/2023/09/index.html | 8 +- archives/2023/09/page/2/index.html | 4 +- archives/2023/page/3/index.html | 12 +- archives/page/3/index.html | 12 +- atom.xml | 249 ++++++++--------- .../black-souls/index.html" | 12 +- .../index.html" | 12 +- index.html | 9 +- page/2/index.html | 66 ++--- page/3/index.html | 103 +++---- page/4/index.html | 59 ++-- search.xml | 255 +++++++++--------- sitemap.txt | 26 +- sitemap.xml | 56 ++-- tags/black-souls/index.html | 12 +- .../index.html" | 12 +- 23 files changed, 492 insertions(+), 480 deletions(-) diff --git "a/2023/09/29/61a\346\200\273\345\222\214/index.html" "b/2023/09/29/61a\346\200\273\345\222\214/index.html" index 2904926de..69ed94fad 100644 --- "a/2023/09/29/61a\346\200\273\345\222\214/index.html" +++ "b/2023/09/29/61a\346\200\273\345\222\214/index.html" @@ -608,8 +608,8 @@

生成器生成树的搜索路径

-
diff --git "a/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" "b/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" index 9625d413f..b3fddc7bf 100644 --- "a/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" +++ "b/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" @@ -359,13 +359,13 @@

玛丽苏

-
-
diff --git "a/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" "b/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" index f66005d33..c51d75457 100644 --- "a/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" +++ "b/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" @@ -356,13 +356,13 @@

-
-
diff --git "a/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" "b/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" index 5e58064db..1c43a7358 100644 --- "a/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" +++ "b/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" @@ -378,13 +378,13 @@

ex02

-
-
diff --git "a/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" "b/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" index cbb899389..343fe5ff6 100644 --- "a/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" +++ "b/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" @@ -441,13 +441,13 @@

汉诺塔递归

-
-
diff --git "a/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" "b/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" index c3387dda0..b94e44e88 100644 --- "a/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" +++ "b/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" @@ -424,8 +424,8 @@

涉及的c++特性

-
diff --git "a/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" "b/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" index 802b58a2e..10ec0e4d9 100644 --- "a/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" +++ "b/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" @@ -22,15 +22,15 @@ - + - + - + @@ -274,7 +274,7 @@

发表于 - +

操作系统:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用

基本特征

操作系统的基本特征包括开并发,共享,虚拟和异步 1. 并发 并发是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。 并行性是指系统具有同时进行运算或操作的特性,在同一时刻能完成两种或两种以上的动作并行性要有相关硬件的支持, 如多流水线或多处理机硬件环境

  1. 共享 共享:系统内的某些资源可以供并发的不同进程使用,分为以下几种方式
  2. 互斥共享 规定在一段时间内只充许 一个进程访问该资源,系统分配该资源前,必须确保没有其他进程正在使用它,分配后,在进程访问并释放该资源后,其他进程对资源的申请才会被操作系统允许。 这种一段时间内只能被一个进程占有的资源被称为临界资源 大部分硬件,某些软件的栈,变量等都属于临界资源
  3. 同时访问 某些系统资源可以在同一时间段内被多个进程同时访问,例如文件系统,这种同时访问可能是交替进行。 互斥共享要求一种资源在一段时间内(哪怕是一段很小的时间)只能满足一个请求,同时访问通常要求一个请求可以分时间片间隔地完成,效果和连续完成相同

并发和共享是操作系统两个最基本的特征,两者之间互为存在的条件: - 资源共享是以程序的并发为条件的:若系统不充许程序并发执行,则自然不存在资源共享问题 - 若系统不能对资源共享实施有效的管理,则必将影响到程序的并发执行,其至根本无法并发执行。

  1. 虚拟 虚拟是指把一个物理上的实体变为若干逻辑上的对应物。 虚拟处理器技术是通过多道程序设计技术,采用让多道程序并发执行的方法,来分时使用一 个处理器的。此时,虽然只有一个处理器,但它能同时为多个用户服务 把一个物理cpu虚拟成多个虚拟cpu,称为虚拟处理器 虚拟技术可以在时间或者空间上进行相应的现实虚拟转换

  2. 异步 虽然进程可以并发进行,但推进速度,时间等是不确定的,操作系统必须确保,相同环境下相同操作的进程得到相同的结果,不论时间多久

功能

  1. 管理系统资源
    1. 处理机(进程)的管理,包括创建,调度,死锁检测和恢复等
    2. 存储器管理,即内存的分配和管理
    3. 文件管理,即操作系统的文件系统空间,目录,格式等
    4. 设备管理,处理用户的I/O请求
  2. 提供用户接口操作硬件和程序
    1. 命令接口
      1. 联机命令接口(交互式命令接口,适用于实时或分时系统):用户通过终端实时输入命令与操作系统交换,输入一条,操作系统解释并执行一条,然后才可以输入下一条(shell)
      2. 脱机命令接口(批处理命令接口,适用于批处理系统):用作业控制命令写成一本作业说明书,操作系统读取说明书,逐条解释执行 (脚本)
    2. 程序接口:有一系列系统调用组成,,用户在程序中使用这些系统调用命令来让操作系统提供相应服务,例如GUI界面(严格的说gui界面只是使用了操作系统提供的图形相关的系统调用)
  3. 实现了对计算机资源的扩充

历史

]]> + 概论

操作系统:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用

基本特征

操作系统的基本特征包括开并发,共享,虚拟和异步

  1. 并发 并发是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。 并行性是指系统具有同时进行运算或操作的特性,在同一时刻能完成两种或两种以上的动作并行性要有相关硬件的支持, 如多流水线或多处理机硬件环境

  2. 共享 共享:系统内的某些资源可以供并发的不同进程使用,分为以下几种方式

  3. 互斥共享 规定在一段时间内只充许 一个进程访问该资源,系统分配该资源前,必须确保没有其他进程正在使用它,分配后,在进程访问并释放该资源后,其他进程对资源的申请才会被操作系统允许。 这种一段时间内只能被一个进程占有的资源被称为临界资源 大部分硬件,某些软件的栈,变量等都属于临界资源

  4. 同时访问 某些系统资源可以在同一时间段内被多个进程同时访问,例如文件系统,这种同时访问可能是交替进行。 互斥共享要求一种资源在一段时间内(哪怕是一段很小的时间)只能满足一个请求,同时访问通常要求一个请求可以分时间片间隔地完成,效果和连续完成相同

并发和共享是操作系统两个最基本的特征,两者之间互为存在的条件:

  1. 虚拟 虚拟是指把一个物理上的实体变为若干逻辑上的对应物。 虚拟处理器技术是通过多道程序设计技术,采用让多道程序并发执行的方法,来分时使用一 个处理器的。此时,虽然只有一个处理器,但它能同时为多个用户服务 把一个物理cpu虚拟成多个虚拟cpu,称为虚拟处理器 虚拟技术可以在时间或者空间上进行相应的现实虚拟转换

  2. 异步 虽然进程可以并发进行,但推进速度,时间等是不确定的,操作系统必须确保,相同环境下相同操作的进程得到相同的结果,不论时间多久

功能

  1. 管理系统资源
    1. 处理机(进程)的管理,包括创建,调度,死锁检测和恢复等
    2. 存储器管理,即内存的分配和管理
    3. 文件管理,即操作系统的文件系统空间,目录,格式等
    4. 设备管理,处理用户的I/O请求
  2. 提供用户接口操作硬件和程序
    1. 命令接口
      1. 联机命令接口(交互式命令接口,适用于实时或分时系统):用户通过终端实时输入命令与操作系统交换,输入一条,操作系统解释并执行一条,然后才可以输入下一条(shell)
      2. 脱机命令接口(批处理命令接口,适用于批处理系统):用作业控制命令写成一本作业说明书,操作系统读取说明书,逐条解释执行 (脚本)
    2. 程序接口:有一系列系统调用组成,,用户在程序中使用这些系统调用命令来让操作系统提供相应服务,例如GUI界面(严格的说gui界面只是使用了操作系统提供的图形相关的系统调用)
  3. 实现了对计算机资源的扩充

历史

]]>
<h1 id="概论">概论</h1> <p><code>操作系统</code>:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用</p> <h2 id="基本特征">基本特征</h2> -<p><code>操作系统</code>的基本特征包括开并发,共享,虚拟和异步 1. 并发 <code>并发</code>是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。 <code>并行性</code>是指系统具有同时进行运算或操作的特性,在同一时刻能完成两种或两种以上的动作<code>并行性</code>要有相关硬件的支持, 如多流水线或多处理机硬件环境</p> -<ol start="2" type="1"> -<li>共享 <code>共享</code>:系统内的某些资源可以供并发的不同进程使用,分为以下几种方式 +<p><code>操作系统</code>的基本特征包括开并发,共享,虚拟和异步</p> +<ol type="1"> +<li><p>并发 <code>并发</code>是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。 <code>并行性</code>是指系统具有同时进行运算或操作的特性,在同一时刻能完成两种或两种以上的动作<code>并行性</code>要有相关硬件的支持, 如多流水线或多处理机硬件环境</p></li> +<li><p>共享 <code>共享</code>:系统内的某些资源可以供并发的不同进程使用,分为以下几种方式 @@ -518,31 +519,6 @@ - - 游戏互动性的新探索——步行模拟器 - - https://thinklive1.github.io/2023/09/30/%E6%AD%A5%E8%A1%8C%E6%A8%A1%E6%8B%9F%E5%99%A8/ - 2023-09-30T11:35:13.293Z - 2023-11-27T12:47:59.707Z - - 步行模拟器,在本视频中取操作只局限于步行和一些简单动作,主要获取信息的途径为阅读和观察的游戏,这是一种颇为先锋,也颇为小众的游戏类型,在其中有一些火到出圈的佳作,也有缺点明细的庸作,但都有着共性在其中,今天,我就用一个业余爱好者的身份来浅析一下这类游戏。 我们先从步行模拟器的历史说起,由于我不是专业人士,也不是什么老玩家,所以只能大概地说说。 溯及这类游戏的根源是一件很难且没有必要的事情,所以我们只把目光放在本世纪好了,在2007年,一个传奇的年份,当时的游戏界见证了巫师一,质量效应一,刺客信条一等传奇系列首作的诞生,也有一些人注意到一款名为《亲爱的艾斯特》的奇异游戏,对一个原教旨主义者来说它可能算不上游戏,玩家操控着一位失去妻子的男人在孤岛上步行,整部游戏唯一的信息来源就是沿途的风景,壁画,以及男人的自言自语,某种意义上这带来了一种推理小说式的体验,你需要在文本中领略事件的来龙去脉,同时体验它压抑深沉的环境氛围。 亲爱的艾斯特取得了意想不到的小范围成功,本作为免费游戏的它在12年发布了付费版,并取得了80万的销量,可以说,近十年的步行模拟器很大程度上是由它启蒙的。 因此,以12年为分水岭,逐渐涌现出不少的步行模拟器游戏。 13年亮相的是著名的meta游戏史丹利的寓言和较为平庸的到家(gone home) 14年问世的是解密风的伊森卡特的消失 15年艾斯特的工作室发行了同类型的万众狂欢 16年则有看火人与弗吉尼亚出现 而在17年,此类型的集大成者,艾迪芬奇的记忆横空出世,成为了此类型至今为止的最优者 可能不少对此类游戏毫无兴趣的玩家会好奇,步行模拟器的卖点到底在哪? 在这个媒体资源空前丰富的时代,每个人都能输出自己的思想,因此思想的输出变得极为廉价,而接受者的地位却会被拔高,因此,门槛越高的思想输出方式就有着越大的不被接受的风险,导致晦涩隐喻的内容就会不受待见。尽管如此,这些晦涩的思想与表达依旧是存在的,步行模拟器就是一种方式。 事实上,接受他人的思想表达一直都有很大的风险,只要作者多加一点私货,或者在莫名其妙的地方整个活,接受者的思想就会收到极大的冲击,例子我就不举了,懂得都懂。所以很多人都会倾向于不去接受,晦涩的作品他们根本不会碰,也有的人沉迷于此类快感,不顾风险地追寻自己认为好的输出者,这两种选择没有高下之分,但体现在游戏上,我们就会发现后者经常会成为所谓的小众游戏爱好者,这并不意味着他们很优越,相反,他们可能已经踩过不知道多少雷了。 为此前的论述做一个总结,步行模拟器可以作为一个高门槛的思想输出方法,因此能吸引一些喜欢此类体验的玩家。事实上,它和同样强调探索的avg可能存在一些关系,但由于我对此没有足够的知识,就不献丑了。 在此基础上,我们来分析此类游戏的一些特性。 首先,第一个问题是,为什么要用步行模拟器这种形式,毫无疑问这种游戏的互动性基本不是很强,也没有刺激官能的要素,然而,正是因为这种自断一臂式的操作,让它能够把自己的叙事能力提高到大部分游戏所不能及的程度,玩法单一也就意味着玩家的注意力会完全集中于一点,制作者只要专注于此方面,就能高频度地向玩家提供信息,而不会让人一头雾水,因为这样的特点,相比大部分游戏,步行模拟器可以聚焦于很多与众不同的题材,可以选用不同的叙事方式, 另一个优点是,较小的游戏规模与如今相对成熟的游戏工业,让制作者能以较为低廉的成本做出不同的场景,美术效果和环境在步行模拟器中有很大的作用,我之所以这么说,不仅是因为它有着渲染气氛的作用,在很多此类游戏中,环境本身就承担着叙事的任务,尤其以艾迪芬奇的记忆而言,环境在这款游戏中达到了当代游戏的新高度,不同的房间布置在无言中传达了房间主人的个性,甚至在一些细节中暗示了主人的命运。可以这么说,在很多步行模拟器中,环境有着超越装饰的作用 步行模拟器还有一个特点,那就是它是第一人称的,你可能单纯地觉得这是为了提高代入感,但事实上,因为互动性的匮乏,步行模拟器往往更趋向于探索和体验,而不是扮演,更形象的说法是,在步行模拟器中看到的是别人的故事,因此在我看来,第一人称更多的意义是类似侦探小说的叙述主体,也就是说,以这个故事而言,第一人称对应的角色就是最适合展现故事全貌的人,同时,这个主体具体的身份也可以是一个谜题,伊森卡特的消失,艾迪芬奇的记忆都在这方面上做了文章,非常有趣。 上述特点事实上还是很笼统的,实际上的步行模拟器在风格和题材上都是各具特色,特点也不尽相同,但由于到目前为止出名的步行模拟器实在不多,所以我们就用穷举的方法来说说这些步行模拟器。 先从最早的亲爱的艾斯特说起 在所有步行模拟器中,艾斯特应该是互动性最低的一个,你能做的只有控制一个喃喃自语的男人在孤岛上乱走,然而,艾斯特依然是一部很优秀的游戏,优秀的文本质量和环境建模完美地融合在了一起,配合迷雾重重的故事,与四个风格迥异的场景与种种细节,成功营造出了一种哀伤中透着迷幻的气氛。虽然选取了悼念亡妻的题材,但艾斯特并没有直接表现哀伤,叙事主体的男子呈现的态度是思辨的,其文本很有些深度,艾斯特的氛围塑造与文本水平,我个人认为是步行模拟器中最优秀的之一,并没有被后来者超越,甚至也没有被他们自己超越。 史丹利的寓言 这游戏很难归类,它更为众人所熟悉的标签是meta游戏,举个不恰当的例子,meta游戏和游戏的区别就像文学批评和文学的区别,很难说史丹利的目的是对游戏这一创作形式进行批判还是呈现一段故事。 这游戏几乎是靠作者一个人的天才撑起来的,即便在meta游戏中有史丹利寓言这么强烈批判属性的游戏,据我所知也是不存在的,它很有创设性的给予了游戏四个视角两个阵营,呈现者阵营的游戏系统(游戏作者?)与旁白,接受者阵营的史丹利与玩家本人,史丹利的故事几乎都是两个阵营间不同角色的互动,它实现了大部分游戏都做不到的一点,即让玩家直接与游戏的底层逻辑对话。 现代游戏互动性的本质是什么,无非不过是选择而已,拟真度高的游戏也不过是多提供了一些选项,史丹利抓住了这个底层逻辑,因此哪怕是步行模拟器这一形式只要用好“选择”,就不会缺少互动性。 这样的策略让史丹利显得不是那么“步行模拟器”,但实际上这还是一部叙事游戏,只不过它的故事千变万化,且富有批判意味,而且它的叙事有着“选择”的成分,因此它包含了十几个不同的故事。 归家 归家是一部很有实验意义的作品,如果你情商比较高的话,应该就知道我的意思是这游戏有着不少的缺点,归家的故事发生在20世纪末的一个美国家庭,一个暴风雨之夜,家中的姐姐回到家中,发现妹妹离家出走,于是开始寻找原因,归家的核心机制是拾取/查看物体触发回忆,核心谜题则是揭开妹妹的下落,然而这游戏的故事非常简单,简单到什么程度呢?在触发前三个回忆后你基本上就能猜到故事的梗概了——没错,一个俗套的恋爱被父母反对然后私奔的故事,稍微有些不同的是,主角是两位女同性恋,此外,游戏中有一些不怎么明显的机关且缺乏提示的机关,总体感觉实在是索然无味,尽管某种意义上它为有核心谜题的步行模拟器树了一个榜样,但论其素质十分乏善可陈,最大的优点可能是还算有20世纪风格的家居布置。 值得一提的是ign给了归家9.5的超高分,对ign来说这种分数是很少见的,我们之前提到的艾斯特得到了8分,史丹利寓言得到了8.8分,而品质平平的到家则得到了9.5分的超高评价,并且编辑的评论是没有缺点,联系其故事题材,此件原因令人深思,因为涉及敏感话题,我就不多说了 伊森卡特的消失 这是一部很有风格的作品,在场景建模上制作组创作性的采用了结合实景照片的做法,因此画质显得极为真实,配合微恐怖的风格,代入感极强,游戏的内容是一个有着回溯犯罪现场能力的侦探应伊斯卡特的邀请调查一个据说有着不可名状怪物的地区的系列凶杀案,抛开几乎为0的地图指引,游玩过程中你会觉得这似乎就是一个普通的解谜游戏,虽有称道之处,但综合来看质量一般,然而,这款游戏最值得称道的一点是,制作组为了一个有极大反转的结局在流程中埋了不少伏笔,因此伊森卡特的结局在我看来在叙事游戏中算最优秀的一档,当然实际上这也是见仁见智的一件事,或许也有不少人觉得铺垫不足。 在步行模拟器中悬疑风格的作品伊斯卡特应该可以说是最成功的。 万众狂欢 这是一部和亲爱的艾斯特风格迥异的作品,它没有叙事主体,玩家以超然的眼光去回顾一座村庄全员蒸发的惨剧,我认为这是一部失败的作品,为什么呢。作为一个拼凑出故事全貌的游戏,万众狂欢很不幸的选择了把最大的悬念放在开头——凶手是形似光球的不可名状生物,而游戏的过程则是目睹居民怎么一步步迈向死亡,整个过程中的互动,只有不如不做的触发回忆过程有——跟着手柄按QTE。具体到故事,恕我直言是很无聊的,寥寥几语的场景中大部分缺少让人身临其境的氛围营造,整部游戏有着浓郁的宗教风格,因此部分场景会有种神圣感,但也就仅此而已了,没有悬念,没有细腻的情感,没有复杂精彩的故事,更没有氛围的营造,万众狂欢在我看来是一部平庸的游戏 看火人 在众多步行模拟器中,看火人是极其冷门的纯写实题材,它选取了森林看护员这一冷门的职业视角来叙述故事,然而它的美术风格却是抽象的大色块风格,这造就了看火人实中有虚的奇妙质感,不论看火人的故事如何,这样的题材与美术创新是优秀的且值得鼓励的。 主角亨利在爱妻患病后心灰意冷,因为酗酒被妻子家人排挤的他最后来到了荒无人烟的森林公园成为了火情瞭望员,我们可以看到,游戏的主题几乎已经确定为心灵的救赎,但看火人的呈现方式是特别的,因为职业的特殊性,从始至终能与亨利交流的只有一位名为黛利拉的女性,在一片孤独的瞭望塔中这似乎是亨利唯一的情感支柱,事实上,看火人最大的优点就是情感的细腻,整个游戏几乎就是亨利与黛利拉互相的情感激励与救赎,最后这场类似柏拉图之恋的关系随着因为火情观察员撤离而收尾。 值得一提的是,看火人神奇的在游戏中夹杂了不少悬疑的成分,这让看火人的基调显得有些奇怪,由一开始的悠闲巡逻转到紧张的解密,随后又在急转直下后收尾,尽管不算无聊,但前后依旧有割裂感。 尽管如此,凭借细腻的情感描写,看火人依旧是一部优秀的游戏。 弗吉尼亚 这是一款很奇特的游戏,即使在步行模拟器里,它也是交互性最差的一类,它使用了一种极为抽象的风格,整个游戏由很多不明所以,充斥着象征的片段组成,而将这些片段串联到一起不过是一些点触的操作,坦白的说,我只能分离地去欣赏这些场景,单从象征的角度来说这些场景单独拿出来还挺有意思的,但你很难把这些片段连起来,事实上不让你把他们连起来可能正是这游戏的目的,此外,该游戏使用了很罕见的古典风格配乐,配合上本就很魔幻的内容产生了一种难以言喻的奇特的氛围。总的来说,这真的是一个很难评价的游戏,如果你有些猎奇心的话倒可以尝试一下 艾迪芬奇的记忆 艾迪芬奇的记忆是一款很优秀的游戏,但它的意义不仅如此,可以说在对互动性的新尝试方面,艾迪芬奇是游戏界最前沿的一个,游戏在叙事上最大的优势就是互动性,大部分游戏选择了剧情分支,qte之类的通解,而艾迪芬奇的记忆则在此基础上作出了创新,单论最简单的字幕,往往只被放置在屏幕底部用于阐释信息,而艾迪芬奇则将它放置在了场景之中,伴随着主角的前进逐渐浮现在路边,如此一来字幕甚至兼任了指引的作用。 依我看来,艾迪芬奇的主基调可以用魔幻二字来概括。随着艾迪依次探索旧宅,我们进入了一个个家族成员死前的景象中,但我们透过屏幕看到的不仅仅是一个个纪录片式的景象,还有情绪的具象化,例如令人啧啧称奇的操纵漫画中的角色一段,操纵角色在悬疑漫画的分镜中行走,这是一种崭新且绝妙的传递恐惧感的方式,艾迪芬奇的互动形式总是新颖的,角色伴随着开罐头喃喃自语,在切鱼的流水线上展开与工作融为一体的幻想,手柄的两遥感分别控制现实与幻想世界,此类新颖的设想,艾迪芬奇有近十种,可以这是一款极为奢侈的堆砌创意的游戏。 艾迪芬奇的家族大都耽于幻想,他们的幻想往往与现实融为一体,以此呈现出的情景显得分外的魔幻,以游戏的形式来叙述这样的故事,这一模式提供了一种特别的审视真实世界与内心世界的视角,这样类似魔幻现实主义的创作手法可以说极为前卫和有趣。 毫无疑问艾迪芬奇的互动性与创意是它最耀眼的闪光点,在此的映衬下,艾迪芬奇的剧情似乎显得暧昧不清,多个家庭成员的死亡都没有得到明确交代,尽管在一个个情景中我们能在画面中感知到情绪的具象化,尽管艾迪芬奇家族一向有着早死的诅咒,但艾迪芬奇没有,至少没有直接透露任何家庭成员对于死亡的看法,在一部探讨死亡的作品中这点显得很奇怪,似乎它只想将死亡本身呈现出来,却不想对此发表任何议论,我们很难说艾迪芬奇有什么主旨,在死亡这个主题上,制作组显得分外的冷漠,只留下玩家在原地回味。Steam上艾迪芬奇的商店页面有这样一句差评,艾迪芬奇的记忆有着美化死亡的嫌疑,这对那些有自杀倾向的人来说似乎太不友好了。这并不是没有道理。 总结 步行模拟器始终是个小众的品类,它固然有着一些创作上的优点,但成本和受众的因素始终制约着这一类型,导致作品寥寥无几,但在步行模拟器其实不乏对游戏这一创作形式的革新,作为新时代的叙事向avg游戏与独立游戏的一大阵营,步行模拟器的身上其实或多或少蕴含着电子游戏未来的一大方向,即作为有才能的作者表达自己的一种方式,对此我报以极大的期待。

]]>
- - - <p>步行模拟器,在本视频中取操作只局限于步行和一些简单动作,主要获取信息的途径为阅读和观察的游戏,这是一种颇为先锋,也颇为小众的游戏类型,在其中有一些火到出圈的佳作,也有缺点明细的庸作,但都有着共性在其中,今天,我就用一个业余爱好者的身份来浅析一下这类游戏。 - - - - - - - - - - - - -
- 游戏简评 @@ -600,6 +576,31 @@ + + 游戏互动性的新探索——步行模拟器 + + https://thinklive1.github.io/2023/09/30/%E6%AD%A5%E8%A1%8C%E6%A8%A1%E6%8B%9F%E5%99%A8/ + 2023-09-30T11:35:13.293Z + 2023-11-27T12:47:59.707Z + + 步行模拟器,在本视频中取操作只局限于步行和一些简单动作,主要获取信息的途径为阅读和观察的游戏,这是一种颇为先锋,也颇为小众的游戏类型,在其中有一些火到出圈的佳作,也有缺点明细的庸作,但都有着共性在其中,今天,我就用一个业余爱好者的身份来浅析一下这类游戏。 我们先从步行模拟器的历史说起,由于我不是专业人士,也不是什么老玩家,所以只能大概地说说。 溯及这类游戏的根源是一件很难且没有必要的事情,所以我们只把目光放在本世纪好了,在2007年,一个传奇的年份,当时的游戏界见证了巫师一,质量效应一,刺客信条一等传奇系列首作的诞生,也有一些人注意到一款名为《亲爱的艾斯特》的奇异游戏,对一个原教旨主义者来说它可能算不上游戏,玩家操控着一位失去妻子的男人在孤岛上步行,整部游戏唯一的信息来源就是沿途的风景,壁画,以及男人的自言自语,某种意义上这带来了一种推理小说式的体验,你需要在文本中领略事件的来龙去脉,同时体验它压抑深沉的环境氛围。 亲爱的艾斯特取得了意想不到的小范围成功,本作为免费游戏的它在12年发布了付费版,并取得了80万的销量,可以说,近十年的步行模拟器很大程度上是由它启蒙的。 因此,以12年为分水岭,逐渐涌现出不少的步行模拟器游戏。 13年亮相的是著名的meta游戏史丹利的寓言和较为平庸的到家(gone home) 14年问世的是解密风的伊森卡特的消失 15年艾斯特的工作室发行了同类型的万众狂欢 16年则有看火人与弗吉尼亚出现 而在17年,此类型的集大成者,艾迪芬奇的记忆横空出世,成为了此类型至今为止的最优者 可能不少对此类游戏毫无兴趣的玩家会好奇,步行模拟器的卖点到底在哪? 在这个媒体资源空前丰富的时代,每个人都能输出自己的思想,因此思想的输出变得极为廉价,而接受者的地位却会被拔高,因此,门槛越高的思想输出方式就有着越大的不被接受的风险,导致晦涩隐喻的内容就会不受待见。尽管如此,这些晦涩的思想与表达依旧是存在的,步行模拟器就是一种方式。 事实上,接受他人的思想表达一直都有很大的风险,只要作者多加一点私货,或者在莫名其妙的地方整个活,接受者的思想就会收到极大的冲击,例子我就不举了,懂得都懂。所以很多人都会倾向于不去接受,晦涩的作品他们根本不会碰,也有的人沉迷于此类快感,不顾风险地追寻自己认为好的输出者,这两种选择没有高下之分,但体现在游戏上,我们就会发现后者经常会成为所谓的小众游戏爱好者,这并不意味着他们很优越,相反,他们可能已经踩过不知道多少雷了。 为此前的论述做一个总结,步行模拟器可以作为一个高门槛的思想输出方法,因此能吸引一些喜欢此类体验的玩家。事实上,它和同样强调探索的avg可能存在一些关系,但由于我对此没有足够的知识,就不献丑了。 在此基础上,我们来分析此类游戏的一些特性。 首先,第一个问题是,为什么要用步行模拟器这种形式,毫无疑问这种游戏的互动性基本不是很强,也没有刺激官能的要素,然而,正是因为这种自断一臂式的操作,让它能够把自己的叙事能力提高到大部分游戏所不能及的程度,玩法单一也就意味着玩家的注意力会完全集中于一点,制作者只要专注于此方面,就能高频度地向玩家提供信息,而不会让人一头雾水,因为这样的特点,相比大部分游戏,步行模拟器可以聚焦于很多与众不同的题材,可以选用不同的叙事方式, 另一个优点是,较小的游戏规模与如今相对成熟的游戏工业,让制作者能以较为低廉的成本做出不同的场景,美术效果和环境在步行模拟器中有很大的作用,我之所以这么说,不仅是因为它有着渲染气氛的作用,在很多此类游戏中,环境本身就承担着叙事的任务,尤其以艾迪芬奇的记忆而言,环境在这款游戏中达到了当代游戏的新高度,不同的房间布置在无言中传达了房间主人的个性,甚至在一些细节中暗示了主人的命运。可以这么说,在很多步行模拟器中,环境有着超越装饰的作用 步行模拟器还有一个特点,那就是它是第一人称的,你可能单纯地觉得这是为了提高代入感,但事实上,因为互动性的匮乏,步行模拟器往往更趋向于探索和体验,而不是扮演,更形象的说法是,在步行模拟器中看到的是别人的故事,因此在我看来,第一人称更多的意义是类似侦探小说的叙述主体,也就是说,以这个故事而言,第一人称对应的角色就是最适合展现故事全貌的人,同时,这个主体具体的身份也可以是一个谜题,伊森卡特的消失,艾迪芬奇的记忆都在这方面上做了文章,非常有趣。 上述特点事实上还是很笼统的,实际上的步行模拟器在风格和题材上都是各具特色,特点也不尽相同,但由于到目前为止出名的步行模拟器实在不多,所以我们就用穷举的方法来说说这些步行模拟器。 先从最早的亲爱的艾斯特说起 在所有步行模拟器中,艾斯特应该是互动性最低的一个,你能做的只有控制一个喃喃自语的男人在孤岛上乱走,然而,艾斯特依然是一部很优秀的游戏,优秀的文本质量和环境建模完美地融合在了一起,配合迷雾重重的故事,与四个风格迥异的场景与种种细节,成功营造出了一种哀伤中透着迷幻的气氛。虽然选取了悼念亡妻的题材,但艾斯特并没有直接表现哀伤,叙事主体的男子呈现的态度是思辨的,其文本很有些深度,艾斯特的氛围塑造与文本水平,我个人认为是步行模拟器中最优秀的之一,并没有被后来者超越,甚至也没有被他们自己超越。 史丹利的寓言 这游戏很难归类,它更为众人所熟悉的标签是meta游戏,举个不恰当的例子,meta游戏和游戏的区别就像文学批评和文学的区别,很难说史丹利的目的是对游戏这一创作形式进行批判还是呈现一段故事。 这游戏几乎是靠作者一个人的天才撑起来的,即便在meta游戏中有史丹利寓言这么强烈批判属性的游戏,据我所知也是不存在的,它很有创设性的给予了游戏四个视角两个阵营,呈现者阵营的游戏系统(游戏作者?)与旁白,接受者阵营的史丹利与玩家本人,史丹利的故事几乎都是两个阵营间不同角色的互动,它实现了大部分游戏都做不到的一点,即让玩家直接与游戏的底层逻辑对话。 现代游戏互动性的本质是什么,无非不过是选择而已,拟真度高的游戏也不过是多提供了一些选项,史丹利抓住了这个底层逻辑,因此哪怕是步行模拟器这一形式只要用好“选择”,就不会缺少互动性。 这样的策略让史丹利显得不是那么“步行模拟器”,但实际上这还是一部叙事游戏,只不过它的故事千变万化,且富有批判意味,而且它的叙事有着“选择”的成分,因此它包含了十几个不同的故事。 归家 归家是一部很有实验意义的作品,如果你情商比较高的话,应该就知道我的意思是这游戏有着不少的缺点,归家的故事发生在20世纪末的一个美国家庭,一个暴风雨之夜,家中的姐姐回到家中,发现妹妹离家出走,于是开始寻找原因,归家的核心机制是拾取/查看物体触发回忆,核心谜题则是揭开妹妹的下落,然而这游戏的故事非常简单,简单到什么程度呢?在触发前三个回忆后你基本上就能猜到故事的梗概了——没错,一个俗套的恋爱被父母反对然后私奔的故事,稍微有些不同的是,主角是两位女同性恋,此外,游戏中有一些不怎么明显的机关且缺乏提示的机关,总体感觉实在是索然无味,尽管某种意义上它为有核心谜题的步行模拟器树了一个榜样,但论其素质十分乏善可陈,最大的优点可能是还算有20世纪风格的家居布置。 值得一提的是ign给了归家9.5的超高分,对ign来说这种分数是很少见的,我们之前提到的艾斯特得到了8分,史丹利寓言得到了8.8分,而品质平平的到家则得到了9.5分的超高评价,并且编辑的评论是没有缺点,联系其故事题材,此件原因令人深思,因为涉及敏感话题,我就不多说了 伊森卡特的消失 这是一部很有风格的作品,在场景建模上制作组创作性的采用了结合实景照片的做法,因此画质显得极为真实,配合微恐怖的风格,代入感极强,游戏的内容是一个有着回溯犯罪现场能力的侦探应伊斯卡特的邀请调查一个据说有着不可名状怪物的地区的系列凶杀案,抛开几乎为0的地图指引,游玩过程中你会觉得这似乎就是一个普通的解谜游戏,虽有称道之处,但综合来看质量一般,然而,这款游戏最值得称道的一点是,制作组为了一个有极大反转的结局在流程中埋了不少伏笔,因此伊森卡特的结局在我看来在叙事游戏中算最优秀的一档,当然实际上这也是见仁见智的一件事,或许也有不少人觉得铺垫不足。 在步行模拟器中悬疑风格的作品伊斯卡特应该可以说是最成功的。 万众狂欢 这是一部和亲爱的艾斯特风格迥异的作品,它没有叙事主体,玩家以超然的眼光去回顾一座村庄全员蒸发的惨剧,我认为这是一部失败的作品,为什么呢。作为一个拼凑出故事全貌的游戏,万众狂欢很不幸的选择了把最大的悬念放在开头——凶手是形似光球的不可名状生物,而游戏的过程则是目睹居民怎么一步步迈向死亡,整个过程中的互动,只有不如不做的触发回忆过程有——跟着手柄按QTE。具体到故事,恕我直言是很无聊的,寥寥几语的场景中大部分缺少让人身临其境的氛围营造,整部游戏有着浓郁的宗教风格,因此部分场景会有种神圣感,但也就仅此而已了,没有悬念,没有细腻的情感,没有复杂精彩的故事,更没有氛围的营造,万众狂欢在我看来是一部平庸的游戏 看火人 在众多步行模拟器中,看火人是极其冷门的纯写实题材,它选取了森林看护员这一冷门的职业视角来叙述故事,然而它的美术风格却是抽象的大色块风格,这造就了看火人实中有虚的奇妙质感,不论看火人的故事如何,这样的题材与美术创新是优秀的且值得鼓励的。 主角亨利在爱妻患病后心灰意冷,因为酗酒被妻子家人排挤的他最后来到了荒无人烟的森林公园成为了火情瞭望员,我们可以看到,游戏的主题几乎已经确定为心灵的救赎,但看火人的呈现方式是特别的,因为职业的特殊性,从始至终能与亨利交流的只有一位名为黛利拉的女性,在一片孤独的瞭望塔中这似乎是亨利唯一的情感支柱,事实上,看火人最大的优点就是情感的细腻,整个游戏几乎就是亨利与黛利拉互相的情感激励与救赎,最后这场类似柏拉图之恋的关系随着因为火情观察员撤离而收尾。 值得一提的是,看火人神奇的在游戏中夹杂了不少悬疑的成分,这让看火人的基调显得有些奇怪,由一开始的悠闲巡逻转到紧张的解密,随后又在急转直下后收尾,尽管不算无聊,但前后依旧有割裂感。 尽管如此,凭借细腻的情感描写,看火人依旧是一部优秀的游戏。 弗吉尼亚 这是一款很奇特的游戏,即使在步行模拟器里,它也是交互性最差的一类,它使用了一种极为抽象的风格,整个游戏由很多不明所以,充斥着象征的片段组成,而将这些片段串联到一起不过是一些点触的操作,坦白的说,我只能分离地去欣赏这些场景,单从象征的角度来说这些场景单独拿出来还挺有意思的,但你很难把这些片段连起来,事实上不让你把他们连起来可能正是这游戏的目的,此外,该游戏使用了很罕见的古典风格配乐,配合上本就很魔幻的内容产生了一种难以言喻的奇特的氛围。总的来说,这真的是一个很难评价的游戏,如果你有些猎奇心的话倒可以尝试一下 艾迪芬奇的记忆 艾迪芬奇的记忆是一款很优秀的游戏,但它的意义不仅如此,可以说在对互动性的新尝试方面,艾迪芬奇是游戏界最前沿的一个,游戏在叙事上最大的优势就是互动性,大部分游戏选择了剧情分支,qte之类的通解,而艾迪芬奇的记忆则在此基础上作出了创新,单论最简单的字幕,往往只被放置在屏幕底部用于阐释信息,而艾迪芬奇则将它放置在了场景之中,伴随着主角的前进逐渐浮现在路边,如此一来字幕甚至兼任了指引的作用。 依我看来,艾迪芬奇的主基调可以用魔幻二字来概括。随着艾迪依次探索旧宅,我们进入了一个个家族成员死前的景象中,但我们透过屏幕看到的不仅仅是一个个纪录片式的景象,还有情绪的具象化,例如令人啧啧称奇的操纵漫画中的角色一段,操纵角色在悬疑漫画的分镜中行走,这是一种崭新且绝妙的传递恐惧感的方式,艾迪芬奇的互动形式总是新颖的,角色伴随着开罐头喃喃自语,在切鱼的流水线上展开与工作融为一体的幻想,手柄的两遥感分别控制现实与幻想世界,此类新颖的设想,艾迪芬奇有近十种,可以这是一款极为奢侈的堆砌创意的游戏。 艾迪芬奇的家族大都耽于幻想,他们的幻想往往与现实融为一体,以此呈现出的情景显得分外的魔幻,以游戏的形式来叙述这样的故事,这一模式提供了一种特别的审视真实世界与内心世界的视角,这样类似魔幻现实主义的创作手法可以说极为前卫和有趣。 毫无疑问艾迪芬奇的互动性与创意是它最耀眼的闪光点,在此的映衬下,艾迪芬奇的剧情似乎显得暧昧不清,多个家庭成员的死亡都没有得到明确交代,尽管在一个个情景中我们能在画面中感知到情绪的具象化,尽管艾迪芬奇家族一向有着早死的诅咒,但艾迪芬奇没有,至少没有直接透露任何家庭成员对于死亡的看法,在一部探讨死亡的作品中这点显得很奇怪,似乎它只想将死亡本身呈现出来,却不想对此发表任何议论,我们很难说艾迪芬奇有什么主旨,在死亡这个主题上,制作组显得分外的冷漠,只留下玩家在原地回味。Steam上艾迪芬奇的商店页面有这样一句差评,艾迪芬奇的记忆有着美化死亡的嫌疑,这对那些有自杀倾向的人来说似乎太不友好了。这并不是没有道理。 总结 步行模拟器始终是个小众的品类,它固然有着一些创作上的优点,但成本和受众的因素始终制约着这一类型,导致作品寥寥无几,但在步行模拟器其实不乏对游戏这一创作形式的革新,作为新时代的叙事向avg游戏与独立游戏的一大阵营,步行模拟器的身上其实或多或少蕴含着电子游戏未来的一大方向,即作为有才能的作者表达自己的一种方式,对此我报以极大的期待。

]]>
+ + + <p>步行模拟器,在本视频中取操作只局限于步行和一些简单动作,主要获取信息的途径为阅读和观察的游戏,这是一种颇为先锋,也颇为小众的游戏类型,在其中有一些火到出圈的佳作,也有缺点明细的庸作,但都有着共性在其中,今天,我就用一个业余爱好者的身份来浅析一下这类游戏。 + + + + + + + + + + + + +
+ 爱丽丝的回忆 @@ -644,50 +645,50 @@ - 龙腾世纪三部曲 - - https://thinklive1.github.io/2023/09/30/%E9%BE%99%E8%85%BE%E4%B8%96%E7%BA%AA/ - 2023-09-30T11:45:00.003Z + 迪瑞克拉世界观轶事集 + + https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E8%BD%B6%E4%BA%8B%E9%9B%86/ + 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.707Z - dao

本世纪的欧美rpg里最出名的应该是巫师三了,你可能曾因为好奇去搜过cdpr的发家史,也就是从卖盗版游戏到引进游戏并本土化赚到了第一桶金,这个引进的游戏是博德之门,博德之门的开发商是生软。 这里插一句,波兰人的首秀巫师一在开发阶段几乎遇到了一个新游戏能想到的所有问题,这时生软仗义地扶了波兰人一把,才有了巫师一的面世,遂成rpg界一段佳话,不过后来二者先后拉了( 龙腾世纪本来在定位上是博德之门的替代品,因为版权问题生软不能继续开发博德之门,于是便做出了龙腾世纪起源,这一项目立项在02年,但直到07年得到了EA的支持才在09年把这一“神作”做了出来,直到这时EA还是带善人的形象,并没有露出狰狞的獠牙,而在生软的黄金时代打磨了7年的起源,我可以毫不夸张地说,哪怕今年推出这款游戏,它依然是年度最佳候选级别的神作。 我先说说,我为什么要做这个视频,其实在一开始,dao在我的心中的地位还没有要我做一个视频出来的程度,但在玩了龙腾世纪的后两作后,DAO在我心中地位飙升,可见对比的力量,这个杂谈系列会讲完我对龙腾世纪整个系列的感受,当然是纯个人感受,我不 是什么rpg遗老,只是一个当代rpg爱好者而已,如有不同意之处,反正我也不会改的。

当你打开dao建立存档时,你可以选择三个种族,三个职业,在种族内甚至有平民和贵族的区别,根据职业和种族的不同,光开头剧情就有六种,由此开始,玩家就能感受到dao的超高自由度。 当然,对于rpg来说,自由度并不是什么稀奇的东西,但dao的自由度是有其独特之处的,以自由度出名的上古卷轴五,它的自由度体现于扮演的角色的多样性,龙裔,战友团成员,冬堡法师等等,这几种身份并没有交集,是独立的,而起源的自由度体现在行为的自由,自由度再高的游戏也不能完全模拟现实,但高自由度的游戏只需要模拟到玩家一时间能想到或者能让他们觉得有趣的所有选项就够了,DAO做到了这点,举例来说,当你接到了调查黑恶势力的任务,你可以当个正义的使者把邪恶势力端了,也可以接受贿赂,甚至可以献祭奴隶来提高自己的力量,你可以与邪教合作玷污圣物,也可以屠杀邪教,杀死恶龙,扮演被选召的勇士,很多时候当你背叛道德时得到的奖励反而更好,高道德的行为除了增加部分队友的好感度并没有太多作用,与巫师类似,起源遵循着成人的价值观,尽管选择大部分时候不像巫师那么残酷,而且起源中后悔也是很容易的一件事,相对削弱了选择的分量。

我们再来说说提高起源代入感的另一个设计——队友系统,独身在一个苍茫浩瀚的魔幻世界冒险难免会感到孤独,巫师的解决方式是让杰洛特和爱人与亲友保持时不时的联系,上古卷轴的解决方式,嗯,我没感到有什么解决方式,至少本体没有,当然如果装了随从mod肯定就完全不一样了。在龙腾世纪起源中你绝不会感到孤独,相比其他知名rpg,生软最显著的优点应该就是队友塑造了,dao的队友大部分有着讨喜且有深度的人设,这是由海量的工作量撑起来的,在冒险时会随机出现队友间的闲聊,几乎所有队友两两组合都有为数不少的对话,或八卦,或正经或取笑,这让人感到队友都是活生生的人,同时也可想而知其中的工作量,单个角色的对话文字量往往都要以万为单位,此外,在营地和队友闲聊也能通过一些选项增减好感度,所有队友都有为数不少的对话树,并且随着好感度的增减还会解锁额外选项。 队友间除了友情也能发展出爱情,这就不得不提我认为在魔幻rpg中最有魅力的女角色——莫瑞甘,她是个荒野女巫的女儿,,价值观完全是混乱中立甚至偏邪恶的,你做好事她嫌你磨叽,做坏事说不定夸你有魄力,好感度低时会邀请你滚床单并声明只是玩玩,好感度高起来了反而不愿继续亲近——“明明说了只是玩玩,怎么你当真了呢”在游戏的结局莫瑞甘会不可避免地离去,而在一个(拿感情骗钱的)的dlc里沃顿却能不远万里追踪到正欲逃走的她,最终让莫瑞甘也承认了爱情的存在,不得不说我真被这段爱情所感动了,这种细腻的感情戏其实不输我们以感情线为特色的双剑系列(当然续作就没这么顶了) 代入感之外,起源的战斗系统也是极有意思的,多有意思呢,大概比巫师三好几十个上古卷轴五吧(不是)起源的系统在今天看也不算过时,采用一种可以随时暂停的即时战斗系统,同时可以为队友ai设置战术,选项极为详细,大佬光靠设置ai应该就可以全自动战斗,我这种咸鱼打boss还是要几步一暂停,很明显这是一种重策略轻即时的系统,不设技能栏上限让法师成为了团队灵魂,控制,辅助,aoe,单体爆发应有尽有,可以说带够蓝药,法师就是无敌的(大部分Boss远程攻击弱于近战),即便职业平衡不是那么好,但队友是可以随意搭配的,丰富的技能树,转职,加点策略,装备系统让起源的战斗和养成充满乐趣,当然大型迷宫各种怪潮难免会腻烦,不过比起后面两作真的是让我体验最好的战斗系统了。 最后我们来说说起源的剧情和任务设计,大恶魔苏醒,黑潮突起,作为临危受命的灰袍守护者,沃顿利用古老盟约集结联军,手刃大恶魔,可以说是一个很俗套的故事,怎么把这种看起来很俗的故事讲好呢,答案是独立的小故事相加辅以大量填充细节和设定,起源的几条线,法师,矮人,精灵,伯爵都是相对独立的故事,套路很简单:求援——当地陷入危机——解决危机——得到援助,期间夹杂背叛者洛根使绊的故事线,每个地方引出了一部分的世界观设定,起源有着极其繁杂的文本,尽管套路类似,但每条线提供的信息量都是复杂且独特的,同时也有着世界观内各个势力特有的风貌,安教的圣洁,矮人的森严都得到了体现,即使很想比较,龙腾世纪的世界观也是独特且复杂的,当然,相比起源的主线,支线反而比较一般,不乏收集的填充式支线,当然,队友的支线还是很有趣的,也有一些补充世界观的有趣支线。 说了这么多,应该基本说完了起源的特点,当然也有很多具体内容我并没有提及,事实上起源并不是没有缺点,比如优化太差,自带防沉迷,玩几个小时就会卡顿到没完继续,只能重启,此外,敌人种类稀缺,也存在强行推动剧情而忽略合理性的情节,甚至有手刃大恶魔实力的主角有的时候莫名其妙就当垫脚石了,但起源仍然是神作,作为一个玩惯了10年后游戏的人,我玩起源没有感到任何系统在恶心我,可见制作组对玩家体验的重视,这是龙腾世纪的续作都未能做到的,,这也是我为龙腾世纪和生软感到可惜的原因,下一期我会叙述我对两部续作的看法,当然批评为主,,, 出道即巅峰的起源全平台销量不过470w,或许正是这样的销量驱使着生软不惜与老玩家对立也要向着主机倾斜,只可惜了龙腾世纪成为了开幕即巅峰,出场即绝唱的一个悲剧……

da2

今天我们来说说龙腾世纪二,,龙腾世纪二是系列中一部很,额,很独特的作品,他刚发售时的风评,作为后来人我不是很清楚,不过就现在来看,da2的风评呈现一种两极分化的形势。 这里插一句奥,我个人感觉rpg游戏的受众是个很宽容的群体,我这种认为2077是款好游戏的人放一些地方可能被叫孝子了,但对现在龙腾世纪的粉丝来说这可能都不算事,举个例子吧,写文案的这天龙腾世纪吧有个直接辱骂起源人气角色的,甚至没什么人骂回去,这放在其他单机游戏圈子里是难以想象的,所以对于龙腾世纪二这样极其赶工的,大部分玩家评价起来基本没什么戾气,当然事实上我很喜欢这一点,也是这点造成了da2并没有招致较为深入的批评,今天我会详细地阐述这部作品的缺点,当然是以我的角度,同时我也不会带有什么负面情绪,我个人其实很喜欢这个系列,二代我也不是那么讨厌,但它的问题确实是露骨的,毕竟太温和往往就意味着圈子的自净能力不够,对一些问题往往就不能看的那么透彻。 我之前说了da2是一部赶工明显的作品,有多赶工呢,2077和它相比那都不算事,生软甚至没有给二代一个后缀名…… 我们先从系统性的问题说起 首先作为一个rpg游戏,da2从头到尾(一共三章)几乎一直在重复利用十几个地图,一样的别墅,一样的山洞(还Tm贼亮)等等,这也是所有玩家都承认的一个问题,考虑到14个月的工期,这点可能也是难以避免的,不过这个问题实际上并不止这么简单,因为地图的数量太少,各种任务线又要在不停阶段换来换去,这就给玩家造成了一个两难的问题——如果按任务线推不得不忍受一个又一个重复度极高的地图,如果以最高效率的原则一个地点一个地点地清,又会错失现状的任务叙事,这种矛盾是稀缺的地图造成的,也是da2在叙事上的一个根本性的缺点 然后,整个战斗系统可以说在da2迎来了史诗性的大改,或许是制作组没有力气做大规模的技能,所以被官方钦定为法师的霍克技能远远没有一代多,对一个技能你要投至少两个点数进去才能强化到底,更别提一个系的被动build需要投入更多,法师的技能树相比战士盗贼完全没有优势,还有那个攻击动作,法师舞得和金箍棒似的,搞act化不能这么搞啊,怕不是设计师想起自己做《翡翠帝国》(生软以前的东方题材rpg)曾经看过的西游记,把法杖当金箍棒设计……然后是二代的刷兵机制,科克沃是个小城市,但在本作中你可以看到如同下饺子一样天降的敌人杂兵——分批次有顺序地入场,先不说不集结优势兵力在战术上有多不明智,二代的aoe法术是大削过的,我基本上要带两个输出法师才能确保范围伤害足够…… 然后是Boss战的秘之设计,堆血加流程化战斗,什么意思呢,举个例子,在最后一章有个杀龙的支线,Boss血贼厚,而且打一会它就会飞走留一堆小杂兵,自己在打不到的高台上放冷箭,有一说一,不难打,但确实恶心,我记得贴吧有个最高难度的老哥打了一小时,我估计啊,制作组对赶工做的boss没信心,所以用这种机制来给玩家提供“紧张感” 本作队友的战术槽给得更多了,这是个好事,但相应的队友的装备系统反而被砍了(武器能换)也就是当霍克捡到非自己职业的装备时,这就是垃圾,还有本作的dlc装备,又多又杂……steam上的全dlc装备过了100件,而且大多是毕业装备的水平,当然本来装备系统也没什么收集的乐趣,dlc出了应该也是破罐子破摔…… 当然成功的革新也不是没有,队友的感情线是得到了深化的,高对立和高友好都能得到buff和对应技能树,这有利于玩家不顾及队友好感度地遵循本心去做选择,也增加了build的多样性以及跨职业的连击,不过相应的礼物系统和营地闲聊也砍了……(但我个人还是更喜欢起源的策略性战斗)…… 随后的一大麻烦就是剧情,da的小格局剧情在魔幻rpg中应该算少见,虽然这种选择多半也是因为无奈,很多玩家或许是因为新奇而觉得这样的叙事很有意思,确实,不能说da2的故事无聊,但是缺点和漏洞也很明显,我们先把剧情大纲给复习一遍。 枯潮来袭,叛教法师之子霍克与家人逃难到科克沃,在一次矮人矿坑冒险中发家致富,几年后解决了库纳利人的叛乱成为捍卫者,最终面临圣法矛盾的激烈化,并在安德斯的一次恐怖袭击后解决了发布灭法师环令的圣殿骑士领导者梅疯子,圣法大战的时代就此拉开序幕。 只看大纲其实生软的编剧还是有点东西的,有转折,有历史大势,有多方势力的牵扯,看起来很好,是吧,但如果你抛开糟糕的跑任务体验去仔细审视这个故事,你就会发现很难立得住脚。 我猜想啊,14个月的工期一给,编剧拍脑子一想,咱做个小格局故事,矛盾层层激化,来点刺激的,然后开始考虑怎么让角色对号入座,为什么这么说呢,因为da2的故事是典型的情节推动型,霍克从始至终跟着情节走,不是说这么不好,不过da2处理得相对不太行,同年的巫师二也是分三章的小格局叙事,但他们着眼点是主角,杰洛特的立场很明确,找老婆顺便寻回过去记忆,政治那是附带的,他被牵着走,被逼着站队,很合理,互相利用嘛;da2有所不同,霍克从始至终都是城里有排面的人物,就是第一章也是和城里卫队小队长有裙带关系的王牌佣兵,他不能一直被动吧,你da招牌式的自由度呢? 我们来按顺序捋一下故事线,第一章用一些小任务引出了血法师与激进派圣殿骑士两大毒瘤作为引子其实还行,不过霍克听了瓦里克几句忽悠就要下坑道了略显仓促,当然瓦叔是一代口才点满那种人物,系列里忽悠谁谁信,不过下坑道不带安德斯霍克的弟弟就会死着实是个离谱的安排,奥尔加过后大家应当都知道对一个重要人物的出退场不能那么仓促,但奥尔加死的仓促是因为不这么做编不下去,da2是图什么?沃顿和队友杀了不知道多少暗裔,就没受过伤?怎么就你卡沃毒抗负数,你要说是为了霍克成长也不现实,da这种强调主角就是自己的游戏是不会有主角成长的需要的,只能说这段是真的迷惑,除了让卡沃有机会当沃顿没有任何意义 然后进入第二章,这一章的主线是库纳利人线,这段剧情其实写得不错,库纳利人的塑造很有趣,但问题在于二代本就是个内容不足的游戏,着力想展现的圣法之争和库纳利人一点关系也没有,这段想抬升霍克地位的意图实在是明显过头了,再加上一大段剧情给了库纳利人,分散了玩家注意力不说,让圣法大战本就不足的铺垫和描写雪上加霜,当然第二章也有支线,支线讲了什么呢,全讲了血法师是怎么毒害大众的,事实上本作除了第一章有几个法师卖惨,其他的戏份几乎全给了血法师以及安德斯这种激进派,这就导致了一个很搞笑的问题,你说法师不能迫害,但梅疯子一开始也没杀人,你这城市逢一个法师十有八九练血魔法不管你管谁呢?其实圣法之争的核心问题很简单——法师到底多容易堕落,在一代中一个法师用血魔法能屠大半个法环,很危险,但召唤恶魔者本来就是个危险分子,血魔法对他来说只是工具,你要说恶魔诱惑法师有多容易就很难说,同是老血法师的莫姐不就啥事没有,这个问题不挑明,法师的存废很难有定论。 我们再来说说全游戏的高潮——第三章,da2的剧情呈现一个很神奇的现象,你要说层层递进那确实是这样,但递进的未免比较太快了,纵观全游戏你基本看不到什么温和派——无论圣法,对编剧来说激进派确实好用啊,超快节奏推剧情,但对玩家就会感到憋屈。全游戏最激进的梅疯子,她疯吧,但面对霍克这个叛教法师之子,公然的血魔法使用者她一点也不刁难你,霍克还有个顶着精灵和血法师双重debuff的梅丽尔,她也不管,霍克既然这么有面子,那联合一下城里的势力反对她不难吧,结果没给选项,更神奇的是圣殿和法师还有有识之士站出来想把梅疯子杀了,这时候编剧又觉得梅疯子真被保守派刀了结局没得放了,于是让这些人绑架了霍克的家人,这也算了,真密会了还有血法师跳出来把温和派圣殿杀了,你们搞秘密集会成员审查就这水平?放进来个血法师不说还在关键时刻内讧,真的可以,事实上你在游戏里遇到的法师不是莫名其妙疯了就是几乎没有塑造,情节推着所有角色在走,再举一个例子,蕾莉安娜这种间谍头子怎么着也是雷厉风行的实战派了吧,科城的局势像在火上烤,教皇把蕾莉安娜这种重量级角色派来,你猜派来做什么,派来劝现任主教快走,那科克沃怎么办呢,蕾妹连句懂得都懂都没和霍克说 几边都这么随波逐流,主线怎么推进呢,于是安德斯直接开始搞起来恐怖袭击,不得不说这段真的是异常生硬,安德斯前几章还一副弱受的样子没一点铺垫直接搞恐怖主义了,而且搞完还一副为大义牺牲的样子,问题的根源不解决,法师永远会被歧视,这样的情节有什么意义呢,要在魔幻世界观谈政治本就是件很难圆的事情,更别提生软还处理得这么生硬 可能有人会说这样神转折也很震撼啊,但正如我之前说的,奥尔加之死也是神转折,但没有足够铺垫的生硬转折在剧本创作里肯定是要避免的,可以说二代编剧本来应该想写出霍克身为科克沃捍卫者也对历史大势卷携着无能为力的剧本,但实际效果呢,是各路代表不了大势的牛鬼蛇神作死,而我们的霍日天在一边看着准备收拾残局。 我一直坚持在文艺创作领域风格和水平要分开看,就比如我知道二代有很多拥护者,但他们可能大部分是喜欢这种以小见大的叙事风格,而不是充满漏洞的叙事水平,da2虽然我说了他的很多缺点,但生软的剧本虽然很难跻身一流,但保持二流水平还是可以的,剧情演出的信息量能淹没很多人对不合理处的关注便是明证。 Da2故事上的失败很大部分要归因于赶工和工期的匮乏,这一游戏的大部分问题皆来自于此,至于一个世界观宏大的rpg讲小格局故事是否明智,从后见之明的角度看,da2在作为da3的引子方面还算是成功的,但无可否认da2在设定上根本没什么进展,我们要知道dao在世界观构建上只是刚刚展开,还没到成熟的地步,直接在这种半成品框架下讲故事对完善世界观有所期待的玩家肯定不会满意 大部分da2的玩家应该都为这款游戏感到可惜,如果再有一年的时间可能以上的问题能解决个大半,但奈何生软摊上ea这么一个急功近利的老板,而在下一作,生软带给我的就更多是愤怒,而不是惋惜了……to be continued 以下是个人的碎碎念 一代赶路神技加速术居然砍成限时Buff了,而且这游戏强调同性恋是不是有点过了,安德斯动不动一脸弱受的样子,而且那啥院居然还有不问你性取向直接调情的男妓……这算性骚扰了吧,伊莎贝拉一代可没那么黑啊,这是在海上漂了几十年人种都换了?生软搞zzzq真的由来已久

dai

今天我们要介绍的这款游戏,于2014年以压倒性优势赢得了tga年度最佳,没有任何一个竞争者是与它同一个量级的,gta5,最后生还者为了避其锋芒不得不选择在13年发售,巫师三被吓得跳票到15年,在得知14年有这款游戏后,宫崎英高慌得只得把黑魂三继续打磨到16年,它就是古往今来最强的rpg游戏——龙腾世纪审判!!! 对审判的评价有个很神奇的现象,刚推出的年份似乎风评尚可,但随着时间推移,评价越来越差,这似乎意味着这是一款开创先河的游戏,无论是填充式的开放世界,还是泛滥的政治正确,都在这款14年的游戏中得到了体现,当然我不怀疑生软的目的,毕竟制作组高层就有同性恋,甚至现在看来惨不忍睹的开放世界当初的生软可能真的觉得很好(虽然被第二年的巫师三干碎了) 审判在我心中一直是一部很独特的作品,如果你让我说明da系列的优点,一代的优点不胜枚举,二代我至少可以说风格很独特,三代就比较神奇,它的优点,额,藏得比较深 那我们不妨就先说说它的优点,审判在世界观和时间上的推进上有巨大的建树,我的意思是,填了几个坑的同时挖了更多的坑,生软在下一盘很大的棋,无论是揭开奥莱斯的帷幕,教会的黑暗过去,亦或是把古代精灵的设定全部推倒,都能让我们感受到生软在剧本上的用心,确实,理论上讲,dai的剧情是很有看头的,但生软把自己的缺点推向台前,把优点深藏幕后,让我在玩的时候频频破防,也是真的厉害 我们还是先从系统问题说起,不知道是什么给了制作组勇气,本作的引擎换成了做战地的寒霜,这个引擎对rpg的适配性极差,为了实现存档生软就不得不对其做了大量魔改,乃至系列核心功能的存档继承还要通过一个网站实现(没有中文支持哦),不知道是不是为了照顾主机,即时演算cg还是锁30帧的,配合僵硬的人物动作,让我感觉在看ppt,审判还有一种极为奇妙的油腻效果,你要用在植被景物上我就当做油画风格了,但奈何人物也是这个样子,个个都像青春期几个月不洗脸一样满脸反光,在这里我澄清一下啊,有黑子造谣叫索拉斯“蛋头”,索拉斯什么时候配碰瓷我们鸡蛋了,你家鸡蛋反光到这种程度? 审判主打一个开放世界,什么叫开放世界呢,每个地图给你一堆无聊的收集式支线,跑断腿去吧,此外,除了某些装备词条,审判官没有任何提高那慢的像残废一样的移速的手段,偏偏生软还恶趣味地把地图做的很大,收集式支线的收集品路线拉得很长,如果不修改游戏速度,或者有什么特殊癖好我觉得是撑不下去的,顺便一提也基本没有什么像样的奖励,生软不会真的觉得这种任务能留得住玩家吧,就算14年大家还没有被育碧的填充式开放世界搞得审美疲劳,也不会对这种设计甘之若饴吧 当然了,也有人反驳,又没有强迫你做,不喜欢大可不做,首先呢,为了推主线总归是要做支线积攒势力点的,其次,这也涉及到游戏设计的一个问题,一个叙事向游戏,最根本的是什么,我认为就是像玩家提供信息,一个优秀的的叙事游戏必须在游玩过程中高密度同时高质量的提供给玩家信息,同时这个过程必须是有导向性的,要将玩家的注意力导向最能给予他们信息的方向,因此任务日志里主线永远要在c位,即使是巫师三这种支线质量领先业界的作品,也有粗制滥造纯跑腿的任务,但这些任务流程不会长,也就是,虽然提供不了什么和世界观塑造或者叙事相关的信息,但由于时间短,这段时间的信息密度并没有低到无法忍受,我们看看dai是怎么处理的,首先支线在基本没有信息量的同时,极度磨叽,当然这也就算了,毕竟不喜欢可以不玩嘛,但制作组自作聪明地把这些制作水平极度粗糙的支线,给塞在了日志里,一打开日志界面就是密密麻麻的0/X,我相信但凡是个正常人都会感到烦躁,这就是很失败的一点,它将玩家的注意力导向了最错误的方向,是个极度离谱的设计 同样是为了照顾主机,本作的技能栏进一步精简到了8个技能,8个技能,战士和盗贼都没有过这么吃紧的技能栏,你让法师玩什么?虽然是个人喜好问题,但这种革新是不是有点太过分了一点呢?说实话dai我是一点玩法师的欲望也没有,不是说强度有多少削弱,而是策略选择的灵活性没有了,说到策略,本作更迷惑的一点是取消了战术设定,可以说是向即时act全面转进,da系列每代都有极大的革新,我也不知道是图个什么,我们就当是因为商业利益不得不妥协了吧。 再说剧情和人设的问题,只看大纲,审判的剧情和一代很像,都是主角临危受命杀死大魔王拯救世界的故事,区别也是有点,审判的格局宏大的多,看得出编剧很有野心,一代的费罗登和仅仅提及过的奥莱斯都是本作的舞台,但问题在于呈现的方式,极度草率,我之前说dai是开放世界,其实这不完全准确,因为只有地图和任务是开放的,能去的地方其实就几个,而且大多是荒郊野外,根本不足以展示末日将临下两国的反应,当然生软也想了个办法,就是决策桌系统,说实话这就是个挂机文字游戏,而且频繁进出还很浪费时间,尽管事件很丰富,但寥寥几语文字提供不了多少信息量,一代通过支线我起码看出了点费罗登人应对枯潮的绝望与恐惧,审判恕我直言,完全没什么感觉,当然我不否认主线的几个大事件做的不错,但相应的小格局叙事的空缺让我感觉到这场灾难的苍白,试想一下,审判团之外判官直接接触过什么组织什么人,没几个,是吧。 再说人物,本作的大反派,考爷,不得不说异常苍白,一代的反派洛根虽然傲慢愚蠢但至少性格是有几个侧面的,考爷有什么呢,纯粹的邪恶与野心,其实这样也行,我一向认为刻画人物有两条路,一条是通过各种细节展示其多面性或者成长与突变,一种就是把一个性格特质发挥到极致,比如jojo福音的田最环,就是个坏人,但他诡计多端会演戏,文能严刑逼供心理施压,武能压着吉良和仗助打,这就是把恶这一性格写到极致,但考爷两边都不沾,风头全被我们男判官的好兄弟,女判官的好情人索光头抢走了,真的是惨。 反观入侵者dlc可以说才是真的点睛之笔,回过头来想想,几乎整个审判本体都在给这个dlc作铺垫,不得不说这个dlc确实让我感受到了生软最后的实力 再说队友,其实dai的队友一直给我一种神奇的疏离感,但本着科学严谨的态度,我思考了好一阵为什么会有这种感觉,在这里和大家分享一下 首先是身份上的疏离,一二代的队友都各有各的不同,但总归是人类,精灵,矮人三个基本分类,而且归属上都是费罗登的人,审判就比较神奇,铁牛是库纳利人,科尔是个灵体,其他队友从费罗登奥莱斯两对头,到遥不可及的德凡特,都有,当然这只是最浅显的一点,但身份的疏离明显加大了队友间的隔阂 其次,考虑一下一二代与三代主角的不同,一二代都是有所谓初始剧情的,因此他们都有自己的死忠与初始势力,一代的沃顿初始有同事A哥和受了母亲命令的莫姐两大死忠才开始招募队友的旅程,二代的霍克不仅有弟弟/妹妹还有艾芙琳的支持,更重要的是,加入的队友大部分是孤家寡人,都是孤身投奔梁山的类型,而审判就不同了,初始就有自己势力的卡姐,率部投奔的萨拉,间谍铁牛,法师领袖薇薇安,瓦里克还是霍克的死忠(十年老交情不可能完全站在判官这边)导致判官严格来说甚至没有可以信任的亲信,相反,还要应付各怀异心的队友 最后,对于角色的塑造来说,一共有三个过程,不成熟,成熟,升华,举例来说,一代鲜有不成熟的角色,成熟的利己人格莫姐最后接纳了爱情这是对其人设的升华,成熟的温奶最后决定牺牲自己造福世人,这也是一种升华,一代是不缺少有自己成熟价值观的人物的,看着傻白甜的蕾妹实际上早就身经百战了,而三代不成熟人格就多起来了,卡姐看着霸气,实际上被瓦里克骗了很久,而且天真的没有意识到圣殿骑士膨胀的权力必然导致的对法师的压迫,科尔更不必说,黑墙直到赎罪后才形成了成熟的人格 再说一些其他方面的问题,我是指,政治正确,不知何时起gayware的游戏已经成了同性恋人群的狂欢处了,在尊重同性恋的同时我能请生软尊重一下异性恋吗,队友里能推的只有卡姐?生软塑造女性角色的功底可以说在倒退了,相反的,光头倒颇有一代莫姐的风采,然后是黑人姐姐薇薇安,据我所知龙腾世纪并没有任何关于人种肤色的设定,但我们的薇薇安姐姐就这么不羁地出现在我们眼前,似乎不认为自己在满世界的白皮人中有任何特殊之处,更神奇的是这位姐姐的人设还是交际高手,我很好奇奥莱死的权贵们难道真能把薇薇安当同族看待?据我所知一个明显与交际圈所有人都不同的人,被排挤才是正常操作吧,而我们的薇薇安姐,不仅顶着异于常人的肤色,还有着其貌不扬的一张脸,能成为帝国圈内炙手可热的交际花也是相当励志了。顺便一提,有人说叠buff拿年度最佳是美末二首创,其实是dai玩剩下的,从这点看可以说是非常有创造性的一作了 总的来说,虽然定位上dai是一部中兴之作,但这部作品在最底层的设计逻辑上存在很大的问题,整个路都走错了,如果生软把做开放地图和低质量支线的精力拿来做出一代那种不乏少数有趣支线的线性地图,把决策桌换成各种小任务,那么呈现出的效果必然会好很多,同时,恼人的政治正确,油光满面的建模,浮夸的网游式特效,让审判在外观上都显得不讨喜,我由衷的希望da4里生软能认清自己,摆脱这些乱七八糟的问题。

]]>
- + 泰特斯

正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 当时开国皇帝恩西斯去世没有多久,年轻的皇帝卡奥斯也是为年轻气盛的青年,泰特斯认为这是成为皇帝亲信的好机会。

当时无权无势的人想要上位有两种办法,一是参军博得战功,二是进入帝国大学谋求文官职位,泰特斯身体虚弱,而且厌恶战争,但却有个不错的头脑,于是在他刻苦攻读下终于进入了帝国的最高学府学习数学,十年后,泰特斯已经是位小有名气的数学家了。

新帝卡奥斯是个奇怪的皇帝,他不甚喜欢锦衣玉食,也不爱美人或者诗琴书赋,唯独对数学很感兴趣,帝国的数学家往往是些老古董,唯有泰特斯名声卓著,血气方刚,二人一见如故,泰特斯如愿以偿成为皇帝的亲信。

卡奥斯将各项赋税与各种工程的设计实施交给了泰特斯,结果无不让他满意,为了表示对泰特斯的欣赏,皇帝决定将自己的妹妹嫁给他。

当公主府的使臣带着婚书拜访泰特斯时,他礼貌而不失坚决地回绝了,此时在他看来任何不懂数学之美的人都是庸俗的,除了数学女神的青睐,他对任何女人不屑一顾。

当然,这件事传到了皇帝的耳朵里,同时传导的还有群臣的议论,皇帝敏感地察觉到在大部分人眼中泰特斯才是帝国最聪明的人,心怀不满的皇帝半强迫地让公主嫁给了泰特斯。当然,皇帝并不无情,否则如果他将所有比他强的数学家都杀了,那么帝国早就没几个大数学家了——要知道他的水平只是二流的

为了自己与泰特斯的安危,贤惠的公主规劝丈夫,聪明的泰特斯恍然大悟,从此以后他收敛锋芒,沉迷于公主府奢华的生活,最终,他与公主幸福地生活到了最后。

泰特斯关于数学研究的遗著于共和历11年首次出现在公众面前,最后屡经辗转进入了共和国首都博物馆的展馆

黎明

外交官是位三十出头的年轻人(就他的职位而言),一个月前,他被尊贵的皇帝陛下召见,并被赋予和葛雷氏族谈判的任务。他精于谈判之道,自从帝国决定用经济而不是武力的手段来征服那些遮布隆(帝国语,未开化的人)他变成了谈判桌上最可怕的对手,有人说他的鹰眼能轻易看穿对手的心理底线,有人说他的眼线分布各地,实际上,在外交官的心中,他的才能无关轻重,仅仅是帝国的威亚所致罢了,在早先的黑暗岁月中,遮布隆大多被帝国的屠杀,谎言与掠夺打败。

葛雷族有着一支装备精良的武装,他们背靠大陆大方最大的矿系,然而在帝国面前,这一切毫无意义,诚然,他们完全可以炸毁矿道,但那并不能躲避他们沦为帝国仆从的命运。

当我走进葛雷族的营地时,几乎所有人都对我怒目而视,其中大多是野性,却也带着几份文明,族长是位很硬朗的老人。

“知道吗,按我们的习俗,只要学到知识,就是师徒,你毕业于帝国大学,而我读过帝国大学出版的书,所以我们应该是师兄弟”

我对这老人不合时宜的幽默搞得一点摸不清头脑,“过来,我想让你看个东西”老人领着我向营地的深处走去,在巨大的仓库群前停了下来。

当他打开大门的时候我就知道了——金子,宝石,帝国经济体系中不可或缺的存在,自此帝国历234年定下贵金属和帝国货币的兑换关系后,它们就成了帝国最坚实的支柱。

“这是祖先为我们留下的,留着我们营地的大约只有十分之一””

“你们没有告诉我们这里的矿脉有黄金和宝石?”

“我现在不是告诉你们了吗?”

“……”

“你们帝国的经济命脉就是流通在市场上的黄金吧,如果这种规模的黄金瞬间涌入你们的市场,会发生什么?”

“……”

“好了,开始谈判吧”

历时3天的谈判后,帝国开出了有史以来最宽松的条件,葛雷族的所有自治权予以保留,唯一的条件是,必须与帝国展开全方面的贸易

度量

1
只是两个小人物的故事

一般来说,这年头很难遇到算命的,至于在酒吧里看到算命的就更少见了,用算命来骗酒喝已经是不知多少年前的老故事了,然而,在此时此刻,却有两个中年男人在酒吧里对饮。

“你是刚来这座城市吗?”

“恰恰相反,我在这待了很多年了”

发问者并没有追问

“你活过3000帝国币吗?”

莫名其妙的问题,乡巴佬的叫法,发问者心想,一时间他不知对方是什么意思

“我的父亲在活到566布朗时咽了气,他本指望着活到700布朗的,呵呵,然后我就到这里来了”

和一个不知从哪个穷乡僻壤来的家伙聊天或许能让自己以后酒场吹牛添一些料,中年人想,于是他决定听下去。

“来到这里后,一时间我很不适应,你们似乎总喜欢用在时间和空间上均匀分布的事物当做度量的标准,真是奇怪”

提问者忍不住做出了回答“你是说你们甚至没有时空的概念?”

“用你们的话说,我们的时间是经济学,空间则是社会学。当然,你们的语言和概念是无法完全解释的,300克朗昭示着步入成年,数不过来的人意味着一个国家,扎在一定的一堆人意味着一个省,这只是比喻。”

他自嘲般地说“我来的时候觉得在那地方我始终是客子,来到这里后又感觉并非家乡”

窗外一只先前飞走的蝴蝶盘旋一圈后又回到了树梢。

“知道吗?你会活过394杯酒。”他没头没脑地说了一句。

另一位中年人沉默着,他每周的同一时间都会来这里点一杯酒。

“而我,会活过自己度量过的第1944位客户”

“你指望我为你的疯话付钱吗?”

”我不适应你们的语言,我也不适应你们的思维……每一秒,每一厘米对你们而言都是无法更改的,你为什么觉得作为我故乡度量——金钱是能更改的呢?对你来说这是一天,对我而言这是6帝国币,二者都是神圣不可更改的。”

中年人有些可悲地看着他“你需要去补补数学和物理的课”

“我只想知道自己该用什么来度量”他显得有些颓废。

“结账,他那杯也算我的”占卜师指着中年男人桌上的酒,向服务员喊道。

占卜师离开酒吧的背影显得并不年轻,“我是他的第几个客户?”中年男人想到。

中年人从此再也没有喝过酒,一年后,一种以果汁为主成分的硬饮料在帝国风靡一时,中年人在一次应酬中举起了一杯苹果汁,当他察觉到一丝酒味后已经晚了,作为一个厌恶半途而废的男人,他选择一饮而尽,随后咽了气。

]]>
- <h1 id="dao">dao</h1> -<p>本世纪的欧美rpg里最出名的应该是巫师三了,你可能曾因为好奇去搜过cdpr的发家史,也就是从卖盗版游戏到引进游戏并本土化赚到了第一桶金,这个引进的游戏是博德之门,博德之门的开发商是生软。 + <h2 id="泰特斯">泰特斯</h2> +<p>正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 - - - + - - +
- 迪瑞克拉世界观轶事集 - - https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E8%BD%B6%E4%BA%8B%E9%9B%86/ - 2023-09-29T02:18:45.993Z + 龙腾世纪三部曲 + + https://thinklive1.github.io/2023/09/30/%E9%BE%99%E8%85%BE%E4%B8%96%E7%BA%AA/ + 2023-09-30T11:45:00.003Z 2023-11-27T12:47:59.707Z - 泰特斯

正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 当时开国皇帝恩西斯去世没有多久,年轻的皇帝卡奥斯也是为年轻气盛的青年,泰特斯认为这是成为皇帝亲信的好机会。

当时无权无势的人想要上位有两种办法,一是参军博得战功,二是进入帝国大学谋求文官职位,泰特斯身体虚弱,而且厌恶战争,但却有个不错的头脑,于是在他刻苦攻读下终于进入了帝国的最高学府学习数学,十年后,泰特斯已经是位小有名气的数学家了。

新帝卡奥斯是个奇怪的皇帝,他不甚喜欢锦衣玉食,也不爱美人或者诗琴书赋,唯独对数学很感兴趣,帝国的数学家往往是些老古董,唯有泰特斯名声卓著,血气方刚,二人一见如故,泰特斯如愿以偿成为皇帝的亲信。

卡奥斯将各项赋税与各种工程的设计实施交给了泰特斯,结果无不让他满意,为了表示对泰特斯的欣赏,皇帝决定将自己的妹妹嫁给他。

当公主府的使臣带着婚书拜访泰特斯时,他礼貌而不失坚决地回绝了,此时在他看来任何不懂数学之美的人都是庸俗的,除了数学女神的青睐,他对任何女人不屑一顾。

当然,这件事传到了皇帝的耳朵里,同时传导的还有群臣的议论,皇帝敏感地察觉到在大部分人眼中泰特斯才是帝国最聪明的人,心怀不满的皇帝半强迫地让公主嫁给了泰特斯。当然,皇帝并不无情,否则如果他将所有比他强的数学家都杀了,那么帝国早就没几个大数学家了——要知道他的水平只是二流的

为了自己与泰特斯的安危,贤惠的公主规劝丈夫,聪明的泰特斯恍然大悟,从此以后他收敛锋芒,沉迷于公主府奢华的生活,最终,他与公主幸福地生活到了最后。

泰特斯关于数学研究的遗著于共和历11年首次出现在公众面前,最后屡经辗转进入了共和国首都博物馆的展馆

黎明

外交官是位三十出头的年轻人(就他的职位而言),一个月前,他被尊贵的皇帝陛下召见,并被赋予和葛雷氏族谈判的任务。他精于谈判之道,自从帝国决定用经济而不是武力的手段来征服那些遮布隆(帝国语,未开化的人)他变成了谈判桌上最可怕的对手,有人说他的鹰眼能轻易看穿对手的心理底线,有人说他的眼线分布各地,实际上,在外交官的心中,他的才能无关轻重,仅仅是帝国的威亚所致罢了,在早先的黑暗岁月中,遮布隆大多被帝国的屠杀,谎言与掠夺打败。

葛雷族有着一支装备精良的武装,他们背靠大陆大方最大的矿系,然而在帝国面前,这一切毫无意义,诚然,他们完全可以炸毁矿道,但那并不能躲避他们沦为帝国仆从的命运。

当我走进葛雷族的营地时,几乎所有人都对我怒目而视,其中大多是野性,却也带着几份文明,族长是位很硬朗的老人。

“知道吗,按我们的习俗,只要学到知识,就是师徒,你毕业于帝国大学,而我读过帝国大学出版的书,所以我们应该是师兄弟”

我对这老人不合时宜的幽默搞得一点摸不清头脑,“过来,我想让你看个东西”老人领着我向营地的深处走去,在巨大的仓库群前停了下来。

当他打开大门的时候我就知道了——金子,宝石,帝国经济体系中不可或缺的存在,自此帝国历234年定下贵金属和帝国货币的兑换关系后,它们就成了帝国最坚实的支柱。

“这是祖先为我们留下的,留着我们营地的大约只有十分之一””

“你们没有告诉我们这里的矿脉有黄金和宝石?”

“我现在不是告诉你们了吗?”

“……”

“你们帝国的经济命脉就是流通在市场上的黄金吧,如果这种规模的黄金瞬间涌入你们的市场,会发生什么?”

“……”

“好了,开始谈判吧”

历时3天的谈判后,帝国开出了有史以来最宽松的条件,葛雷族的所有自治权予以保留,唯一的条件是,必须与帝国展开全方面的贸易

度量

1
只是两个小人物的故事

一般来说,这年头很难遇到算命的,至于在酒吧里看到算命的就更少见了,用算命来骗酒喝已经是不知多少年前的老故事了,然而,在此时此刻,却有两个中年男人在酒吧里对饮。

“你是刚来这座城市吗?”

“恰恰相反,我在这待了很多年了”

发问者并没有追问

“你活过3000帝国币吗?”

莫名其妙的问题,乡巴佬的叫法,发问者心想,一时间他不知对方是什么意思

“我的父亲在活到566布朗时咽了气,他本指望着活到700布朗的,呵呵,然后我就到这里来了”

和一个不知从哪个穷乡僻壤来的家伙聊天或许能让自己以后酒场吹牛添一些料,中年人想,于是他决定听下去。

“来到这里后,一时间我很不适应,你们似乎总喜欢用在时间和空间上均匀分布的事物当做度量的标准,真是奇怪”

提问者忍不住做出了回答“你是说你们甚至没有时空的概念?”

“用你们的话说,我们的时间是经济学,空间则是社会学。当然,你们的语言和概念是无法完全解释的,300克朗昭示着步入成年,数不过来的人意味着一个国家,扎在一定的一堆人意味着一个省,这只是比喻。”

他自嘲般地说“我来的时候觉得在那地方我始终是客子,来到这里后又感觉并非家乡”

窗外一只先前飞走的蝴蝶盘旋一圈后又回到了树梢。

“知道吗?你会活过394杯酒。”他没头没脑地说了一句。

另一位中年人沉默着,他每周的同一时间都会来这里点一杯酒。

“而我,会活过自己度量过的第1944位客户”

“你指望我为你的疯话付钱吗?”

”我不适应你们的语言,我也不适应你们的思维……每一秒,每一厘米对你们而言都是无法更改的,你为什么觉得作为我故乡度量——金钱是能更改的呢?对你来说这是一天,对我而言这是6帝国币,二者都是神圣不可更改的。”

中年人有些可悲地看着他“你需要去补补数学和物理的课”

“我只想知道自己该用什么来度量”他显得有些颓废。

“结账,他那杯也算我的”占卜师指着中年男人桌上的酒,向服务员喊道。

占卜师离开酒吧的背影显得并不年轻,“我是他的第几个客户?”中年男人想到。

中年人从此再也没有喝过酒,一年后,一种以果汁为主成分的硬饮料在帝国风靡一时,中年人在一次应酬中举起了一杯苹果汁,当他察觉到一丝酒味后已经晚了,作为一个厌恶半途而废的男人,他选择一饮而尽,随后咽了气。

]]>
+ dao

本世纪的欧美rpg里最出名的应该是巫师三了,你可能曾因为好奇去搜过cdpr的发家史,也就是从卖盗版游戏到引进游戏并本土化赚到了第一桶金,这个引进的游戏是博德之门,博德之门的开发商是生软。 这里插一句,波兰人的首秀巫师一在开发阶段几乎遇到了一个新游戏能想到的所有问题,这时生软仗义地扶了波兰人一把,才有了巫师一的面世,遂成rpg界一段佳话,不过后来二者先后拉了( 龙腾世纪本来在定位上是博德之门的替代品,因为版权问题生软不能继续开发博德之门,于是便做出了龙腾世纪起源,这一项目立项在02年,但直到07年得到了EA的支持才在09年把这一“神作”做了出来,直到这时EA还是带善人的形象,并没有露出狰狞的獠牙,而在生软的黄金时代打磨了7年的起源,我可以毫不夸张地说,哪怕今年推出这款游戏,它依然是年度最佳候选级别的神作。 我先说说,我为什么要做这个视频,其实在一开始,dao在我的心中的地位还没有要我做一个视频出来的程度,但在玩了龙腾世纪的后两作后,DAO在我心中地位飙升,可见对比的力量,这个杂谈系列会讲完我对龙腾世纪整个系列的感受,当然是纯个人感受,我不 是什么rpg遗老,只是一个当代rpg爱好者而已,如有不同意之处,反正我也不会改的。

当你打开dao建立存档时,你可以选择三个种族,三个职业,在种族内甚至有平民和贵族的区别,根据职业和种族的不同,光开头剧情就有六种,由此开始,玩家就能感受到dao的超高自由度。 当然,对于rpg来说,自由度并不是什么稀奇的东西,但dao的自由度是有其独特之处的,以自由度出名的上古卷轴五,它的自由度体现于扮演的角色的多样性,龙裔,战友团成员,冬堡法师等等,这几种身份并没有交集,是独立的,而起源的自由度体现在行为的自由,自由度再高的游戏也不能完全模拟现实,但高自由度的游戏只需要模拟到玩家一时间能想到或者能让他们觉得有趣的所有选项就够了,DAO做到了这点,举例来说,当你接到了调查黑恶势力的任务,你可以当个正义的使者把邪恶势力端了,也可以接受贿赂,甚至可以献祭奴隶来提高自己的力量,你可以与邪教合作玷污圣物,也可以屠杀邪教,杀死恶龙,扮演被选召的勇士,很多时候当你背叛道德时得到的奖励反而更好,高道德的行为除了增加部分队友的好感度并没有太多作用,与巫师类似,起源遵循着成人的价值观,尽管选择大部分时候不像巫师那么残酷,而且起源中后悔也是很容易的一件事,相对削弱了选择的分量。

我们再来说说提高起源代入感的另一个设计——队友系统,独身在一个苍茫浩瀚的魔幻世界冒险难免会感到孤独,巫师的解决方式是让杰洛特和爱人与亲友保持时不时的联系,上古卷轴的解决方式,嗯,我没感到有什么解决方式,至少本体没有,当然如果装了随从mod肯定就完全不一样了。在龙腾世纪起源中你绝不会感到孤独,相比其他知名rpg,生软最显著的优点应该就是队友塑造了,dao的队友大部分有着讨喜且有深度的人设,这是由海量的工作量撑起来的,在冒险时会随机出现队友间的闲聊,几乎所有队友两两组合都有为数不少的对话,或八卦,或正经或取笑,这让人感到队友都是活生生的人,同时也可想而知其中的工作量,单个角色的对话文字量往往都要以万为单位,此外,在营地和队友闲聊也能通过一些选项增减好感度,所有队友都有为数不少的对话树,并且随着好感度的增减还会解锁额外选项。 队友间除了友情也能发展出爱情,这就不得不提我认为在魔幻rpg中最有魅力的女角色——莫瑞甘,她是个荒野女巫的女儿,,价值观完全是混乱中立甚至偏邪恶的,你做好事她嫌你磨叽,做坏事说不定夸你有魄力,好感度低时会邀请你滚床单并声明只是玩玩,好感度高起来了反而不愿继续亲近——“明明说了只是玩玩,怎么你当真了呢”在游戏的结局莫瑞甘会不可避免地离去,而在一个(拿感情骗钱的)的dlc里沃顿却能不远万里追踪到正欲逃走的她,最终让莫瑞甘也承认了爱情的存在,不得不说我真被这段爱情所感动了,这种细腻的感情戏其实不输我们以感情线为特色的双剑系列(当然续作就没这么顶了) 代入感之外,起源的战斗系统也是极有意思的,多有意思呢,大概比巫师三好几十个上古卷轴五吧(不是)起源的系统在今天看也不算过时,采用一种可以随时暂停的即时战斗系统,同时可以为队友ai设置战术,选项极为详细,大佬光靠设置ai应该就可以全自动战斗,我这种咸鱼打boss还是要几步一暂停,很明显这是一种重策略轻即时的系统,不设技能栏上限让法师成为了团队灵魂,控制,辅助,aoe,单体爆发应有尽有,可以说带够蓝药,法师就是无敌的(大部分Boss远程攻击弱于近战),即便职业平衡不是那么好,但队友是可以随意搭配的,丰富的技能树,转职,加点策略,装备系统让起源的战斗和养成充满乐趣,当然大型迷宫各种怪潮难免会腻烦,不过比起后面两作真的是让我体验最好的战斗系统了。 最后我们来说说起源的剧情和任务设计,大恶魔苏醒,黑潮突起,作为临危受命的灰袍守护者,沃顿利用古老盟约集结联军,手刃大恶魔,可以说是一个很俗套的故事,怎么把这种看起来很俗的故事讲好呢,答案是独立的小故事相加辅以大量填充细节和设定,起源的几条线,法师,矮人,精灵,伯爵都是相对独立的故事,套路很简单:求援——当地陷入危机——解决危机——得到援助,期间夹杂背叛者洛根使绊的故事线,每个地方引出了一部分的世界观设定,起源有着极其繁杂的文本,尽管套路类似,但每条线提供的信息量都是复杂且独特的,同时也有着世界观内各个势力特有的风貌,安教的圣洁,矮人的森严都得到了体现,即使很想比较,龙腾世纪的世界观也是独特且复杂的,当然,相比起源的主线,支线反而比较一般,不乏收集的填充式支线,当然,队友的支线还是很有趣的,也有一些补充世界观的有趣支线。 说了这么多,应该基本说完了起源的特点,当然也有很多具体内容我并没有提及,事实上起源并不是没有缺点,比如优化太差,自带防沉迷,玩几个小时就会卡顿到没完继续,只能重启,此外,敌人种类稀缺,也存在强行推动剧情而忽略合理性的情节,甚至有手刃大恶魔实力的主角有的时候莫名其妙就当垫脚石了,但起源仍然是神作,作为一个玩惯了10年后游戏的人,我玩起源没有感到任何系统在恶心我,可见制作组对玩家体验的重视,这是龙腾世纪的续作都未能做到的,,这也是我为龙腾世纪和生软感到可惜的原因,下一期我会叙述我对两部续作的看法,当然批评为主,,, 出道即巅峰的起源全平台销量不过470w,或许正是这样的销量驱使着生软不惜与老玩家对立也要向着主机倾斜,只可惜了龙腾世纪成为了开幕即巅峰,出场即绝唱的一个悲剧……

da2

今天我们来说说龙腾世纪二,,龙腾世纪二是系列中一部很,额,很独特的作品,他刚发售时的风评,作为后来人我不是很清楚,不过就现在来看,da2的风评呈现一种两极分化的形势。 这里插一句奥,我个人感觉rpg游戏的受众是个很宽容的群体,我这种认为2077是款好游戏的人放一些地方可能被叫孝子了,但对现在龙腾世纪的粉丝来说这可能都不算事,举个例子吧,写文案的这天龙腾世纪吧有个直接辱骂起源人气角色的,甚至没什么人骂回去,这放在其他单机游戏圈子里是难以想象的,所以对于龙腾世纪二这样极其赶工的,大部分玩家评价起来基本没什么戾气,当然事实上我很喜欢这一点,也是这点造成了da2并没有招致较为深入的批评,今天我会详细地阐述这部作品的缺点,当然是以我的角度,同时我也不会带有什么负面情绪,我个人其实很喜欢这个系列,二代我也不是那么讨厌,但它的问题确实是露骨的,毕竟太温和往往就意味着圈子的自净能力不够,对一些问题往往就不能看的那么透彻。 我之前说了da2是一部赶工明显的作品,有多赶工呢,2077和它相比那都不算事,生软甚至没有给二代一个后缀名…… 我们先从系统性的问题说起 首先作为一个rpg游戏,da2从头到尾(一共三章)几乎一直在重复利用十几个地图,一样的别墅,一样的山洞(还Tm贼亮)等等,这也是所有玩家都承认的一个问题,考虑到14个月的工期,这点可能也是难以避免的,不过这个问题实际上并不止这么简单,因为地图的数量太少,各种任务线又要在不停阶段换来换去,这就给玩家造成了一个两难的问题——如果按任务线推不得不忍受一个又一个重复度极高的地图,如果以最高效率的原则一个地点一个地点地清,又会错失现状的任务叙事,这种矛盾是稀缺的地图造成的,也是da2在叙事上的一个根本性的缺点 然后,整个战斗系统可以说在da2迎来了史诗性的大改,或许是制作组没有力气做大规模的技能,所以被官方钦定为法师的霍克技能远远没有一代多,对一个技能你要投至少两个点数进去才能强化到底,更别提一个系的被动build需要投入更多,法师的技能树相比战士盗贼完全没有优势,还有那个攻击动作,法师舞得和金箍棒似的,搞act化不能这么搞啊,怕不是设计师想起自己做《翡翠帝国》(生软以前的东方题材rpg)曾经看过的西游记,把法杖当金箍棒设计……然后是二代的刷兵机制,科克沃是个小城市,但在本作中你可以看到如同下饺子一样天降的敌人杂兵——分批次有顺序地入场,先不说不集结优势兵力在战术上有多不明智,二代的aoe法术是大削过的,我基本上要带两个输出法师才能确保范围伤害足够…… 然后是Boss战的秘之设计,堆血加流程化战斗,什么意思呢,举个例子,在最后一章有个杀龙的支线,Boss血贼厚,而且打一会它就会飞走留一堆小杂兵,自己在打不到的高台上放冷箭,有一说一,不难打,但确实恶心,我记得贴吧有个最高难度的老哥打了一小时,我估计啊,制作组对赶工做的boss没信心,所以用这种机制来给玩家提供“紧张感” 本作队友的战术槽给得更多了,这是个好事,但相应的队友的装备系统反而被砍了(武器能换)也就是当霍克捡到非自己职业的装备时,这就是垃圾,还有本作的dlc装备,又多又杂……steam上的全dlc装备过了100件,而且大多是毕业装备的水平,当然本来装备系统也没什么收集的乐趣,dlc出了应该也是破罐子破摔…… 当然成功的革新也不是没有,队友的感情线是得到了深化的,高对立和高友好都能得到buff和对应技能树,这有利于玩家不顾及队友好感度地遵循本心去做选择,也增加了build的多样性以及跨职业的连击,不过相应的礼物系统和营地闲聊也砍了……(但我个人还是更喜欢起源的策略性战斗)…… 随后的一大麻烦就是剧情,da的小格局剧情在魔幻rpg中应该算少见,虽然这种选择多半也是因为无奈,很多玩家或许是因为新奇而觉得这样的叙事很有意思,确实,不能说da2的故事无聊,但是缺点和漏洞也很明显,我们先把剧情大纲给复习一遍。 枯潮来袭,叛教法师之子霍克与家人逃难到科克沃,在一次矮人矿坑冒险中发家致富,几年后解决了库纳利人的叛乱成为捍卫者,最终面临圣法矛盾的激烈化,并在安德斯的一次恐怖袭击后解决了发布灭法师环令的圣殿骑士领导者梅疯子,圣法大战的时代就此拉开序幕。 只看大纲其实生软的编剧还是有点东西的,有转折,有历史大势,有多方势力的牵扯,看起来很好,是吧,但如果你抛开糟糕的跑任务体验去仔细审视这个故事,你就会发现很难立得住脚。 我猜想啊,14个月的工期一给,编剧拍脑子一想,咱做个小格局故事,矛盾层层激化,来点刺激的,然后开始考虑怎么让角色对号入座,为什么这么说呢,因为da2的故事是典型的情节推动型,霍克从始至终跟着情节走,不是说这么不好,不过da2处理得相对不太行,同年的巫师二也是分三章的小格局叙事,但他们着眼点是主角,杰洛特的立场很明确,找老婆顺便寻回过去记忆,政治那是附带的,他被牵着走,被逼着站队,很合理,互相利用嘛;da2有所不同,霍克从始至终都是城里有排面的人物,就是第一章也是和城里卫队小队长有裙带关系的王牌佣兵,他不能一直被动吧,你da招牌式的自由度呢? 我们来按顺序捋一下故事线,第一章用一些小任务引出了血法师与激进派圣殿骑士两大毒瘤作为引子其实还行,不过霍克听了瓦里克几句忽悠就要下坑道了略显仓促,当然瓦叔是一代口才点满那种人物,系列里忽悠谁谁信,不过下坑道不带安德斯霍克的弟弟就会死着实是个离谱的安排,奥尔加过后大家应当都知道对一个重要人物的出退场不能那么仓促,但奥尔加死的仓促是因为不这么做编不下去,da2是图什么?沃顿和队友杀了不知道多少暗裔,就没受过伤?怎么就你卡沃毒抗负数,你要说是为了霍克成长也不现实,da这种强调主角就是自己的游戏是不会有主角成长的需要的,只能说这段是真的迷惑,除了让卡沃有机会当沃顿没有任何意义 然后进入第二章,这一章的主线是库纳利人线,这段剧情其实写得不错,库纳利人的塑造很有趣,但问题在于二代本就是个内容不足的游戏,着力想展现的圣法之争和库纳利人一点关系也没有,这段想抬升霍克地位的意图实在是明显过头了,再加上一大段剧情给了库纳利人,分散了玩家注意力不说,让圣法大战本就不足的铺垫和描写雪上加霜,当然第二章也有支线,支线讲了什么呢,全讲了血法师是怎么毒害大众的,事实上本作除了第一章有几个法师卖惨,其他的戏份几乎全给了血法师以及安德斯这种激进派,这就导致了一个很搞笑的问题,你说法师不能迫害,但梅疯子一开始也没杀人,你这城市逢一个法师十有八九练血魔法不管你管谁呢?其实圣法之争的核心问题很简单——法师到底多容易堕落,在一代中一个法师用血魔法能屠大半个法环,很危险,但召唤恶魔者本来就是个危险分子,血魔法对他来说只是工具,你要说恶魔诱惑法师有多容易就很难说,同是老血法师的莫姐不就啥事没有,这个问题不挑明,法师的存废很难有定论。 我们再来说说全游戏的高潮——第三章,da2的剧情呈现一个很神奇的现象,你要说层层递进那确实是这样,但递进的未免比较太快了,纵观全游戏你基本看不到什么温和派——无论圣法,对编剧来说激进派确实好用啊,超快节奏推剧情,但对玩家就会感到憋屈。全游戏最激进的梅疯子,她疯吧,但面对霍克这个叛教法师之子,公然的血魔法使用者她一点也不刁难你,霍克还有个顶着精灵和血法师双重debuff的梅丽尔,她也不管,霍克既然这么有面子,那联合一下城里的势力反对她不难吧,结果没给选项,更神奇的是圣殿和法师还有有识之士站出来想把梅疯子杀了,这时候编剧又觉得梅疯子真被保守派刀了结局没得放了,于是让这些人绑架了霍克的家人,这也算了,真密会了还有血法师跳出来把温和派圣殿杀了,你们搞秘密集会成员审查就这水平?放进来个血法师不说还在关键时刻内讧,真的可以,事实上你在游戏里遇到的法师不是莫名其妙疯了就是几乎没有塑造,情节推着所有角色在走,再举一个例子,蕾莉安娜这种间谍头子怎么着也是雷厉风行的实战派了吧,科城的局势像在火上烤,教皇把蕾莉安娜这种重量级角色派来,你猜派来做什么,派来劝现任主教快走,那科克沃怎么办呢,蕾妹连句懂得都懂都没和霍克说 几边都这么随波逐流,主线怎么推进呢,于是安德斯直接开始搞起来恐怖袭击,不得不说这段真的是异常生硬,安德斯前几章还一副弱受的样子没一点铺垫直接搞恐怖主义了,而且搞完还一副为大义牺牲的样子,问题的根源不解决,法师永远会被歧视,这样的情节有什么意义呢,要在魔幻世界观谈政治本就是件很难圆的事情,更别提生软还处理得这么生硬 可能有人会说这样神转折也很震撼啊,但正如我之前说的,奥尔加之死也是神转折,但没有足够铺垫的生硬转折在剧本创作里肯定是要避免的,可以说二代编剧本来应该想写出霍克身为科克沃捍卫者也对历史大势卷携着无能为力的剧本,但实际效果呢,是各路代表不了大势的牛鬼蛇神作死,而我们的霍日天在一边看着准备收拾残局。 我一直坚持在文艺创作领域风格和水平要分开看,就比如我知道二代有很多拥护者,但他们可能大部分是喜欢这种以小见大的叙事风格,而不是充满漏洞的叙事水平,da2虽然我说了他的很多缺点,但生软的剧本虽然很难跻身一流,但保持二流水平还是可以的,剧情演出的信息量能淹没很多人对不合理处的关注便是明证。 Da2故事上的失败很大部分要归因于赶工和工期的匮乏,这一游戏的大部分问题皆来自于此,至于一个世界观宏大的rpg讲小格局故事是否明智,从后见之明的角度看,da2在作为da3的引子方面还算是成功的,但无可否认da2在设定上根本没什么进展,我们要知道dao在世界观构建上只是刚刚展开,还没到成熟的地步,直接在这种半成品框架下讲故事对完善世界观有所期待的玩家肯定不会满意 大部分da2的玩家应该都为这款游戏感到可惜,如果再有一年的时间可能以上的问题能解决个大半,但奈何生软摊上ea这么一个急功近利的老板,而在下一作,生软带给我的就更多是愤怒,而不是惋惜了……to be continued 以下是个人的碎碎念 一代赶路神技加速术居然砍成限时Buff了,而且这游戏强调同性恋是不是有点过了,安德斯动不动一脸弱受的样子,而且那啥院居然还有不问你性取向直接调情的男妓……这算性骚扰了吧,伊莎贝拉一代可没那么黑啊,这是在海上漂了几十年人种都换了?生软搞zzzq真的由来已久

dai

今天我们要介绍的这款游戏,于2014年以压倒性优势赢得了tga年度最佳,没有任何一个竞争者是与它同一个量级的,gta5,最后生还者为了避其锋芒不得不选择在13年发售,巫师三被吓得跳票到15年,在得知14年有这款游戏后,宫崎英高慌得只得把黑魂三继续打磨到16年,它就是古往今来最强的rpg游戏——龙腾世纪审判!!! 对审判的评价有个很神奇的现象,刚推出的年份似乎风评尚可,但随着时间推移,评价越来越差,这似乎意味着这是一款开创先河的游戏,无论是填充式的开放世界,还是泛滥的政治正确,都在这款14年的游戏中得到了体现,当然我不怀疑生软的目的,毕竟制作组高层就有同性恋,甚至现在看来惨不忍睹的开放世界当初的生软可能真的觉得很好(虽然被第二年的巫师三干碎了) 审判在我心中一直是一部很独特的作品,如果你让我说明da系列的优点,一代的优点不胜枚举,二代我至少可以说风格很独特,三代就比较神奇,它的优点,额,藏得比较深 那我们不妨就先说说它的优点,审判在世界观和时间上的推进上有巨大的建树,我的意思是,填了几个坑的同时挖了更多的坑,生软在下一盘很大的棋,无论是揭开奥莱斯的帷幕,教会的黑暗过去,亦或是把古代精灵的设定全部推倒,都能让我们感受到生软在剧本上的用心,确实,理论上讲,dai的剧情是很有看头的,但生软把自己的缺点推向台前,把优点深藏幕后,让我在玩的时候频频破防,也是真的厉害 我们还是先从系统问题说起,不知道是什么给了制作组勇气,本作的引擎换成了做战地的寒霜,这个引擎对rpg的适配性极差,为了实现存档生软就不得不对其做了大量魔改,乃至系列核心功能的存档继承还要通过一个网站实现(没有中文支持哦),不知道是不是为了照顾主机,即时演算cg还是锁30帧的,配合僵硬的人物动作,让我感觉在看ppt,审判还有一种极为奇妙的油腻效果,你要用在植被景物上我就当做油画风格了,但奈何人物也是这个样子,个个都像青春期几个月不洗脸一样满脸反光,在这里我澄清一下啊,有黑子造谣叫索拉斯“蛋头”,索拉斯什么时候配碰瓷我们鸡蛋了,你家鸡蛋反光到这种程度? 审判主打一个开放世界,什么叫开放世界呢,每个地图给你一堆无聊的收集式支线,跑断腿去吧,此外,除了某些装备词条,审判官没有任何提高那慢的像残废一样的移速的手段,偏偏生软还恶趣味地把地图做的很大,收集式支线的收集品路线拉得很长,如果不修改游戏速度,或者有什么特殊癖好我觉得是撑不下去的,顺便一提也基本没有什么像样的奖励,生软不会真的觉得这种任务能留得住玩家吧,就算14年大家还没有被育碧的填充式开放世界搞得审美疲劳,也不会对这种设计甘之若饴吧 当然了,也有人反驳,又没有强迫你做,不喜欢大可不做,首先呢,为了推主线总归是要做支线积攒势力点的,其次,这也涉及到游戏设计的一个问题,一个叙事向游戏,最根本的是什么,我认为就是像玩家提供信息,一个优秀的的叙事游戏必须在游玩过程中高密度同时高质量的提供给玩家信息,同时这个过程必须是有导向性的,要将玩家的注意力导向最能给予他们信息的方向,因此任务日志里主线永远要在c位,即使是巫师三这种支线质量领先业界的作品,也有粗制滥造纯跑腿的任务,但这些任务流程不会长,也就是,虽然提供不了什么和世界观塑造或者叙事相关的信息,但由于时间短,这段时间的信息密度并没有低到无法忍受,我们看看dai是怎么处理的,首先支线在基本没有信息量的同时,极度磨叽,当然这也就算了,毕竟不喜欢可以不玩嘛,但制作组自作聪明地把这些制作水平极度粗糙的支线,给塞在了日志里,一打开日志界面就是密密麻麻的0/X,我相信但凡是个正常人都会感到烦躁,这就是很失败的一点,它将玩家的注意力导向了最错误的方向,是个极度离谱的设计 同样是为了照顾主机,本作的技能栏进一步精简到了8个技能,8个技能,战士和盗贼都没有过这么吃紧的技能栏,你让法师玩什么?虽然是个人喜好问题,但这种革新是不是有点太过分了一点呢?说实话dai我是一点玩法师的欲望也没有,不是说强度有多少削弱,而是策略选择的灵活性没有了,说到策略,本作更迷惑的一点是取消了战术设定,可以说是向即时act全面转进,da系列每代都有极大的革新,我也不知道是图个什么,我们就当是因为商业利益不得不妥协了吧。 再说剧情和人设的问题,只看大纲,审判的剧情和一代很像,都是主角临危受命杀死大魔王拯救世界的故事,区别也是有点,审判的格局宏大的多,看得出编剧很有野心,一代的费罗登和仅仅提及过的奥莱斯都是本作的舞台,但问题在于呈现的方式,极度草率,我之前说dai是开放世界,其实这不完全准确,因为只有地图和任务是开放的,能去的地方其实就几个,而且大多是荒郊野外,根本不足以展示末日将临下两国的反应,当然生软也想了个办法,就是决策桌系统,说实话这就是个挂机文字游戏,而且频繁进出还很浪费时间,尽管事件很丰富,但寥寥几语文字提供不了多少信息量,一代通过支线我起码看出了点费罗登人应对枯潮的绝望与恐惧,审判恕我直言,完全没什么感觉,当然我不否认主线的几个大事件做的不错,但相应的小格局叙事的空缺让我感觉到这场灾难的苍白,试想一下,审判团之外判官直接接触过什么组织什么人,没几个,是吧。 再说人物,本作的大反派,考爷,不得不说异常苍白,一代的反派洛根虽然傲慢愚蠢但至少性格是有几个侧面的,考爷有什么呢,纯粹的邪恶与野心,其实这样也行,我一向认为刻画人物有两条路,一条是通过各种细节展示其多面性或者成长与突变,一种就是把一个性格特质发挥到极致,比如jojo福音的田最环,就是个坏人,但他诡计多端会演戏,文能严刑逼供心理施压,武能压着吉良和仗助打,这就是把恶这一性格写到极致,但考爷两边都不沾,风头全被我们男判官的好兄弟,女判官的好情人索光头抢走了,真的是惨。 反观入侵者dlc可以说才是真的点睛之笔,回过头来想想,几乎整个审判本体都在给这个dlc作铺垫,不得不说这个dlc确实让我感受到了生软最后的实力 再说队友,其实dai的队友一直给我一种神奇的疏离感,但本着科学严谨的态度,我思考了好一阵为什么会有这种感觉,在这里和大家分享一下 首先是身份上的疏离,一二代的队友都各有各的不同,但总归是人类,精灵,矮人三个基本分类,而且归属上都是费罗登的人,审判就比较神奇,铁牛是库纳利人,科尔是个灵体,其他队友从费罗登奥莱斯两对头,到遥不可及的德凡特,都有,当然这只是最浅显的一点,但身份的疏离明显加大了队友间的隔阂 其次,考虑一下一二代与三代主角的不同,一二代都是有所谓初始剧情的,因此他们都有自己的死忠与初始势力,一代的沃顿初始有同事A哥和受了母亲命令的莫姐两大死忠才开始招募队友的旅程,二代的霍克不仅有弟弟/妹妹还有艾芙琳的支持,更重要的是,加入的队友大部分是孤家寡人,都是孤身投奔梁山的类型,而审判就不同了,初始就有自己势力的卡姐,率部投奔的萨拉,间谍铁牛,法师领袖薇薇安,瓦里克还是霍克的死忠(十年老交情不可能完全站在判官这边)导致判官严格来说甚至没有可以信任的亲信,相反,还要应付各怀异心的队友 最后,对于角色的塑造来说,一共有三个过程,不成熟,成熟,升华,举例来说,一代鲜有不成熟的角色,成熟的利己人格莫姐最后接纳了爱情这是对其人设的升华,成熟的温奶最后决定牺牲自己造福世人,这也是一种升华,一代是不缺少有自己成熟价值观的人物的,看着傻白甜的蕾妹实际上早就身经百战了,而三代不成熟人格就多起来了,卡姐看着霸气,实际上被瓦里克骗了很久,而且天真的没有意识到圣殿骑士膨胀的权力必然导致的对法师的压迫,科尔更不必说,黑墙直到赎罪后才形成了成熟的人格 再说一些其他方面的问题,我是指,政治正确,不知何时起gayware的游戏已经成了同性恋人群的狂欢处了,在尊重同性恋的同时我能请生软尊重一下异性恋吗,队友里能推的只有卡姐?生软塑造女性角色的功底可以说在倒退了,相反的,光头倒颇有一代莫姐的风采,然后是黑人姐姐薇薇安,据我所知龙腾世纪并没有任何关于人种肤色的设定,但我们的薇薇安姐姐就这么不羁地出现在我们眼前,似乎不认为自己在满世界的白皮人中有任何特殊之处,更神奇的是这位姐姐的人设还是交际高手,我很好奇奥莱死的权贵们难道真能把薇薇安当同族看待?据我所知一个明显与交际圈所有人都不同的人,被排挤才是正常操作吧,而我们的薇薇安姐,不仅顶着异于常人的肤色,还有着其貌不扬的一张脸,能成为帝国圈内炙手可热的交际花也是相当励志了。顺便一提,有人说叠buff拿年度最佳是美末二首创,其实是dai玩剩下的,从这点看可以说是非常有创造性的一作了 总的来说,虽然定位上dai是一部中兴之作,但这部作品在最底层的设计逻辑上存在很大的问题,整个路都走错了,如果生软把做开放地图和低质量支线的精力拿来做出一代那种不乏少数有趣支线的线性地图,把决策桌换成各种小任务,那么呈现出的效果必然会好很多,同时,恼人的政治正确,油光满面的建模,浮夸的网游式特效,让审判在外观上都显得不讨喜,我由衷的希望da4里生软能认清自己,摆脱这些乱七八糟的问题。

]]>
- <h2 id="泰特斯">泰特斯</h2> -<p>正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 + <h1 id="dao">dao</h1> +<p>本世纪的欧美rpg里最出名的应该是巫师三了,你可能曾因为好奇去搜过cdpr的发家史,也就是从卖盗版游戏到引进游戏并本土化赚到了第一桶金,这个引进的游戏是博德之门,博德之门的开发商是生软。 - + + - + + + +
@@ -770,54 +771,54 @@ - 基于恐龙书和苏大ppt的操作系统笔记 - - https://thinklive1.github.io/2023/09/29/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ - 2023-09-29T02:18:45.993Z + 影子工厂 + + https://thinklive1.github.io/2023/09/30/%E5%BD%B1%E5%AD%90%E5%B7%A5%E5%8E%82/ + 2023-09-30T11:38:04.163Z 2023-11-27T12:47:59.697Z -
1
2
3
4
5
6
7
8
9
10
11
12
13
计算机系统可以分为四个部分
硬件(Hardware) – 提供基本的计算资源
CPU, memory, I/O devices
操作系统(Operating System)
控制和协调各用户的应用程序对硬件的使用
应用程序(Application programs) – 规定了用户按何种方式使用系统资源
字处理程序, 编译器, 网络浏览器, 数据库系统, 视频游戏
用户(Users)
人, 机器, 其他计算机
操作系统的目标:
运行用户程序  ---核心目标
更方便使用计算机 ---面向用户
更高效使用计算机 ---面向系统

计算机启动时,会启动引导程序,来初始化系统的各个组件,加载操作系统并开始执行 操作系统加载到内存后,开始为系统和用户提供服务,成为系统进程或者后台程序该阶段完成后系统完全启动并且等待事件发生。 事件发生通过”中断“机制来通知,cpu被中断时,停止正在做的事,并立即转到固定位置继续执行中断服务程序,执行完后继续执行被中断的计算

1
在冯·诺依曼体系结构( von Neumann architecture)上执行时,一个典型的指令执行周期是,首先从内存中获取指令,并存到指令寄存器( instruction register)。接着,该指令被解码,也可能会从内存中获取操作数据并且存到内部寄存器。在指令完成对操作数据的执行后,结果也可存到内存。注意:内存单元只能看到内存地址的流,而并不知道它们如何产生(通过指令计数器、索引、间接、常量地址或其他方式)或它们是什么样(指令或数据)的地址。相应地,我们可以忽略程序如何产生内存地址,而只关注由程序运行所生成的地址序列。

集群系统

由两个或多个独立的系统耦合起来 共享数据 storage-area network (SAN)。 提供高可用性。 ›一定的冗余 非对称集群(Asymmetric Clustering):一台机器运行应用程序,而其他机器处于热备份模式。 对称集群(Symmetric Clustering):多个主机都运行应用程序 提供high-performance computing (HPC) 用专门的应用程序利用集群,并行计算parallelization

1
2
3
4
多道程序设计:在内存中同时存在多道作业,在管理程序控制下相互穿插运行
通过作业调度(Job Scheduling)选中一个作业并运行
当该作业必须等待时 (如等待I/O), 切换到另一个作业
目的:提高CPU的利用率,充分发挥计算机系统部件的并行性

分时系统:控制响应时间较短,使计算机可交互,›一般采用时间片轮转方式使一台计算机为多个用户服务 并行:两个或者多个作业在同一时刻运行 并发:两个或多个作业在同一时间间隔内依次运行 双重模式:允许OS保护自身和其他系统部件 用户模式(user mode)和内核模式(kernel mode),由硬件提供模式位 特权指令:可能引起系统崩溃的指令,只能运行在内核模式

1
2
3
4
5
6
如果操作系统不能获得CPU控制权,就无法管理系统
eg.用户程序死循环,用户程序不调用系统调用
解决方法:定时器
在一段时间后发生中断,CPU控制权返回操作系统
固定时间和可变时间定时器
利用时钟和计数器实现

I/O保护 防止用户程序执行非法I/O 解决方法:所有I/O指令都是特权指令 用户程序通过系统调用进行I/O操作 内存保护 防止内存非法访问 解决方法:存储保护机制 硬件支持 程序运行必须的存储设备 CPU只能直接访问寄存器、高速缓存和内存 处理前和处理后的所有数据都在内存 执行的指令都在内存 内存管理:提供内存的分配、回收、地址转换、共享和保护等功能 提高内存利用率 提高内存访问速度 从而提高计算机运行效率

操作系统服务提供对用户很有用的函数:

层次结构:操作系统划分为若干层,在低层上构建高层,底层(0层)为硬件,最高层( N层)为用户层,每层只使用低层次的功能和服务 优点 ›简化了系统设计和实现,便于调试和升级维护 缺点 层定义困难,效率差 微内核: 问题:内核越来越大,越来越难管理 内核微型化:核内移出尽可能多功能到用户空间 好处: 便于扩充,便于移植操作系统到新架构系统上,更稳定 (更少的代码运行在核心态),更安全 坏处: 用户空间和内核空间通信的系统开销增加 解决方法:提出消息传递机制 模块化: 大部分现代操作系统采用模块结构(Linux, Solaris) 使用面向对象方法 每个核心部件分开 每个与其他模块的会话被称为接口 每个模块在需要时被加载到内核 总体而言,类似于分层方法,但更灵活

1
2
3
4
一个程序可对应一个或多个进程,同样一个进程可对应一个或多个程序
程序是进程的代码部分
进程是活动(active)实体,程序静止(被动passive)实体
进程在内存,程序在外存
Control Block)
1
2
3
4
5
6
7
8
PCB包含同进程有关的信息,包括:
进程状态
程序计数器
CPU寄存器
CPU调度信息
内存管理信息
计账信息
I/O状态信息

图片 进程调度队列: 作业队列 - 在系统中的所有进程的集合 就绪队列 - 在主内存中的,就绪并等待执行的所有进程的集合 设备队列 - 等待某一I/O设备的进程队列 在各种队列之间进程的迁移 进程终止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
消息传递在微内核中的应用
远程通信无法采用共享内存

发送send(message) - 固定或可变大小消息
接收receive(message)
若P与Q要通信,需要:
建立通信连接
通过send/receive交换消息
通信连接的实现
物理的(如,共享存储,硬件总线)
逻辑的(如,逻辑特性)
消息传递可阻塞(blocking)或非阻塞(non-blocking)
阻塞-同步
阻塞send:发送进程阻塞,直到消息被接收
阻塞receive:接受者进程阻塞,直到有消息可用
非阻塞-异步
非阻塞send:发送进程发送消息并继续操作
非阻塞receive: 接收者收到一个有效消息或空消息
如果通过信箱,则可分为直接和间接通信

线程(轻型进程lightweight process, LWP )是CPU使用的一个基本单元,包括

1
2
3
4
5
6
7
8
调度
线程是调度的基本单位,同一进程中的线程切换不会引起进程切换。
并发
线程可以提高系统的并发性。
资源
进程拥有资源,是资源分配的基本单位,而线程则不拥有资源,但它可以访问创建它的进程所拥有的资源
上下文切换
线程的上下文切换的代价比进程小。

可分为数据并行和任务并行 图片 图片 图片 //S是应用程序的一部分,N是它在N个处理器上串行运行 线程的分类

概念

`需要调度的四种情况

进程调度

等待时间=开始处理时间-到达时间 周转时间=等待时间+处理时间

先来先服务-FCFS

优点:实现简单 缺点:长进程在前会使多个短进程等待过久,增加平均等待时间

短作业优先-SJF

SJF是最优的 – 对一组指定的进程而言,它给出了最短的平均等待时间

抢占式调度

有比当前进程所需时间更短进程到达时,更换目前进行进程 常用于长进程调度,缺点在于进程的cpu区间难以估计 通常用指数平均估计

非抢占式调度

进程只在结束后让出cpu

优先级调度

基于进程紧迫程度赋予优先级,cpu分配给最高优先级进程 优点 实现简单,考虑了进程的紧迫程度 灵活,可模拟其它算法

`问题

响应比高者优先调度

响应比=(开始时间-到达时间)/运行时间

轮转调度-RR

将较小的时间单元定义为时间片,就绪队列为循环队列,调度程序循环整个队列,为每个进程分配不超过一个时间片的cpu

多级队列调度

进程分为前台进程(交互进程)和后台进程(批处理进程) 不同类型的进程需要不同策略 交互进程需要短的响应时间 批处理进程需要短的等待时间 ›多级队列梯度系统中存在多个就绪队列,每个队列有自己的调度算法

多级反馈序列-MLFQ

(MultiLevel Feedback Queue Scheduling) 多级队列的延伸 不同:

1
2
3
4
eg.
Q0-RR时间片8ms
Q1-RR时间片16ms
Q2-FCFS

缺点:优先级一开始确定,无法调整

线程调度

区别用户层和内核层 调度线程而不是进程 多对多和多对一模型,线程库在可用的LWP上调度用户层线程 process-contention scope (PCS) 在进程中进行调度竞争 通常由程序员通过优先级设置 内核线程通过system-contention scope (SCS) 在CPU上调度– 系统中统一竞争 一对一模型仅使用SCS,如Windows, Linux

局部调度

[[线程库]]决定哪个线程列入轻量级进程LWP

全局调度

内核决定下一个运行的内核线程

多处理器调度

调度类似单处理器,但需要将任务平均分配

对称多处理器-SMP

单队列多核调度方法(SQMP)

系统有一个就绪队列。当任意一个CPU空闲时,就从就绪队列中选择一个进程到该CPU上运行 优点: 容易从单核调度算法推广到多核/多处理器、 实现简单,负载均衡 缺点: 不具有亲和性 加锁问题

多队列调度方法(MQMP)

系统有多个就绪队列,一般每个CPU一个。每个就绪队列有自己的调度算法,并且每个就绪队列的调度相对独立 优点: 亲和性好 不需要加锁 缺点: 负载不均衡 策略:“偷”进程 每个处理器决定自己调度方式 定期检测每个cpu负载,分配任务给空闲处理器亲和性:进程倾向于在给定cpu上运行

单队列调度

共享队列,分配给不同cpu 不具有亲和性

多队列调度

不同cpu有各自队列 优点:亲和性较好,不需要加锁 缺点:负载不均匀

非对称处理器-ASMP

仅一个处理器处理系统数据结构,减轻共享需求

实时cpu调度

单速速度调度

依照周期倒数分配一个优先级 优点:最大化cpu利用率 缺点:不保证每个进程都赶上截止期限(周期内执行不完)

最早截止期限优先调度-EDF

根据截止时间分配优先级 越早截止期限,优先级越高

比例分享调度

所有应用中分配T股,确保所有进程有固定的cpu时间,如果新加入进程大于T股剩余量,则不允许进入

实例

linux

windows

对共享数据的并发访问可能导致数据的不一致性,需要保证并发进程正确执行顺序的机制 竞争条件:多个进程并发访问同一共享数据

临界区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Peterson算法
do {

  flag [i]:= true;
  turn = j;
  while (flag [j] and turn == j) ;

  critical section

  flag [i] = false;

  remainder section

  } while (1);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
acquire() {  
       while (!available)
          ; /* busy wait */
       available = false;;
    }
   release() {
       available = true;
    }
   do {

    acquire lock

       critical section

    release lock

      remainder section

 } while (true);

互斥锁(自旋锁)

原子执行acquire(),release() acquire:while(!available) waiting; available=false release:available=false

面包店算法

1
2
3
4
5
6
7
8
9
10
11
12
do {
  choosing[i] = true;
  number[i] = max(number[0], number[1], …, number [n – 1])+1;
  choosing[i] = false;
  for (j = 0; j < n; j++) {
  while (choosing[j]) ;
  while ((number[j] != 0) && (number[j,j] < number[i,i])) ;
  }
  critical section
  number[i] = 0;
  remainder section
} while (1);

信号量(软件解决方案)

1
2
3
4
5
6
7
8
9
信号量S – 整型变量
提供两个不可分割的[原子操作]访问信号量
wait (S):
     while S<= 0 do no-op; 
     S--;
signal(S):
    S++;
wait (S)又称为P(S)
signal(S)又称为V(S)

`分类

1
2
3
4
5
6
7
8
9
例子:P1  和 P2 需要 C1 比C2先运行
       semaphore s=0
P1:
   C1;
   signal(s);

P2:
   wait(s);
   C2;

死锁 – 两个或多个进程无限期地等待一个事件的发生,而该事件正是由其中的一个等待进程引起的. P0  P1   P(S);  P(Q);   P(Q);  P(S);   V(S);  V(Q);   V(Q)  V(S); 饥饿 – 无限期地阻塞。进程可能永远无法从它等待的信号量队列中移去.

实例

生产者消费者问题

生产者 把产品放入指定缓冲区 in:所有的生产者对in指针需要互斥 counter:所有生产者消费者进程对counter互斥消费者 从指定缓冲区取出产品 out:所有的消费者对out指针需要互斥 counter:所有生产者消费者进程对counter互斥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
buffer[in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
counter++;

nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;

生产者:
 {
  …
  生产一个产品
  …
  wait(empty);
  wait(m);
   …
  C1:把产品放入指定缓冲区
   …
  signal(m);
  signal(full);
  }

消费者:
 {
  …
  wait(full);
  wait(m);
   …
  C2:从指定缓冲区取出产品
   …
  signal(m);
  signal(empty);
   …
  消费取出的产品
   …
  }

`同步分析

读者写者问题

两组并发进程读者和写者,共享一组数据区进行读写 `要求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
增加一个读者计数器rc,设置初始值为0;
读者:Repeat
P(mutex);
readcount:=readcount+1;
if readcount=1
then P (w);
V(mutex);//mutex为互斥信号量,初始值为1

P(mutex);
readcount:=readcount-1;
if readcount=0
then V(w);
V(mutex);
Until false


Writers
……
P(W);

V(W);
…...

`问题:写者可能饥饿

哲学家就餐问题

5个哲学家、5根筷子,每个哲学家左右各有一根筷子,每个哲学家只有拿起左右两个筷子才能吃饭 五个元素数组储存筷子,对每个哲学家有拿起左右筷子,放下左右筷子的函数 `防止死锁

方法1

最多允许四个哲学家同时坐在桌子周围

1
2
3
4
5
6
7
8
9
10
11
semephore *chopstick[5];   //初始值为1
semaphore *seat;  //初始值为4
哲学家 i:
  ……
  P(seat);  //看看4个座位是否有空
  P(chopStick[i]);  //拿左边筷子
  P(chopStick[(i + 1) % 5]);  //拿右边筷子
   吃饭
   V(chopStick[i]);  //放下左边筷子
   V(chopStick[(i + 1) % 5]);  //放下右边筷子
   V(seat);  //释放占据的位置
方法2

仅当一个哲学家左右两边筷子都可用时,才允许他拿筷子 哲学家分为三个状态thinking,hungry,eating 设置5个信号量代表所有哲学家,仅当自身hungry且左右都不在吃饭时才开始eating

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void test(int i);
    {
        if (state[i] == hungry) &&  //是否饿了
          (state[(i+4)%5]!=eating) && //左边哲学家是否在吃饭
          (state[(i+1)%5]!=eating)  //右边哲学家是否在吃饭
          {
                 state[i]=eating;  //设置哲学家状态为eating
                 V(ph[i]);  //ph[i]设置为1
           }     
     }
     state[i]=hungry;
            P(m);
            test(i);
            V(m);
            P(ph[i]);
方法3

›给所有哲学家编号,奇数号哲学家必须首先拿左边筷子,偶数号哲学家则反之

信号量总结

S>0:有S个资源可用 S=0:无资源可用 S<0:则|S|表示S等待队列中的进程个数 P(S):申请一个资源 V(S):释放一个资源 互斥信号量初始值:一般为1 同步信号量初始值:0-N `P、V操作成对出现 互斥操作:P、V操作处于同一进程内 同步操作:P、V操作在不同进程内 两个一起的P操作的顺序至关重要 同步与互斥P操作一起时,同步P操作要在互斥P操作前 两个V操作的次序无关紧要

缺点:同步操作分散:信号量机制中,同步操作分散在各个进程中,使用不当就可能导致各进程死锁(如P、V操作的次序错误、重复或遗漏) 易读性差:要了解对于一组共享变量及信号量的操作是否正确,必须通读整个系统或者并发程序; 不利于修改和维护:各模块的独立性差,任一组变量或一段代码的修改都可能影响全局; 正确性难以保证:操作系统或并发程序通常很大,很难保证这样一个复杂的系统没有逻辑错误;

管程

一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据 封装数据以及对数据的操作 确保每次只要一个进程在管程内活动 互斥 管程中的变量只能被管程中的操作访问 任何时候只有一个进程在管程中操作 类似临界区 由编译器完成同步 条件变量 唤醒和阻塞操作 x.wait(): 进程阻塞直到另外一个进程调用x.signal() x.signal():唤醒另外一个进程

问题

管程内可能存在不止1个进程 如:进程P调用signal操作唤醒进程Q后 存在的可能 P等待直到Q离开管程 (Hoare) Q等待直到P离开管程(Lampson & Redll,MESA语言) P的signal操作是P在管程内的最后一个语句 (Hansen,并行Pascal)

内存概念

地址绑定

地址绑定(重定位):把程序中的相对地址转换为内存中的绝对地址的过程 指令和数据绑定到内存地址可在三个不同阶段: ›编译时期( Compile time) 如果内存位置已知,可生成绝对代码 如果开始位置改变,需要重新编译代码加载时期( Load time) 如果存储位置在编译时不知,则必须生成可重定位( relocatable )代码 ›`执行时期( Execution time) 如果进程执行时可在内存移动,则地址绑定可延迟到运行时 需要硬件对地址映射的支持(例如基址和限长寄存器) 大部分操作系统用这个方法

逻辑地址和物理地址

逻辑地址空间的概念同物理地址空间相关联,它是正确内存管理的中心 逻辑地址Logical address 由CPU产生 在进程内的相对地址 也称:虚拟地址、程序地址 物理地址Physical address 内存地址 所有内存统一编址 也称:绝对地址、实地址

内存管理单元

把虚拟地址映射到物理地址的硬件 是CPU用来管理内存的控制线路 在MMU策略中,基址寄存器中的值在其送入内存的时候被加入到由一个用户进程所产生的每个地址中 用户程序所对应到的是逻辑地址,物理地址对它从来都不可见

动态加载和链接

加载 例程在调用之前并不加载 更好的内存空间利用率 没有被使用的例程不被载入 当需大量代码来处理不经常使用的功能时非常有用链接 和各种库文件的链接被推迟到执行时期 需要动态装载技术支持 一小段代码 - 存根,用来定位合适的保留在内存中的库程序 存根用例程地址来替换自己,并开始执行例程 操作系统需要检查例程是否在进程的内存空间,所以需要操作系统支持

交换

一个进程可以暂时被交换(swap)到内存外的一个备份区,随后可以被换回内存继续执行。 备份区—是一个固定的足够大的可以容纳所有用户内存映像拷贝的快速磁盘;必须提供对这些内存映像的直接访问。

1
2
3
4
滚入,滚出(Roll out, roll in )—交换由于基于优先级的算法而不同,低优先级的进程被换出,这样高优先级的进程可以被装入和执行。
交换时间的主要部分是转移时间,总的转移时间直接同交换的内存的数量成比例。
在许多系统如:UNIX,Linux,Windows中,可以找到一些被修正过的交换措施。
系统维持一个就绪队列,它包括在备份存储或在内存中准备运行的所有进程

连续内存分配

为一个用户程序分配一个连续的内存空间

  1. 已分配的分区-已分配分区表   b) 空的分区-空闲分区表

选择孔

碎片

分段

一个程序是一些段的集合,一个段是一个逻辑单位 每个段用段名称和段偏移指定位置 一个逻辑地址是两个向量的集合: <segment-number, offset>

段表 - 映射二维用户地址,每个表项包括: 基址 - 包含内存中段物理地址的起始地址 限长 - 指定段的长度 段表基址寄存器(STBR)指向段表在内存中的地址 段表限长寄存器(STLR)表明被一个程序所使用的段的数目 如果 s < STLR,段号s 是合法的

由于段的长度各不相同,内存分配是一个动态存储-分配问题

`内存分配 首先/最佳适应法 外碎片问题

`重定位 ›动态 ›由段表来执行

`共享 ›共享的段 ›同样的段号

分页

允许进程的物理地址不连续 基本方法:将物理内存分为固定大小的块,称为帧或页帧,逻辑内存分为同样大小的块,称为页或页面 进程物理地址空间可能不连续 如果有可用的物理内存,它将分给进程 把物理内存分成大小固定的块,称为帧(Frame) 大小为2的幂 早期:512字节至8192字节 现在:4K-64K 把逻辑内存也分为同样大小的块,称为页(Page) 系统保留所有空闲帧的记录 运行一个有N页大小程序,需要找到N个空帧来装入程序 建立一个页表,把逻辑地址转换为物理地址 存在内碎片 内存保护 内存的保护由与每个帧相连的保护位来实现 有效-无效位附在页表的每个表项中: ›“有效”表示相关的页在进程的逻辑地址空间,并且是一个合法的页 ›“无效”表示页不在进程的逻辑地址空间中共享代码 如果代码是可重入代码(只读),可以在进程间共享 (如文本编辑器, 编译器, 数据库系统) 共享代码必须出现在所有进程的逻辑地址空间的相同位置
`私有代码和数据 每个进程保留一个代码和数据副本 存有私有数据和代码的页能够出现在逻辑地址空间的任意位置

页表的层次结构

二层页表

内存的保护由与每个帧相连的保护位来实现 有效-无效位附在页表的每个表项中: “有效”表示相关的页在进程的逻辑地址空间,并且是一个合法的页 “无效”表示页不在进程的逻辑地址空间中 图片

哈希页表

虚拟页号被散列到一个页表中。这种页表的每一个条目都包括了一个链表元素,这些元素哈希成同一 虚拟页号与链表中的每个元素相比较,找到匹配项。如果匹配,则相应的物理帧被取出。 虚拟页号与链表中的每个元素相比较,找到匹配项。如果匹配,则相应的物理帧被取出。

反向页表

对于每个真正的内存页或帧有一个条目。 每个条目保存在真正内存位置的页的虚拟地址,以及包括拥有这个页的进程的信息。 `优缺点 减少了需要储存每个页表的内存,但是当访问一个页时,增加了寻找页表需要的时间。 使用哈希表来将查找限制在一个或少数几个页表条目。 实现共享内存困难

段页式原理

分段和分页原理的结合 先将用户程序分成若干个段,再把每个段分成若干个页,并为每个段赋予一个段号 逻辑地址:<段号,页号,页内偏移> 存在内碎片 无外碎片

内存扩充技术

  1. 紧缩Compaction(可变分区)
  2. 覆盖技术Overlaying
  3. 交换技术Swapping
  4. 虚拟内存Virtual Memory

覆盖

解决问题à程序大小超过物理内存总和 程序执行时 ›只在内存中保留那些在任何时间都需要的指令和数据 ›程序的不同部分在内存中相互替换 由程序员声明覆盖结构,不需要操作系统的特别支持 覆盖结构的程序设计很复杂 应用于早期的操作系统

交换

在多道程序环境下,一方面,在内存中的某些进程由于某事件尚未发生而被阻塞运行,但它却占用了大量的内存空间,甚至有时可能出现在内存中所有进程都被阻塞而迫使CPU停止下来等待的情况 另一方面,却又有着许多作业在外存上等待,因无内存而不能进入内存运行的情况 浪费资源,降低系统吞吐量。 一个进程可以暂时被交换(swap)到内存外的一个备份区,随后可以被换回内存继续执行 备份区—是一个固定的足够大的可以容纳所有用户内存映像拷贝的快速磁盘;必须提供对这些内存映像的直接访问 交换(备份区):系统指定一块特殊的磁盘区域作为交换空间(swap space),包含连续的磁道,操作系统可以使用底层的磁盘读写操作对其高效访问

系统模型

资源类型 R1, R2, . . ., Rm CPU周期,内存空间,I/O设备 每一种资源Ri 有Wi  种实例 每一个进程通过如下方法来使用资源 申请,使用,释放 资源动态申请-常用方法 在进程运行过程中申请资源 资源静态申请 在进程运行前一次申请所有资源

必要条件

死锁指一组等待的进程,其中每一个进程都持有资源,并且等待着由这个组中其他进程所持有的资源

资源分配图

被分为两个部分 ›P = {P1, P2, …, Pn}, 含有系统中全部的进程 ›R = {R1, R2, …, Rm}, 含有系统中全部的资源 请求边:有向边Pi->Rj 分配边:有向边Ri->P

死锁处理的分类

预防

›`抑制死锁发生的必要条件

  1. 如果一个进程的申请没有实现,它要释放所有占有的资源
  2. 先占的资源放入进程等待资源列表中
  3. 进程在重新得到旧的资源的时候可以重新开始
  4. 进程申请资源时,如果资源可用则分配,如果不可用,检查资源是否被分配给等待额外资源的其他进程,如果是,抢占资源,否则,申请进程等待

避免

安全状态

当进程申请一个有效的资源的时候,系统必须确定分配后是安全的 如果存在一个安全序列,系统处于安全态 进程序列<P1, P2, …, Pn>是安全的,如果每一个进程Pi所申请的可以被满足的资源数加上其他进程所持有的该资源数小于系统总数 如果 Pi 需要的资源不能马上获得,那么Pi 等待直到所有的Pi-1进程结束。 当Pi-1 结束后, Pi获得所需的资源,执行、返回资源、结束。 当Pi结束后, Pi+1获得所需的资源执行,依此类推。 `定理 如果一个系统在安全状态,就没有死锁 如果一个系统不是处于安全状态,就有可能死锁 避免=>确保系统永远不会进入不安全状态

银行家算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Available:  长度为 m的向量。 如果available[j]=k,那么资源Rj有k个实例有效
Max: n x m 矩阵。 如果Max[i,j]=k,那么进程Pi最多可以请求k个资源Rj的实例
Allocation:  n x m 矩阵。 如果Allocation[i,j]=k,那么进程Pj当前分配了k个资源Rj的实例
Need:  n x m 矩阵。如果Need[,j]=k,那么进程Pj还需要k个资源Rj的实例
Need [i,j] = Max[i,j] – Allocation [i,j].
1.让Work和Finish作为长度为m和n的向量初始化:
Work := Available
Finish [i] = false for i - 1,2,3, …, n.
2.  查找i
(a) Finish [i] = false
(b) Needi £ Work
If no such i exists, go to step 4.
3.  Work := Work + Allocationi
Finish[i] := true
go to step 2.
4.  如果对所有i的 Finish [i] = true, 则系统处在安全状态。

   Requesti =进程 Pi 的资源请求向量.  如果Requesti [m] = k 则进程 Pi 想要资源类型为Rjm的k个实例 1.  如果 Requesti £ Needi 转 step 2.  否则报错, 因为进程请求超出了其声明的最大值 2.  如果 Requesti £ Available, 转 step 3.  否则 Pi  必须等待, 因为资源不可用. 3.  假设通过修改下列状态来分配请求的资源给进程Pi :   Available := Available - Requesti;   Allocationi := Allocationi + Requesti;   Needi := Needi – Requesti;;   •如果系统安全 Þ 将资源分配给 Pi. •如果系统不安全 Þ Pi 必须等待,恢复原有的资源分配状态

死锁检测和恢复

每个资源类型有一个实例:维护进程等待图 每个资源类型有多个实例:用available和finished数组探查是否死锁 允许进入死锁状态并加以恢复 维护等待图 节点是进程 Pi->Pj表明Pi在等待Pj 定期调用算法来检查是否有环 一个检查图中是否有环的算法需要n^2的操作来进行,n为图中的节点数 Available :一个长度为m的向量,表示每一种资源类型可用的实例数目 Allocation:  一个n x m 的矩阵,定义了当前分配的每一种资源类型的实例数目 Request: 一个n x m 的矩阵,表明了当前的进程请求。如果Request[i,j]=k,那么进程Pi请求k个资源Rj的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.  让Work和Finish作为长度为m和n的向量初始化
(a) Work = Available
(b)  For i = 0,2, …, n-1, if Allocationi ¹ 0, thenFinish[i] = false;otherwise, Finish[i] = true.

2.  找到满足下列条件的下标i
(a)  Finish[i] = false
(b)  Requesti <= Work
如果没有这样的i存在,转4

3.  Work = Work + Allocationi
Finish[i] = true
转 2.

4.如果有一些i (0 £ i < n) , Finish[i] = false, 则系统处在死锁状态。而且, 如果 Finish[i] = false, 则进程 Pi 是死锁的。

`算法需要m x n^2 次操作来判断是否系统处于死锁状态

恢复

可以一次中断所有进程排查,也可以一个一个终结进程 选择牺牲进程:最小化代价 回滚:返回到安全的状态,然后重新开始进程 饥饿:同样进程的可能总是被选中。在代价因素中加入回滚次数

虚拟内存概念

局部性原理:在一较短的时间内,程序的执行仅局限于某个部分;相应地,它所访问的存储空间也局限于某个区域 一个程序只要部分装入内存就可以运行 整个程序不是同一时间都要运行 `程序部分装入技术优点 进程大小不再受到物理内存大小限制 每个进程需要的内存更小 更多进程可以并发运行 I/O更少

虚拟页式存储管理

基本思想 进程开始运行之前,不是装入全部页面,而是装入一个或零个页面 运行之后,根据进程运行需要,动态装入其他页面 当内存空间已满,而又需要装入新的页面时,则根据某种算法置换内存中的某个页面,以便装入新的页面请求分页(按需调页) 只有在一个页需要的时候才把它换入内存 需要很少的I/O 需要很少的内存 快速响应 多用户 懒惰交换:只有在需要页时,才将它调入内存 交换程序(swapper)对整个进程进行操作 调页程序(pager)只是对进程的单个页进行操作

有效无效位

每一个页表的表项有一个有效- 无效位相关联: 1表示在内存,0表示不在内存 在所有的表项中,这个位被初始化为0 一个页表映象的例子

缺页中断的处理

1.访问指令或数据 2.查看另一个表来决定: 无效引用 Þ 终止 仅仅不在内存 3.找到页在后备存储上的位置 4.得到空的页框,把页换入页框 5.重新设置页表,把有效位设为v 6.重启指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
极端情况:进程执行第一行代码时,内存内没有任何代码和数据
›进程创建时,没有为进程分配内存,仅建立PCB
›导致缺页中断
›纯请求分页(纯粹按需调页)

一条指令可能导致多次缺页(涉及多个页面)
›幸运的是,程序具有局部性(locality of reference)

请求调页需要硬件支持
›带有效无效位的页表
›交换空间
›指令重启

缺页率(缺页的概率):0 <= p <= 1.0
›如果 p = 0 ,没有缺页
›如果 p = 1, 每次访问都缺页

有效访问时间( EAT )
    EAT = (1 – p) x 内存访问时间+ p x 页错误时间

页错误时间=处理缺页中断
  + [页交换出去时间 ]
  + 读入页时间
  + 重启进程开销

性能优化: 页面转换时采用交换空间,而不是文件系统 ›交换区的块大,比文件系统服务快速

在进程装载时,把整个进程拷贝到交换区 ›基于交换区调页 ›早期的 BSD Unix

利用文件系统进行交换 ›Solaris和当前的BSD ›部分内容仍旧需要交换区(堆栈等) 写时复制:允许父进程和子进程在初始化时共享页面 ›如果其中一个进程修改了一个共享页面,会产生副本 ›更加高效 ›应用在Windows,Linux,macOS等系统

需要页置换的情况

页置换—找到内存中当前没有使用的一些页,换出 同一个页可能会被装入内存多次 基本页置换方法

  1. 查找所需页在磁盘上的位置
  2. 查找一空闲帧 如果有空闲帧,就使用它 如果没有空闲帧,使用页置换算法选择一个“牺牲”页框 将“牺牲”帧的内容写到磁盘上,更新页表和帧表
  3. 将所需页读入(新)空闲帧,更新页表和帧表
  4. 重启用户进程

如果发生页置换,则缺页处理时间加倍 使用修改位modify bit或脏 (dirty bit) 来防止页面转移过多—只有被修改的页面才写入磁盘 页置换完善了逻辑内存和物理内存的划分—在一个较小的物理内存基础之上可以提供一个大的虚拟内存

页面置换算法

先进先出(FIFO)算法

置换在内存中驻留时间最长的页面 容易理解和实现、但性能不总是很好 实现:使用FIFO队列管理内存中的所有页 FIFO算法可能会产生Belady异常 更多的页框 =>更多的缺页

最优置换算法OPT

被置换的页是将来不再需要的或最远的将来才会被使用的页 实现? 作用:作为一种标准来衡量其它算法的性能

最近最少使用算法(LRU)

置换最长时间没有使用的页 性能接近OPT 实现:计数器(时间戳)或栈 开销大、需要硬件支持 栈实现—在一个双链表中保留一个记录页数目的栈: 被访问的页: 移到栈顶 需要改变6个指针 没有为置换进行查找

在没有硬件支持的系统中,可使用LRU近似算法访问位 每个页都与一个位相关联,初始值为0 当页访问时设位1

二次机会算法

需要访问位 如果访问位为0,直接置换 如果将要交换的页访问位是1,则: 把访问位设位0 把页留在内存中 以同样的规则,替换下一个页

实现:时钟置换(顺时针方式)

基于计数的页面置换

用一个计数器记录对每一个页的访问次数 LFU 以最小的计数置换一个页

页面缓冲算法

  1. 总是保留一个空闲帧缓冲池
  1. 扩展之一,维护一个修改页面的列表
  1. 另一种修改,保留一个空闲帧池,并且记着哪些页面在哪些帧内

帧分配

两种主要分配策略

固定分配

平均分配 Equal allocation– 例如,如果有100帧和5个进程,给每个进程20帧 在缓冲池里保存空闲帧 比例分配 Proportional allocation – 根据进程大小分配内存 按照多道程度而动态分配,进程分得的数量变化

优先级分配

优先级分配:用优先级而不是大小来进行比例分配
如果进程 Pi 跑出页面错误, 从自己的帧里选择一个替代 从优先级较低的进程里选择一个替代

全局 vs. 局部分配

全局置换 Global replacement – 允许进程从所有帧的集合中选择一个置换帧;一个进程可以从另一个进程那里获取帧 但是进程执行时间可能变化很大,不能控制缺页错误率 有更好的系统吞吐量,更常用 局部置换 Local replacement – 每个进程只从它自己分配的帧中进行选择 对每个进程的表现更一致 但是可能内存低利用

非均匀内存访问(NUMA)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
v以上假设所有内存可以被平等访问

v很多系统如 NUMA – 内存访问速度变化的

›考虑CPU和内存在系统中通过总线互连

v让分配的内存帧‘尽可能地靠近’运行进程的CPU

›通常意味着位于同一系统扳

›Solaris通过在内核中创建延迟组 lgroups

v将相近的CPU和内存聚集在一起

v在组内调度进程的所有线程,并分配它的所有内存

v最大限度减少总体内存延迟,最大化CPU缓存命中率

抖动

如果一个进程没有足够的页,那么缺页率将很高,这将导致: CPU利用率低下. 操作系统认为需要增加多道程序的道数 系统中将加入一个新的进程 颠簸(抖动)=一个进程的页面经常换入换出 原因:分配的帧数 < 局部大小之和

工作集模型

工作集窗口 º 固定数目的页的引用 WSSi (进程Pi的工作集) = 最近D中所有页的引用 (随时间变化) 图片 vExample: D = 10,000

›每5000个时钟单位时钟中断

›为每个页在内存中保留两个位

›任何时候一个时钟中断拷贝,把所有访问位设为0

›如果一个在内存中的位是0,说明页在工作集

内存映射文件

通过映射一个磁盘块成内存的一页,内存映象文件I/O 允许文件I/O 作为普通内存访问。 开始的文件访问按普通请求分页来进行,一页大小的部分文件从文件系统读入物理页。以后文件的读、写操作就按通常的内存访问来处理。 由于通过内存的文件操作而不是使用系统调用read() write() ,简化了文件访问和使用。 多个进程可以允许将同一文件映射到各自的虚拟内存中,以允许数据共享

内核内存分配

通常从空闲内存池中获取 ›内核需要为不同大小的数据结构分配内存 ›一些内核内存需要连续的物理页

1
2
3
4
5
6
7
8
9
10
11
12
13
v内核在使用内存块时有如下特点:

    (1)内存块的尺寸比较小;

    (2)占用内存块的时间比较短;

    (3)要求快速完成分配和回收;

    (4)不参与交换。

    (5)频繁使用尺寸相同的内存块,存放同一结构的数据;

    (6)要求动态分配和回收。

伙伴(Buddy)系统

v主要用于Linux早期版本中内核底层内存管理 v一种经典的内存分配方案 v从物理上连续的大小固定的段上分配内存 v主要思想:内存按2的幂的大小进行划分,即4KB、8KB等,组成若干空闲块链表;查找链表找到满足进程需求的最佳匹配块 ›满足要求是以2的幂为单位的 ›如果请求不为2的幂,则需要调整到下一个更大的2的幂 ›当分配需求小于现在可用内存时,当前段就分为两个更小的2的幂段,继续上述操作直到合适的段大小 `算法 ›首先将整个可用空间看作一块: 2^n ›假设进程申请的空间大小为s,如果满足 2(n-1)<s<=2n,则分配整个块    否则,将块划分为两个大小相等的伙伴,大小为2^(n-1) ›一直划分下去直到产生大于或等于s的最小块

Slab 分配

v内核分配的另一方案 vSlab 是由一个或多个物理上连续的页组成 vCache 含有一个或多个 slab v每个内核数据结构都有一个cache 每个 cache 含有内核数据结构的对象实例

v当创建 cache 时, 包括若干个标记为空闲的对象 v当内核对象时,从cache上直接获取,并标识对象为使用 v当一个slab充满了已使用的对象时,下一个对象的分配从空的slab开始分配 ›如果没有空的slab, 则从物理连续页上分配新的slab v优点 ①没有因碎片而引起的内存浪费

②内存请求可以快速满足

杂项

预调页面 v在进程启动初期,减少大量的缺页中断 v在引用前,调入进程的所有或一些需要的页面 v如果预调入的页面没有被使用,则内存被浪费页面尺寸大小 v碎片 – 需要小的页 v表大小 – 需要大的页 vI/O 开销 – 需要大的页 v程序局部 – 需要小的页 v缺页次数 – 需要大的页 v其他因素 没有最佳答案,总的来说,趋向更大的页 TLB 范围 vTLB 范围 – 通过TLB所访问的内存量 vTLB 范围 = (TLB 大小) X (页大小) v理想情况下,一个进程的工作集应存放在 TLB中 ›否则会有大量的缺页中断 v增加页的大小 ›对于不需要大页的应用程序而言,这将导致碎片的增加 v提供多种页的大小 ›这允许需要大页的应用程序有机会使用大页而不增加碎片的大小倒置页表 v倒置页表降低了保存的物理内存 v不再包括进程逻辑地址空间的完整信息 v为了提供这种信息,进程必须保留一个外部页表 v外部页表可根据需要换进或换出内存 `I/O 联锁与页面锁定 v允许某些页在内存中被锁住

vI/O时,正在进行I/O的页面不允许被置换算法置换出内存 linux vSLAB vDemand paging vGlobal page replacement(LRU) v两个帧列:active_list和inactive_list vKswapd daemon 定期检查windows10 vBoth IA-32 and x86-64 v32bit支持4GB,64bit支持128TB内存 vShared memory, demand paging, copy-on-write, paging和memory compression v按需调页-clustering,预调入3-7页 vWorking-Set 管理(最少50-最多345页)

文件概念

文件 ›计算机中信息存储的基本组织形式 ›相关信息结合 ›具有文件名文件名 ›按名存取:文件名     存储位置 ›文件名由一串ASCII码或(和)汉字构成 ›名字长度 v8.3规则:文件名8个字符,类型3个字符,之间有“.”分割 v长文件名:可以最多输入255多个字符作为文件名 ›文件名可能大小写敏感 文件的打开 v需要数据结构 ›打开文件表:跟踪打开文件 ›文件指针:指向最后一次读写的位置,每个进程1个 ›打开文件计数器:打开文件次数(调用open次数) ›文件存储位置:文件存放在存储设备上的位置信息 ›访问权限:每个进程的访问权限 v优点 ›方便文件共享 ›提高文件存取效率文件锁 ›共享锁 Shared lock 类似于读者锁– 多个进程可以并发获取它。 ›独占锁 Exclusive lock 类似于写者锁 `文件结构 v目的:便于程序理解文件内容 ›无结构:文字流、字节流等 ›简单记录结构:线性、固定长度、可变长度等 ›复杂结构:格式化文档、多媒体文件等 v谁决定了文件结构 ›操作系统 程序

文件访问

逻辑文件

v文件呈现在用户面前的组织结构 v又称为文件逻辑结构 v逻辑文件决定了文件访问方法 `文件访问方式 - 顺序访问 ›最简单的访问方式 ›文件信息按照存放顺序,一个记录一个记录地依次访问 ›顺序文件 ›典型存储设备:磁带 - 直接(随机)访问 ›可以直接定位到文件的某条记录进行访问 ›直接文件 典型设备:磁盘 v访问方式:直接(随机)访问 v直接通过计算得到需要读写记录的位置,直接跳转进行文件读写 - 索引文件 v基本方法:为顺序文件建立索引表

1
2
3
4
5
6
7
8
9
10
11
12
13

记录平均长度:40B   索引表项大小:4B   1M条记录长度:44MB

访问第1万条记录:

       1)计算得到第1万条记录的索引项在索引表中首址:10000*4=40000

       2)从索引表地址40000处读入4个字节,内容为第1万条记录在顺序文件中的首址P

       3)从顺序文件地址P处读入40个字节(假如第1万条记录长度为40B)

合计读入:4+40=44B

目录结构

文件控制块(FCB)

存放操控文件所需的各类文件属性信息 ›文件名 ›长度 ›创建时间 ›存放位置 ›访问控制权限 类似一个索引项 v目录项 ›存放一个文件的各类属性 ›有的系统等同于文件控制块 v目录 ›包含着所有文件信息的节点集合 ›根据文件名检索文件的桥梁 ›目录项的有序集合 v目录文件 ›目录组织形式 ›目录作为一个文件存在于文件系统 v每个目录项中存放了文件在存储设备的存放地址 v目录和文件都驻留在存储设备(如磁盘)

文件检索

v文件检索是一个遍历目录项的过程 1.打开目录文件 2.从磁盘读入该目录文件的1个(物理)块,该块包含若干个目录项 3.根据文件名遍历内存中的该块,如找到则结束 4.判断该目录文件是否还有物理块没有读入,如果是转2;否则,结束。表示该目录中没有此文件名的文件 v目录项由于经常变化,一般不排序 v平均遍历目录项数:       (1+n)/2   不包括文件查不到的情况   ›   目录项大小= ds bytes ›目录中最多文件数 = n ›物理块大小 = b v那么 ›目录文件大小 = ds*n bytes ›目录文件需要的物理块数目 = ds*n/b 检索一个文件需要平均读入的块数=(ds*n/b+1)/2

目录结构

设计目标 v效率 ›快速定位文件位置 ›提高文件访问效率 v命名 ›方便用户使用 ›同名的不同文件 ›不同名的相同文件 v分组 ›文件分组(子目录) ›兼顾效率和方便性单层目录 v所有文件在同一目录中,只有一级目录:根目录 v根目录(/):一个文件系统最顶层的目录 v优点:结构简单 v缺点 ›检索效率差(目录下文件过多) ›不能有同名文件,一个文件只能有一个名称 ›不能分组 双层目录 v每个用户有自己的目录结构 v目录下的目录 v缺点:1)无法分组;2)同一用户不能有相同文件名的文件 v优点:1)不同用户可有相同文件名的文件;2)比单层目录提高检索效率(文件分布在多个用户目录中)树形目录 v特点 ›检索高效(子目录增多导致每个目录下文件减少) ›可以分组 ›允许重名 v当前目录:工作目录 ›cd /spell/mail/prog ›type list v绝对路径 ›从根开始的路径名 v相对路径 ›从当前目录开始的路径名 ›提高检索效率 (有向)无环图目录 v文件共享:不同目录中的文件指向同一个物理文件,也就是它们内容相同 v树型目录不能实现文件共享 v解决方法:图型目录 ›无环图目录 ›通用图目录(有环图) v无环图:有向边无环如何保证无环? ›仅允许指向文件的链接,不允许指向子目录的链接 ›垃圾回收 ›每当加入新链接时,使用环路检测算法判断是否正确 ›优化遍历目录算法,避免对环的重复搜索

杂项

v要访问一个文件系统,必须先安装它。 一个未安装的文件系统将被安装在一个安装点(mount point)上。

远程文件系统

v用网络使得远程计算机之间的联系成为可能 ›手动传输文件如 FTP ›自动,直接访问文件用分布文件系统 distributed file systems ›半自动用万维网 world wide web vClient-server 客户机-服务器模型允许客户机登录远程服务器的文件系统 ›服务器可以服务多台客户机 ›识别客户可能是不安全和复杂的 ›NFS 是标准 UNIX 下客户机-服务器的文件共享协议 ›CIFS 是Windows下标准协议 ›标准操作系统文件调用翻译为远程调用 v分布式信息系统 (分布式命名服务 distributed naming services) 如LDAP, DNS, NIS。

故障

v所有文件系统都有故障模式 ›例如目录结构或者其他磁盘管理信息(元数据 metadata 损坏。 v远程文件系统加入新的故障模式,来自网络故障或者服务器故障 v从故障中恢复包含维护状态信息 state information vStateless 无状态协议如NFC在每个请求里包含所有信息,允许较为容易的故障恢复但是不够安全

共享

v规定系统的多个用户如何访问共享文件 ›类似于第六章的进程同步算法 v由于磁盘和网络的巨大延迟和很慢的传输速率,倾向于没这么复杂 ›Andrew File System (AFS) 实现了复杂共享语义 ›Unix file system (UFS) 使用: v一个用户对已打开文件的写入,对于打开同一文件的其他用户立即可见。 v一种共享模式允许用户共享文件的当前位置指针。 ›AFS 有会话语义 v一旦文件关闭,对其所作的更改只能被后来打开的会话可见。

访问控制权限和分组

v访问模式:读/写/执行 v三种类型的用户   RWX   a) 所有者  7  =>1 1 1    RWX   b) 组用户  6  =>  1 1 0 RWX   c) 公共用户  1  =>  0 0 1 v建立一个组,加入一些用户 v对特定的文件或目录(game) ,定义适当的访问权限

]]>
- + 我本以为影子工厂会如简介说的一样,会是杂糅诸多风格的悬疑风,故事的一开始也的确如此,时间穿越配合豪宅血腥谋杀的经典模式别有一番风味,不过结合前传一贯的发展,不难想象出而在这之后又回到了我们熟悉的时间轴环节,比较特殊的是,这次高瞰老师罕见地采用了正叙的方式,而且此次的故事出奇的平淡,尽管感情上依旧无比细腻,但几乎没有什么出乎意料地发展。 而事实上,高瞰老师擅长的叙事诡计只是换了一种方式呈现在我们面前,这是一个一位身患绝症的女性在生活和事业中苦苦挣扎,在经历了孩子的夭折后,最后选择了事业的故事,尽管这个故事占了整部游戏大半的流程,但其实它本身并不是重点,因为在开头,影子工厂的主线就被堂而皇之地摆在了我们的面前,豪宅层出不穷的死亡案件,于是,在历览了女主的人生后,真相的追寻才真正开始,当然了,故事如何这里就不赘述了。 当然,相比前两作选材的独特,和层出不穷的叙事诡计,影子工厂显得平淡的多,正如lynri所说,昆西相比两位博士不过是一个观察者而已,他对于挚爱的lynri无能为力,面对自己不过是模拟的数据也无能为力,他的一生没有什么狂乱幻想,也没有多么丰富的内心世界,尽管他的内心是强大的,不过依旧没有什么意思。当昆西历览lynri的记忆时,我们会发现相比博士的聒噪,大部分时候他不过沉默地接受着,评价这一环节是在这段记忆中缺少的。而让这段记忆,一个不是最重要的故事占据叙事的大部分是可以的,但问题在于这一部分必须要穿插主线,否则会产生严重的割裂感,而就影子工厂来说,很难说这一部分和主线有着多大的关系,是否手术的分歧导致了之后的一切,但要拼凑出真相,我们需要知道的除了这个世界不是真实的以外,还有分歧点在于保大还是保小,以及lynri的姓氏,而这两点都没有结合进这个过程。抛开叙事结构,如果我们只看这个故事本身,昆西的爱情故事虽然不能说不好,但比起前作的惊艳未免显得俗套。可以说,如果把这个故事大刀阔斧地砍几笔,也不会有多大的差别,当然,就故事的首尾而言依旧是很有趣的。 不过即便如此,我也要说影子工厂是一部水准上的作品,它有着层层递归的脑洞,优秀的人物塑造,最重要的是,它还展示了高瞰老师填坑的一点点意愿,虽然到最后我们也不会知道两位博士之后到底会怎么发展。而对于系列中虽然重要但没有认真探讨过的记忆编辑技术,影子工厂也表明了一种态度,就是尽管这可能看上去虚无的,但就我们个人所及的知识与眼见来看,只有有过美好的时刻,它就是有意义的,这是一种积极向上的态度,尽管这只是一种态度,但对于虚无与否的讨论大部分时候都只能取决于我们的态度。能以合适的形式传达出这样的观点,就是一部很好的作品了。

]]>
- <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">计算机系统可以分为四个部分</span><br><span class="line">硬件(Hardware) – 提供基本的计算资源</span><br><span class="line">CPU, memory, I/O devices</span><br><span class="line">操作系统(Operating System)</span><br><span class="line">控制和协调各用户的应用程序对硬件的使用</span><br><span class="line">应用程序(Application programs) – 规定了用户按何种方式使用系统资源</span><br><span class="line">字处理程序, 编译器, 网络浏览器, 数据库系统, 视频游戏</span><br><span class="line">用户(Users)</span><br><span class="line">人, 机器, 其他计算机</span><br><span class="line">操作系统的目标:</span><br><span class="line">运行用户程序  ---核心目标</span><br><span class="line">更方便使用计算机 ---面向用户</span><br><span class="line">更高效使用计算机 ---面向系统</span><br></pre></td></tr></table></figure> + <p>我本以为影子工厂会如简介说的一样,会是杂糅诸多风格的悬疑风,故事的一开始也的确如此,时间穿越配合豪宅血腥谋杀的经典模式别有一番风味,不过结合前传一贯的发展,不难想象出而在这之后又回到了我们熟悉的时间轴环节,比较特殊的是,这次高瞰老师罕见地采用了正叙的方式,而且此次的故事出奇的平淡,尽管感情上依旧无比细腻,但几乎没有什么出乎意料地发展。 - - + + - - + - +
- 影子工厂 - - https://thinklive1.github.io/2023/09/30/%E5%BD%B1%E5%AD%90%E5%B7%A5%E5%8E%82/ - 2023-09-30T11:38:04.163Z + 基于恐龙书和苏大ppt的操作系统笔记 + + https://thinklive1.github.io/2023/09/29/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ + 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.697Z - 我本以为影子工厂会如简介说的一样,会是杂糅诸多风格的悬疑风,故事的一开始也的确如此,时间穿越配合豪宅血腥谋杀的经典模式别有一番风味,不过结合前传一贯的发展,不难想象出而在这之后又回到了我们熟悉的时间轴环节,比较特殊的是,这次高瞰老师罕见地采用了正叙的方式,而且此次的故事出奇的平淡,尽管感情上依旧无比细腻,但几乎没有什么出乎意料地发展。 而事实上,高瞰老师擅长的叙事诡计只是换了一种方式呈现在我们面前,这是一个一位身患绝症的女性在生活和事业中苦苦挣扎,在经历了孩子的夭折后,最后选择了事业的故事,尽管这个故事占了整部游戏大半的流程,但其实它本身并不是重点,因为在开头,影子工厂的主线就被堂而皇之地摆在了我们的面前,豪宅层出不穷的死亡案件,于是,在历览了女主的人生后,真相的追寻才真正开始,当然了,故事如何这里就不赘述了。 当然,相比前两作选材的独特,和层出不穷的叙事诡计,影子工厂显得平淡的多,正如lynri所说,昆西相比两位博士不过是一个观察者而已,他对于挚爱的lynri无能为力,面对自己不过是模拟的数据也无能为力,他的一生没有什么狂乱幻想,也没有多么丰富的内心世界,尽管他的内心是强大的,不过依旧没有什么意思。当昆西历览lynri的记忆时,我们会发现相比博士的聒噪,大部分时候他不过沉默地接受着,评价这一环节是在这段记忆中缺少的。而让这段记忆,一个不是最重要的故事占据叙事的大部分是可以的,但问题在于这一部分必须要穿插主线,否则会产生严重的割裂感,而就影子工厂来说,很难说这一部分和主线有着多大的关系,是否手术的分歧导致了之后的一切,但要拼凑出真相,我们需要知道的除了这个世界不是真实的以外,还有分歧点在于保大还是保小,以及lynri的姓氏,而这两点都没有结合进这个过程。抛开叙事结构,如果我们只看这个故事本身,昆西的爱情故事虽然不能说不好,但比起前作的惊艳未免显得俗套。可以说,如果把这个故事大刀阔斧地砍几笔,也不会有多大的差别,当然,就故事的首尾而言依旧是很有趣的。 不过即便如此,我也要说影子工厂是一部水准上的作品,它有着层层递归的脑洞,优秀的人物塑造,最重要的是,它还展示了高瞰老师填坑的一点点意愿,虽然到最后我们也不会知道两位博士之后到底会怎么发展。而对于系列中虽然重要但没有认真探讨过的记忆编辑技术,影子工厂也表明了一种态度,就是尽管这可能看上去虚无的,但就我们个人所及的知识与眼见来看,只有有过美好的时刻,它就是有意义的,这是一种积极向上的态度,尽管这只是一种态度,但对于虚无与否的讨论大部分时候都只能取决于我们的态度。能以合适的形式传达出这样的观点,就是一部很好的作品了。

]]>
+
1
2
3
4
5
6
7
8
9
10
11
12
13
计算机系统可以分为四个部分
硬件(Hardware) – 提供基本的计算资源
CPU, memory, I/O devices
操作系统(Operating System)
控制和协调各用户的应用程序对硬件的使用
应用程序(Application programs) – 规定了用户按何种方式使用系统资源
字处理程序, 编译器, 网络浏览器, 数据库系统, 视频游戏
用户(Users)
人, 机器, 其他计算机
操作系统的目标:
运行用户程序  ---核心目标
更方便使用计算机 ---面向用户
更高效使用计算机 ---面向系统

计算机启动时,会启动引导程序,来初始化系统的各个组件,加载操作系统并开始执行 操作系统加载到内存后,开始为系统和用户提供服务,成为系统进程或者后台程序该阶段完成后系统完全启动并且等待事件发生。 事件发生通过”中断“机制来通知,cpu被中断时,停止正在做的事,并立即转到固定位置继续执行中断服务程序,执行完后继续执行被中断的计算

1
在冯·诺依曼体系结构( von Neumann architecture)上执行时,一个典型的指令执行周期是,首先从内存中获取指令,并存到指令寄存器( instruction register)。接着,该指令被解码,也可能会从内存中获取操作数据并且存到内部寄存器。在指令完成对操作数据的执行后,结果也可存到内存。注意:内存单元只能看到内存地址的流,而并不知道它们如何产生(通过指令计数器、索引、间接、常量地址或其他方式)或它们是什么样(指令或数据)的地址。相应地,我们可以忽略程序如何产生内存地址,而只关注由程序运行所生成的地址序列。

集群系统

由两个或多个独立的系统耦合起来 共享数据 storage-area network (SAN)。 提供高可用性。 ›一定的冗余 非对称集群(Asymmetric Clustering):一台机器运行应用程序,而其他机器处于热备份模式。 对称集群(Symmetric Clustering):多个主机都运行应用程序 提供high-performance computing (HPC) 用专门的应用程序利用集群,并行计算parallelization

1
2
3
4
多道程序设计:在内存中同时存在多道作业,在管理程序控制下相互穿插运行
通过作业调度(Job Scheduling)选中一个作业并运行
当该作业必须等待时 (如等待I/O), 切换到另一个作业
目的:提高CPU的利用率,充分发挥计算机系统部件的并行性

分时系统:控制响应时间较短,使计算机可交互,›一般采用时间片轮转方式使一台计算机为多个用户服务 并行:两个或者多个作业在同一时刻运行 并发:两个或多个作业在同一时间间隔内依次运行 双重模式:允许OS保护自身和其他系统部件 用户模式(user mode)和内核模式(kernel mode),由硬件提供模式位 特权指令:可能引起系统崩溃的指令,只能运行在内核模式

1
2
3
4
5
6
如果操作系统不能获得CPU控制权,就无法管理系统
eg.用户程序死循环,用户程序不调用系统调用
解决方法:定时器
在一段时间后发生中断,CPU控制权返回操作系统
固定时间和可变时间定时器
利用时钟和计数器实现

I/O保护 防止用户程序执行非法I/O 解决方法:所有I/O指令都是特权指令 用户程序通过系统调用进行I/O操作 内存保护 防止内存非法访问 解决方法:存储保护机制 硬件支持 程序运行必须的存储设备 CPU只能直接访问寄存器、高速缓存和内存 处理前和处理后的所有数据都在内存 执行的指令都在内存 内存管理:提供内存的分配、回收、地址转换、共享和保护等功能 提高内存利用率 提高内存访问速度 从而提高计算机运行效率

操作系统服务提供对用户很有用的函数:

层次结构:操作系统划分为若干层,在低层上构建高层,底层(0层)为硬件,最高层( N层)为用户层,每层只使用低层次的功能和服务 优点 ›简化了系统设计和实现,便于调试和升级维护 缺点 层定义困难,效率差 微内核: 问题:内核越来越大,越来越难管理 内核微型化:核内移出尽可能多功能到用户空间 好处: 便于扩充,便于移植操作系统到新架构系统上,更稳定 (更少的代码运行在核心态),更安全 坏处: 用户空间和内核空间通信的系统开销增加 解决方法:提出消息传递机制 模块化: 大部分现代操作系统采用模块结构(Linux, Solaris) 使用面向对象方法 每个核心部件分开 每个与其他模块的会话被称为接口 每个模块在需要时被加载到内核 总体而言,类似于分层方法,但更灵活

1
2
3
4
一个程序可对应一个或多个进程,同样一个进程可对应一个或多个程序
程序是进程的代码部分
进程是活动(active)实体,程序静止(被动passive)实体
进程在内存,程序在外存
Control Block)
1
2
3
4
5
6
7
8
PCB包含同进程有关的信息,包括:
进程状态
程序计数器
CPU寄存器
CPU调度信息
内存管理信息
计账信息
I/O状态信息

图片 进程调度队列: 作业队列 - 在系统中的所有进程的集合 就绪队列 - 在主内存中的,就绪并等待执行的所有进程的集合 设备队列 - 等待某一I/O设备的进程队列 在各种队列之间进程的迁移 进程终止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
消息传递在微内核中的应用
远程通信无法采用共享内存

发送send(message) - 固定或可变大小消息
接收receive(message)
若P与Q要通信,需要:
建立通信连接
通过send/receive交换消息
通信连接的实现
物理的(如,共享存储,硬件总线)
逻辑的(如,逻辑特性)
消息传递可阻塞(blocking)或非阻塞(non-blocking)
阻塞-同步
阻塞send:发送进程阻塞,直到消息被接收
阻塞receive:接受者进程阻塞,直到有消息可用
非阻塞-异步
非阻塞send:发送进程发送消息并继续操作
非阻塞receive: 接收者收到一个有效消息或空消息
如果通过信箱,则可分为直接和间接通信

线程(轻型进程lightweight process, LWP )是CPU使用的一个基本单元,包括

1
2
3
4
5
6
7
8
调度
线程是调度的基本单位,同一进程中的线程切换不会引起进程切换。
并发
线程可以提高系统的并发性。
资源
进程拥有资源,是资源分配的基本单位,而线程则不拥有资源,但它可以访问创建它的进程所拥有的资源
上下文切换
线程的上下文切换的代价比进程小。

可分为数据并行和任务并行 图片 图片 图片 //S是应用程序的一部分,N是它在N个处理器上串行运行 线程的分类

概念

`需要调度的四种情况

进程调度

等待时间=开始处理时间-到达时间 周转时间=等待时间+处理时间

先来先服务-FCFS

优点:实现简单 缺点:长进程在前会使多个短进程等待过久,增加平均等待时间

短作业优先-SJF

SJF是最优的 – 对一组指定的进程而言,它给出了最短的平均等待时间

抢占式调度

有比当前进程所需时间更短进程到达时,更换目前进行进程 常用于长进程调度,缺点在于进程的cpu区间难以估计 通常用指数平均估计

非抢占式调度

进程只在结束后让出cpu

优先级调度

基于进程紧迫程度赋予优先级,cpu分配给最高优先级进程 优点 实现简单,考虑了进程的紧迫程度 灵活,可模拟其它算法

`问题

响应比高者优先调度

响应比=(开始时间-到达时间)/运行时间

轮转调度-RR

将较小的时间单元定义为时间片,就绪队列为循环队列,调度程序循环整个队列,为每个进程分配不超过一个时间片的cpu

多级队列调度

进程分为前台进程(交互进程)和后台进程(批处理进程) 不同类型的进程需要不同策略 交互进程需要短的响应时间 批处理进程需要短的等待时间 ›多级队列梯度系统中存在多个就绪队列,每个队列有自己的调度算法

多级反馈序列-MLFQ

(MultiLevel Feedback Queue Scheduling) 多级队列的延伸 不同:

1
2
3
4
eg.
Q0-RR时间片8ms
Q1-RR时间片16ms
Q2-FCFS

缺点:优先级一开始确定,无法调整

线程调度

区别用户层和内核层 调度线程而不是进程 多对多和多对一模型,线程库在可用的LWP上调度用户层线程 process-contention scope (PCS) 在进程中进行调度竞争 通常由程序员通过优先级设置 内核线程通过system-contention scope (SCS) 在CPU上调度– 系统中统一竞争 一对一模型仅使用SCS,如Windows, Linux

局部调度

[[线程库]]决定哪个线程列入轻量级进程LWP

全局调度

内核决定下一个运行的内核线程

多处理器调度

调度类似单处理器,但需要将任务平均分配

对称多处理器-SMP

单队列多核调度方法(SQMP)

系统有一个就绪队列。当任意一个CPU空闲时,就从就绪队列中选择一个进程到该CPU上运行 优点: 容易从单核调度算法推广到多核/多处理器、 实现简单,负载均衡 缺点: 不具有亲和性 加锁问题

多队列调度方法(MQMP)

系统有多个就绪队列,一般每个CPU一个。每个就绪队列有自己的调度算法,并且每个就绪队列的调度相对独立 优点: 亲和性好 不需要加锁 缺点: 负载不均衡 策略:“偷”进程 每个处理器决定自己调度方式 定期检测每个cpu负载,分配任务给空闲处理器亲和性:进程倾向于在给定cpu上运行

单队列调度

共享队列,分配给不同cpu 不具有亲和性

多队列调度

不同cpu有各自队列 优点:亲和性较好,不需要加锁 缺点:负载不均匀

非对称处理器-ASMP

仅一个处理器处理系统数据结构,减轻共享需求

实时cpu调度

单速速度调度

依照周期倒数分配一个优先级 优点:最大化cpu利用率 缺点:不保证每个进程都赶上截止期限(周期内执行不完)

最早截止期限优先调度-EDF

根据截止时间分配优先级 越早截止期限,优先级越高

比例分享调度

所有应用中分配T股,确保所有进程有固定的cpu时间,如果新加入进程大于T股剩余量,则不允许进入

实例

linux

windows

对共享数据的并发访问可能导致数据的不一致性,需要保证并发进程正确执行顺序的机制 竞争条件:多个进程并发访问同一共享数据

临界区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Peterson算法
do {

  flag [i]:= true;
  turn = j;
  while (flag [j] and turn == j) ;

  critical section

  flag [i] = false;

  remainder section

  } while (1);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
acquire() {  
       while (!available)
          ; /* busy wait */
       available = false;;
    }
   release() {
       available = true;
    }
   do {

    acquire lock

       critical section

    release lock

      remainder section

 } while (true);

互斥锁(自旋锁)

原子执行acquire(),release() acquire:while(!available) waiting; available=false release:available=false

面包店算法

1
2
3
4
5
6
7
8
9
10
11
12
do {
  choosing[i] = true;
  number[i] = max(number[0], number[1], …, number [n – 1])+1;
  choosing[i] = false;
  for (j = 0; j < n; j++) {
  while (choosing[j]) ;
  while ((number[j] != 0) && (number[j,j] < number[i,i])) ;
  }
  critical section
  number[i] = 0;
  remainder section
} while (1);

信号量(软件解决方案)

1
2
3
4
5
6
7
8
9
信号量S – 整型变量
提供两个不可分割的[原子操作]访问信号量
wait (S):
     while S<= 0 do no-op; 
     S--;
signal(S):
    S++;
wait (S)又称为P(S)
signal(S)又称为V(S)

`分类

1
2
3
4
5
6
7
8
9
例子:P1  和 P2 需要 C1 比C2先运行
       semaphore s=0
P1:
   C1;
   signal(s);

P2:
   wait(s);
   C2;

死锁 – 两个或多个进程无限期地等待一个事件的发生,而该事件正是由其中的一个等待进程引起的. P0  P1   P(S);  P(Q);   P(Q);  P(S);   V(S);  V(Q);   V(Q)  V(S); 饥饿 – 无限期地阻塞。进程可能永远无法从它等待的信号量队列中移去.

实例

生产者消费者问题

生产者 把产品放入指定缓冲区 in:所有的生产者对in指针需要互斥 counter:所有生产者消费者进程对counter互斥消费者 从指定缓冲区取出产品 out:所有的消费者对out指针需要互斥 counter:所有生产者消费者进程对counter互斥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
buffer[in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
counter++;

nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;

生产者:
 {
  …
  生产一个产品
  …
  wait(empty);
  wait(m);
   …
  C1:把产品放入指定缓冲区
   …
  signal(m);
  signal(full);
  }

消费者:
 {
  …
  wait(full);
  wait(m);
   …
  C2:从指定缓冲区取出产品
   …
  signal(m);
  signal(empty);
   …
  消费取出的产品
   …
  }

`同步分析

读者写者问题

两组并发进程读者和写者,共享一组数据区进行读写 `要求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
增加一个读者计数器rc,设置初始值为0;
读者:Repeat
P(mutex);
readcount:=readcount+1;
if readcount=1
then P (w);
V(mutex);//mutex为互斥信号量,初始值为1

P(mutex);
readcount:=readcount-1;
if readcount=0
then V(w);
V(mutex);
Until false


Writers
……
P(W);

V(W);
…...

`问题:写者可能饥饿

哲学家就餐问题

5个哲学家、5根筷子,每个哲学家左右各有一根筷子,每个哲学家只有拿起左右两个筷子才能吃饭 五个元素数组储存筷子,对每个哲学家有拿起左右筷子,放下左右筷子的函数 `防止死锁

方法1

最多允许四个哲学家同时坐在桌子周围

1
2
3
4
5
6
7
8
9
10
11
semephore *chopstick[5];   //初始值为1
semaphore *seat;  //初始值为4
哲学家 i:
  ……
  P(seat);  //看看4个座位是否有空
  P(chopStick[i]);  //拿左边筷子
  P(chopStick[(i + 1) % 5]);  //拿右边筷子
   吃饭
   V(chopStick[i]);  //放下左边筷子
   V(chopStick[(i + 1) % 5]);  //放下右边筷子
   V(seat);  //释放占据的位置
方法2

仅当一个哲学家左右两边筷子都可用时,才允许他拿筷子 哲学家分为三个状态thinking,hungry,eating 设置5个信号量代表所有哲学家,仅当自身hungry且左右都不在吃饭时才开始eating

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void test(int i);
    {
        if (state[i] == hungry) &&  //是否饿了
          (state[(i+4)%5]!=eating) && //左边哲学家是否在吃饭
          (state[(i+1)%5]!=eating)  //右边哲学家是否在吃饭
          {
                 state[i]=eating;  //设置哲学家状态为eating
                 V(ph[i]);  //ph[i]设置为1
           }     
     }
     state[i]=hungry;
            P(m);
            test(i);
            V(m);
            P(ph[i]);
方法3

›给所有哲学家编号,奇数号哲学家必须首先拿左边筷子,偶数号哲学家则反之

信号量总结

S>0:有S个资源可用 S=0:无资源可用 S<0:则|S|表示S等待队列中的进程个数 P(S):申请一个资源 V(S):释放一个资源 互斥信号量初始值:一般为1 同步信号量初始值:0-N `P、V操作成对出现 互斥操作:P、V操作处于同一进程内 同步操作:P、V操作在不同进程内 两个一起的P操作的顺序至关重要 同步与互斥P操作一起时,同步P操作要在互斥P操作前 两个V操作的次序无关紧要

缺点:同步操作分散:信号量机制中,同步操作分散在各个进程中,使用不当就可能导致各进程死锁(如P、V操作的次序错误、重复或遗漏) 易读性差:要了解对于一组共享变量及信号量的操作是否正确,必须通读整个系统或者并发程序; 不利于修改和维护:各模块的独立性差,任一组变量或一段代码的修改都可能影响全局; 正确性难以保证:操作系统或并发程序通常很大,很难保证这样一个复杂的系统没有逻辑错误;

管程

一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据 封装数据以及对数据的操作 确保每次只要一个进程在管程内活动 互斥 管程中的变量只能被管程中的操作访问 任何时候只有一个进程在管程中操作 类似临界区 由编译器完成同步 条件变量 唤醒和阻塞操作 x.wait(): 进程阻塞直到另外一个进程调用x.signal() x.signal():唤醒另外一个进程

问题

管程内可能存在不止1个进程 如:进程P调用signal操作唤醒进程Q后 存在的可能 P等待直到Q离开管程 (Hoare) Q等待直到P离开管程(Lampson & Redll,MESA语言) P的signal操作是P在管程内的最后一个语句 (Hansen,并行Pascal)

内存概念

地址绑定

地址绑定(重定位):把程序中的相对地址转换为内存中的绝对地址的过程 指令和数据绑定到内存地址可在三个不同阶段: ›编译时期( Compile time) 如果内存位置已知,可生成绝对代码 如果开始位置改变,需要重新编译代码加载时期( Load time) 如果存储位置在编译时不知,则必须生成可重定位( relocatable )代码 ›`执行时期( Execution time) 如果进程执行时可在内存移动,则地址绑定可延迟到运行时 需要硬件对地址映射的支持(例如基址和限长寄存器) 大部分操作系统用这个方法

逻辑地址和物理地址

逻辑地址空间的概念同物理地址空间相关联,它是正确内存管理的中心 逻辑地址Logical address 由CPU产生 在进程内的相对地址 也称:虚拟地址、程序地址 物理地址Physical address 内存地址 所有内存统一编址 也称:绝对地址、实地址

内存管理单元

把虚拟地址映射到物理地址的硬件 是CPU用来管理内存的控制线路 在MMU策略中,基址寄存器中的值在其送入内存的时候被加入到由一个用户进程所产生的每个地址中 用户程序所对应到的是逻辑地址,物理地址对它从来都不可见

动态加载和链接

加载 例程在调用之前并不加载 更好的内存空间利用率 没有被使用的例程不被载入 当需大量代码来处理不经常使用的功能时非常有用链接 和各种库文件的链接被推迟到执行时期 需要动态装载技术支持 一小段代码 - 存根,用来定位合适的保留在内存中的库程序 存根用例程地址来替换自己,并开始执行例程 操作系统需要检查例程是否在进程的内存空间,所以需要操作系统支持

交换

一个进程可以暂时被交换(swap)到内存外的一个备份区,随后可以被换回内存继续执行。 备份区—是一个固定的足够大的可以容纳所有用户内存映像拷贝的快速磁盘;必须提供对这些内存映像的直接访问。

1
2
3
4
滚入,滚出(Roll out, roll in )—交换由于基于优先级的算法而不同,低优先级的进程被换出,这样高优先级的进程可以被装入和执行。
交换时间的主要部分是转移时间,总的转移时间直接同交换的内存的数量成比例。
在许多系统如:UNIX,Linux,Windows中,可以找到一些被修正过的交换措施。
系统维持一个就绪队列,它包括在备份存储或在内存中准备运行的所有进程

连续内存分配

为一个用户程序分配一个连续的内存空间

  1. 已分配的分区-已分配分区表   b) 空的分区-空闲分区表

选择孔

碎片

分段

一个程序是一些段的集合,一个段是一个逻辑单位 每个段用段名称和段偏移指定位置 一个逻辑地址是两个向量的集合: <segment-number, offset>

段表 - 映射二维用户地址,每个表项包括: 基址 - 包含内存中段物理地址的起始地址 限长 - 指定段的长度 段表基址寄存器(STBR)指向段表在内存中的地址 段表限长寄存器(STLR)表明被一个程序所使用的段的数目 如果 s < STLR,段号s 是合法的

由于段的长度各不相同,内存分配是一个动态存储-分配问题

`内存分配 首先/最佳适应法 外碎片问题

`重定位 ›动态 ›由段表来执行

`共享 ›共享的段 ›同样的段号

分页

允许进程的物理地址不连续 基本方法:将物理内存分为固定大小的块,称为帧或页帧,逻辑内存分为同样大小的块,称为页或页面 进程物理地址空间可能不连续 如果有可用的物理内存,它将分给进程 把物理内存分成大小固定的块,称为帧(Frame) 大小为2的幂 早期:512字节至8192字节 现在:4K-64K 把逻辑内存也分为同样大小的块,称为页(Page) 系统保留所有空闲帧的记录 运行一个有N页大小程序,需要找到N个空帧来装入程序 建立一个页表,把逻辑地址转换为物理地址 存在内碎片 内存保护 内存的保护由与每个帧相连的保护位来实现 有效-无效位附在页表的每个表项中: ›“有效”表示相关的页在进程的逻辑地址空间,并且是一个合法的页 ›“无效”表示页不在进程的逻辑地址空间中共享代码 如果代码是可重入代码(只读),可以在进程间共享 (如文本编辑器, 编译器, 数据库系统) 共享代码必须出现在所有进程的逻辑地址空间的相同位置
`私有代码和数据 每个进程保留一个代码和数据副本 存有私有数据和代码的页能够出现在逻辑地址空间的任意位置

页表的层次结构

二层页表

内存的保护由与每个帧相连的保护位来实现 有效-无效位附在页表的每个表项中: “有效”表示相关的页在进程的逻辑地址空间,并且是一个合法的页 “无效”表示页不在进程的逻辑地址空间中 图片

哈希页表

虚拟页号被散列到一个页表中。这种页表的每一个条目都包括了一个链表元素,这些元素哈希成同一 虚拟页号与链表中的每个元素相比较,找到匹配项。如果匹配,则相应的物理帧被取出。 虚拟页号与链表中的每个元素相比较,找到匹配项。如果匹配,则相应的物理帧被取出。

反向页表

对于每个真正的内存页或帧有一个条目。 每个条目保存在真正内存位置的页的虚拟地址,以及包括拥有这个页的进程的信息。 `优缺点 减少了需要储存每个页表的内存,但是当访问一个页时,增加了寻找页表需要的时间。 使用哈希表来将查找限制在一个或少数几个页表条目。 实现共享内存困难

段页式原理

分段和分页原理的结合 先将用户程序分成若干个段,再把每个段分成若干个页,并为每个段赋予一个段号 逻辑地址:<段号,页号,页内偏移> 存在内碎片 无外碎片

内存扩充技术

  1. 紧缩Compaction(可变分区)
  2. 覆盖技术Overlaying
  3. 交换技术Swapping
  4. 虚拟内存Virtual Memory

覆盖

解决问题à程序大小超过物理内存总和 程序执行时 ›只在内存中保留那些在任何时间都需要的指令和数据 ›程序的不同部分在内存中相互替换 由程序员声明覆盖结构,不需要操作系统的特别支持 覆盖结构的程序设计很复杂 应用于早期的操作系统

交换

在多道程序环境下,一方面,在内存中的某些进程由于某事件尚未发生而被阻塞运行,但它却占用了大量的内存空间,甚至有时可能出现在内存中所有进程都被阻塞而迫使CPU停止下来等待的情况 另一方面,却又有着许多作业在外存上等待,因无内存而不能进入内存运行的情况 浪费资源,降低系统吞吐量。 一个进程可以暂时被交换(swap)到内存外的一个备份区,随后可以被换回内存继续执行 备份区—是一个固定的足够大的可以容纳所有用户内存映像拷贝的快速磁盘;必须提供对这些内存映像的直接访问 交换(备份区):系统指定一块特殊的磁盘区域作为交换空间(swap space),包含连续的磁道,操作系统可以使用底层的磁盘读写操作对其高效访问

系统模型

资源类型 R1, R2, . . ., Rm CPU周期,内存空间,I/O设备 每一种资源Ri 有Wi  种实例 每一个进程通过如下方法来使用资源 申请,使用,释放 资源动态申请-常用方法 在进程运行过程中申请资源 资源静态申请 在进程运行前一次申请所有资源

必要条件

死锁指一组等待的进程,其中每一个进程都持有资源,并且等待着由这个组中其他进程所持有的资源

资源分配图

被分为两个部分 ›P = {P1, P2, …, Pn}, 含有系统中全部的进程 ›R = {R1, R2, …, Rm}, 含有系统中全部的资源 请求边:有向边Pi->Rj 分配边:有向边Ri->P

死锁处理的分类

预防

›`抑制死锁发生的必要条件

  1. 如果一个进程的申请没有实现,它要释放所有占有的资源
  2. 先占的资源放入进程等待资源列表中
  3. 进程在重新得到旧的资源的时候可以重新开始
  4. 进程申请资源时,如果资源可用则分配,如果不可用,检查资源是否被分配给等待额外资源的其他进程,如果是,抢占资源,否则,申请进程等待

避免

安全状态

当进程申请一个有效的资源的时候,系统必须确定分配后是安全的 如果存在一个安全序列,系统处于安全态 进程序列<P1, P2, …, Pn>是安全的,如果每一个进程Pi所申请的可以被满足的资源数加上其他进程所持有的该资源数小于系统总数 如果 Pi 需要的资源不能马上获得,那么Pi 等待直到所有的Pi-1进程结束。 当Pi-1 结束后, Pi获得所需的资源,执行、返回资源、结束。 当Pi结束后, Pi+1获得所需的资源执行,依此类推。 `定理 如果一个系统在安全状态,就没有死锁 如果一个系统不是处于安全状态,就有可能死锁 避免=>确保系统永远不会进入不安全状态

银行家算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Available:  长度为 m的向量。 如果available[j]=k,那么资源Rj有k个实例有效
Max: n x m 矩阵。 如果Max[i,j]=k,那么进程Pi最多可以请求k个资源Rj的实例
Allocation:  n x m 矩阵。 如果Allocation[i,j]=k,那么进程Pj当前分配了k个资源Rj的实例
Need:  n x m 矩阵。如果Need[,j]=k,那么进程Pj还需要k个资源Rj的实例
Need [i,j] = Max[i,j] – Allocation [i,j].
1.让Work和Finish作为长度为m和n的向量初始化:
Work := Available
Finish [i] = false for i - 1,2,3, …, n.
2.  查找i
(a) Finish [i] = false
(b) Needi £ Work
If no such i exists, go to step 4.
3.  Work := Work + Allocationi
Finish[i] := true
go to step 2.
4.  如果对所有i的 Finish [i] = true, 则系统处在安全状态。

   Requesti =进程 Pi 的资源请求向量.  如果Requesti [m] = k 则进程 Pi 想要资源类型为Rjm的k个实例 1.  如果 Requesti £ Needi 转 step 2.  否则报错, 因为进程请求超出了其声明的最大值 2.  如果 Requesti £ Available, 转 step 3.  否则 Pi  必须等待, 因为资源不可用. 3.  假设通过修改下列状态来分配请求的资源给进程Pi :   Available := Available - Requesti;   Allocationi := Allocationi + Requesti;   Needi := Needi – Requesti;;   •如果系统安全 Þ 将资源分配给 Pi. •如果系统不安全 Þ Pi 必须等待,恢复原有的资源分配状态

死锁检测和恢复

每个资源类型有一个实例:维护进程等待图 每个资源类型有多个实例:用available和finished数组探查是否死锁 允许进入死锁状态并加以恢复 维护等待图 节点是进程 Pi->Pj表明Pi在等待Pj 定期调用算法来检查是否有环 一个检查图中是否有环的算法需要n^2的操作来进行,n为图中的节点数 Available :一个长度为m的向量,表示每一种资源类型可用的实例数目 Allocation:  一个n x m 的矩阵,定义了当前分配的每一种资源类型的实例数目 Request: 一个n x m 的矩阵,表明了当前的进程请求。如果Request[i,j]=k,那么进程Pi请求k个资源Rj的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.  让Work和Finish作为长度为m和n的向量初始化
(a) Work = Available
(b)  For i = 0,2, …, n-1, if Allocationi ¹ 0, thenFinish[i] = false;otherwise, Finish[i] = true.

2.  找到满足下列条件的下标i
(a)  Finish[i] = false
(b)  Requesti <= Work
如果没有这样的i存在,转4

3.  Work = Work + Allocationi
Finish[i] = true
转 2.

4.如果有一些i (0 £ i < n) , Finish[i] = false, 则系统处在死锁状态。而且, 如果 Finish[i] = false, 则进程 Pi 是死锁的。

`算法需要m x n^2 次操作来判断是否系统处于死锁状态

恢复

可以一次中断所有进程排查,也可以一个一个终结进程 选择牺牲进程:最小化代价 回滚:返回到安全的状态,然后重新开始进程 饥饿:同样进程的可能总是被选中。在代价因素中加入回滚次数

虚拟内存概念

局部性原理:在一较短的时间内,程序的执行仅局限于某个部分;相应地,它所访问的存储空间也局限于某个区域 一个程序只要部分装入内存就可以运行 整个程序不是同一时间都要运行 `程序部分装入技术优点 进程大小不再受到物理内存大小限制 每个进程需要的内存更小 更多进程可以并发运行 I/O更少

虚拟页式存储管理

基本思想 进程开始运行之前,不是装入全部页面,而是装入一个或零个页面 运行之后,根据进程运行需要,动态装入其他页面 当内存空间已满,而又需要装入新的页面时,则根据某种算法置换内存中的某个页面,以便装入新的页面请求分页(按需调页) 只有在一个页需要的时候才把它换入内存 需要很少的I/O 需要很少的内存 快速响应 多用户 懒惰交换:只有在需要页时,才将它调入内存 交换程序(swapper)对整个进程进行操作 调页程序(pager)只是对进程的单个页进行操作

有效无效位

每一个页表的表项有一个有效- 无效位相关联: 1表示在内存,0表示不在内存 在所有的表项中,这个位被初始化为0 一个页表映象的例子

缺页中断的处理

1.访问指令或数据 2.查看另一个表来决定: 无效引用 Þ 终止 仅仅不在内存 3.找到页在后备存储上的位置 4.得到空的页框,把页换入页框 5.重新设置页表,把有效位设为v 6.重启指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
极端情况:进程执行第一行代码时,内存内没有任何代码和数据
›进程创建时,没有为进程分配内存,仅建立PCB
›导致缺页中断
›纯请求分页(纯粹按需调页)

一条指令可能导致多次缺页(涉及多个页面)
›幸运的是,程序具有局部性(locality of reference)

请求调页需要硬件支持
›带有效无效位的页表
›交换空间
›指令重启

缺页率(缺页的概率):0 <= p <= 1.0
›如果 p = 0 ,没有缺页
›如果 p = 1, 每次访问都缺页

有效访问时间( EAT )
    EAT = (1 – p) x 内存访问时间+ p x 页错误时间

页错误时间=处理缺页中断
  + [页交换出去时间 ]
  + 读入页时间
  + 重启进程开销

性能优化: 页面转换时采用交换空间,而不是文件系统 ›交换区的块大,比文件系统服务快速

在进程装载时,把整个进程拷贝到交换区 ›基于交换区调页 ›早期的 BSD Unix

利用文件系统进行交换 ›Solaris和当前的BSD ›部分内容仍旧需要交换区(堆栈等) 写时复制:允许父进程和子进程在初始化时共享页面 ›如果其中一个进程修改了一个共享页面,会产生副本 ›更加高效 ›应用在Windows,Linux,macOS等系统

需要页置换的情况

页置换—找到内存中当前没有使用的一些页,换出 同一个页可能会被装入内存多次 基本页置换方法

  1. 查找所需页在磁盘上的位置
  2. 查找一空闲帧 如果有空闲帧,就使用它 如果没有空闲帧,使用页置换算法选择一个“牺牲”页框 将“牺牲”帧的内容写到磁盘上,更新页表和帧表
  3. 将所需页读入(新)空闲帧,更新页表和帧表
  4. 重启用户进程

如果发生页置换,则缺页处理时间加倍 使用修改位modify bit或脏 (dirty bit) 来防止页面转移过多—只有被修改的页面才写入磁盘 页置换完善了逻辑内存和物理内存的划分—在一个较小的物理内存基础之上可以提供一个大的虚拟内存

页面置换算法

先进先出(FIFO)算法

置换在内存中驻留时间最长的页面 容易理解和实现、但性能不总是很好 实现:使用FIFO队列管理内存中的所有页 FIFO算法可能会产生Belady异常 更多的页框 =>更多的缺页

最优置换算法OPT

被置换的页是将来不再需要的或最远的将来才会被使用的页 实现? 作用:作为一种标准来衡量其它算法的性能

最近最少使用算法(LRU)

置换最长时间没有使用的页 性能接近OPT 实现:计数器(时间戳)或栈 开销大、需要硬件支持 栈实现—在一个双链表中保留一个记录页数目的栈: 被访问的页: 移到栈顶 需要改变6个指针 没有为置换进行查找

在没有硬件支持的系统中,可使用LRU近似算法访问位 每个页都与一个位相关联,初始值为0 当页访问时设位1

二次机会算法

需要访问位 如果访问位为0,直接置换 如果将要交换的页访问位是1,则: 把访问位设位0 把页留在内存中 以同样的规则,替换下一个页

实现:时钟置换(顺时针方式)

基于计数的页面置换

用一个计数器记录对每一个页的访问次数 LFU 以最小的计数置换一个页

页面缓冲算法

  1. 总是保留一个空闲帧缓冲池
  1. 扩展之一,维护一个修改页面的列表
  1. 另一种修改,保留一个空闲帧池,并且记着哪些页面在哪些帧内

帧分配

两种主要分配策略

固定分配

平均分配 Equal allocation– 例如,如果有100帧和5个进程,给每个进程20帧 在缓冲池里保存空闲帧 比例分配 Proportional allocation – 根据进程大小分配内存 按照多道程度而动态分配,进程分得的数量变化

优先级分配

优先级分配:用优先级而不是大小来进行比例分配
如果进程 Pi 跑出页面错误, 从自己的帧里选择一个替代 从优先级较低的进程里选择一个替代

全局 vs. 局部分配

全局置换 Global replacement – 允许进程从所有帧的集合中选择一个置换帧;一个进程可以从另一个进程那里获取帧 但是进程执行时间可能变化很大,不能控制缺页错误率 有更好的系统吞吐量,更常用 局部置换 Local replacement – 每个进程只从它自己分配的帧中进行选择 对每个进程的表现更一致 但是可能内存低利用

非均匀内存访问(NUMA)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
v以上假设所有内存可以被平等访问

v很多系统如 NUMA – 内存访问速度变化的

›考虑CPU和内存在系统中通过总线互连

v让分配的内存帧‘尽可能地靠近’运行进程的CPU

›通常意味着位于同一系统扳

›Solaris通过在内核中创建延迟组 lgroups

v将相近的CPU和内存聚集在一起

v在组内调度进程的所有线程,并分配它的所有内存

v最大限度减少总体内存延迟,最大化CPU缓存命中率

抖动

如果一个进程没有足够的页,那么缺页率将很高,这将导致: CPU利用率低下. 操作系统认为需要增加多道程序的道数 系统中将加入一个新的进程 颠簸(抖动)=一个进程的页面经常换入换出 原因:分配的帧数 < 局部大小之和

工作集模型

工作集窗口 º 固定数目的页的引用 WSSi (进程Pi的工作集) = 最近D中所有页的引用 (随时间变化) 图片 vExample: D = 10,000

›每5000个时钟单位时钟中断

›为每个页在内存中保留两个位

›任何时候一个时钟中断拷贝,把所有访问位设为0

›如果一个在内存中的位是0,说明页在工作集

内存映射文件

通过映射一个磁盘块成内存的一页,内存映象文件I/O 允许文件I/O 作为普通内存访问。 开始的文件访问按普通请求分页来进行,一页大小的部分文件从文件系统读入物理页。以后文件的读、写操作就按通常的内存访问来处理。 由于通过内存的文件操作而不是使用系统调用read() write() ,简化了文件访问和使用。 多个进程可以允许将同一文件映射到各自的虚拟内存中,以允许数据共享

内核内存分配

通常从空闲内存池中获取 ›内核需要为不同大小的数据结构分配内存 ›一些内核内存需要连续的物理页

1
2
3
4
5
6
7
8
9
10
11
12
13
v内核在使用内存块时有如下特点:

    (1)内存块的尺寸比较小;

    (2)占用内存块的时间比较短;

    (3)要求快速完成分配和回收;

    (4)不参与交换。

    (5)频繁使用尺寸相同的内存块,存放同一结构的数据;

    (6)要求动态分配和回收。

伙伴(Buddy)系统

v主要用于Linux早期版本中内核底层内存管理 v一种经典的内存分配方案 v从物理上连续的大小固定的段上分配内存 v主要思想:内存按2的幂的大小进行划分,即4KB、8KB等,组成若干空闲块链表;查找链表找到满足进程需求的最佳匹配块 ›满足要求是以2的幂为单位的 ›如果请求不为2的幂,则需要调整到下一个更大的2的幂 ›当分配需求小于现在可用内存时,当前段就分为两个更小的2的幂段,继续上述操作直到合适的段大小 `算法 ›首先将整个可用空间看作一块: 2^n ›假设进程申请的空间大小为s,如果满足 2(n-1)<s<=2n,则分配整个块    否则,将块划分为两个大小相等的伙伴,大小为2^(n-1) ›一直划分下去直到产生大于或等于s的最小块

Slab 分配

v内核分配的另一方案 vSlab 是由一个或多个物理上连续的页组成 vCache 含有一个或多个 slab v每个内核数据结构都有一个cache 每个 cache 含有内核数据结构的对象实例

v当创建 cache 时, 包括若干个标记为空闲的对象 v当内核对象时,从cache上直接获取,并标识对象为使用 v当一个slab充满了已使用的对象时,下一个对象的分配从空的slab开始分配 ›如果没有空的slab, 则从物理连续页上分配新的slab v优点 ①没有因碎片而引起的内存浪费

②内存请求可以快速满足

杂项

预调页面 v在进程启动初期,减少大量的缺页中断 v在引用前,调入进程的所有或一些需要的页面 v如果预调入的页面没有被使用,则内存被浪费页面尺寸大小 v碎片 – 需要小的页 v表大小 – 需要大的页 vI/O 开销 – 需要大的页 v程序局部 – 需要小的页 v缺页次数 – 需要大的页 v其他因素 没有最佳答案,总的来说,趋向更大的页 TLB 范围 vTLB 范围 – 通过TLB所访问的内存量 vTLB 范围 = (TLB 大小) X (页大小) v理想情况下,一个进程的工作集应存放在 TLB中 ›否则会有大量的缺页中断 v增加页的大小 ›对于不需要大页的应用程序而言,这将导致碎片的增加 v提供多种页的大小 ›这允许需要大页的应用程序有机会使用大页而不增加碎片的大小倒置页表 v倒置页表降低了保存的物理内存 v不再包括进程逻辑地址空间的完整信息 v为了提供这种信息,进程必须保留一个外部页表 v外部页表可根据需要换进或换出内存 `I/O 联锁与页面锁定 v允许某些页在内存中被锁住

vI/O时,正在进行I/O的页面不允许被置换算法置换出内存 linux vSLAB vDemand paging vGlobal page replacement(LRU) v两个帧列:active_list和inactive_list vKswapd daemon 定期检查windows10 vBoth IA-32 and x86-64 v32bit支持4GB,64bit支持128TB内存 vShared memory, demand paging, copy-on-write, paging和memory compression v按需调页-clustering,预调入3-7页 vWorking-Set 管理(最少50-最多345页)

文件概念

文件 ›计算机中信息存储的基本组织形式 ›相关信息结合 ›具有文件名文件名 ›按名存取:文件名     存储位置 ›文件名由一串ASCII码或(和)汉字构成 ›名字长度 v8.3规则:文件名8个字符,类型3个字符,之间有“.”分割 v长文件名:可以最多输入255多个字符作为文件名 ›文件名可能大小写敏感 文件的打开 v需要数据结构 ›打开文件表:跟踪打开文件 ›文件指针:指向最后一次读写的位置,每个进程1个 ›打开文件计数器:打开文件次数(调用open次数) ›文件存储位置:文件存放在存储设备上的位置信息 ›访问权限:每个进程的访问权限 v优点 ›方便文件共享 ›提高文件存取效率文件锁 ›共享锁 Shared lock 类似于读者锁– 多个进程可以并发获取它。 ›独占锁 Exclusive lock 类似于写者锁 `文件结构 v目的:便于程序理解文件内容 ›无结构:文字流、字节流等 ›简单记录结构:线性、固定长度、可变长度等 ›复杂结构:格式化文档、多媒体文件等 v谁决定了文件结构 ›操作系统 程序

文件访问

逻辑文件

v文件呈现在用户面前的组织结构 v又称为文件逻辑结构 v逻辑文件决定了文件访问方法 `文件访问方式 - 顺序访问 ›最简单的访问方式 ›文件信息按照存放顺序,一个记录一个记录地依次访问 ›顺序文件 ›典型存储设备:磁带 - 直接(随机)访问 ›可以直接定位到文件的某条记录进行访问 ›直接文件 典型设备:磁盘 v访问方式:直接(随机)访问 v直接通过计算得到需要读写记录的位置,直接跳转进行文件读写 - 索引文件 v基本方法:为顺序文件建立索引表

1
2
3
4
5
6
7
8
9
10
11
12
13

记录平均长度:40B   索引表项大小:4B   1M条记录长度:44MB

访问第1万条记录:

       1)计算得到第1万条记录的索引项在索引表中首址:10000*4=40000

       2)从索引表地址40000处读入4个字节,内容为第1万条记录在顺序文件中的首址P

       3)从顺序文件地址P处读入40个字节(假如第1万条记录长度为40B)

合计读入:4+40=44B

目录结构

文件控制块(FCB)

存放操控文件所需的各类文件属性信息 ›文件名 ›长度 ›创建时间 ›存放位置 ›访问控制权限 类似一个索引项 v目录项 ›存放一个文件的各类属性 ›有的系统等同于文件控制块 v目录 ›包含着所有文件信息的节点集合 ›根据文件名检索文件的桥梁 ›目录项的有序集合 v目录文件 ›目录组织形式 ›目录作为一个文件存在于文件系统 v每个目录项中存放了文件在存储设备的存放地址 v目录和文件都驻留在存储设备(如磁盘)

文件检索

v文件检索是一个遍历目录项的过程 1.打开目录文件 2.从磁盘读入该目录文件的1个(物理)块,该块包含若干个目录项 3.根据文件名遍历内存中的该块,如找到则结束 4.判断该目录文件是否还有物理块没有读入,如果是转2;否则,结束。表示该目录中没有此文件名的文件 v目录项由于经常变化,一般不排序 v平均遍历目录项数:       (1+n)/2   不包括文件查不到的情况   ›   目录项大小= ds bytes ›目录中最多文件数 = n ›物理块大小 = b v那么 ›目录文件大小 = ds*n bytes ›目录文件需要的物理块数目 = ds*n/b 检索一个文件需要平均读入的块数=(ds*n/b+1)/2

目录结构

设计目标 v效率 ›快速定位文件位置 ›提高文件访问效率 v命名 ›方便用户使用 ›同名的不同文件 ›不同名的相同文件 v分组 ›文件分组(子目录) ›兼顾效率和方便性单层目录 v所有文件在同一目录中,只有一级目录:根目录 v根目录(/):一个文件系统最顶层的目录 v优点:结构简单 v缺点 ›检索效率差(目录下文件过多) ›不能有同名文件,一个文件只能有一个名称 ›不能分组 双层目录 v每个用户有自己的目录结构 v目录下的目录 v缺点:1)无法分组;2)同一用户不能有相同文件名的文件 v优点:1)不同用户可有相同文件名的文件;2)比单层目录提高检索效率(文件分布在多个用户目录中)树形目录 v特点 ›检索高效(子目录增多导致每个目录下文件减少) ›可以分组 ›允许重名 v当前目录:工作目录 ›cd /spell/mail/prog ›type list v绝对路径 ›从根开始的路径名 v相对路径 ›从当前目录开始的路径名 ›提高检索效率 (有向)无环图目录 v文件共享:不同目录中的文件指向同一个物理文件,也就是它们内容相同 v树型目录不能实现文件共享 v解决方法:图型目录 ›无环图目录 ›通用图目录(有环图) v无环图:有向边无环如何保证无环? ›仅允许指向文件的链接,不允许指向子目录的链接 ›垃圾回收 ›每当加入新链接时,使用环路检测算法判断是否正确 ›优化遍历目录算法,避免对环的重复搜索

杂项

v要访问一个文件系统,必须先安装它。 一个未安装的文件系统将被安装在一个安装点(mount point)上。

远程文件系统

v用网络使得远程计算机之间的联系成为可能 ›手动传输文件如 FTP ›自动,直接访问文件用分布文件系统 distributed file systems ›半自动用万维网 world wide web vClient-server 客户机-服务器模型允许客户机登录远程服务器的文件系统 ›服务器可以服务多台客户机 ›识别客户可能是不安全和复杂的 ›NFS 是标准 UNIX 下客户机-服务器的文件共享协议 ›CIFS 是Windows下标准协议 ›标准操作系统文件调用翻译为远程调用 v分布式信息系统 (分布式命名服务 distributed naming services) 如LDAP, DNS, NIS。

故障

v所有文件系统都有故障模式 ›例如目录结构或者其他磁盘管理信息(元数据 metadata 损坏。 v远程文件系统加入新的故障模式,来自网络故障或者服务器故障 v从故障中恢复包含维护状态信息 state information vStateless 无状态协议如NFC在每个请求里包含所有信息,允许较为容易的故障恢复但是不够安全

共享

v规定系统的多个用户如何访问共享文件 ›类似于第六章的进程同步算法 v由于磁盘和网络的巨大延迟和很慢的传输速率,倾向于没这么复杂 ›Andrew File System (AFS) 实现了复杂共享语义 ›Unix file system (UFS) 使用: v一个用户对已打开文件的写入,对于打开同一文件的其他用户立即可见。 v一种共享模式允许用户共享文件的当前位置指针。 ›AFS 有会话语义 v一旦文件关闭,对其所作的更改只能被后来打开的会话可见。

访问控制权限和分组

v访问模式:读/写/执行 v三种类型的用户   RWX   a) 所有者  7  =>1 1 1    RWX   b) 组用户  6  =>  1 1 0 RWX   c) 公共用户  1  =>  0 0 1 v建立一个组,加入一些用户 v对特定的文件或目录(game) ,定义适当的访问权限

]]>
- <p>我本以为影子工厂会如简介说的一样,会是杂糅诸多风格的悬疑风,故事的一开始也的确如此,时间穿越配合豪宅血腥谋杀的经典模式别有一番风味,不过结合前传一贯的发展,不难想象出而在这之后又回到了我们熟悉的时间轴环节,比较特殊的是,这次高瞰老师罕见地采用了正叙的方式,而且此次的故事出奇的平淡,尽管感情上依旧无比细腻,但几乎没有什么出乎意料地发展。 + <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">计算机系统可以分为四个部分</span><br><span class="line">硬件(Hardware) – 提供基本的计算资源</span><br><span class="line">CPU, memory, I/O devices</span><br><span class="line">操作系统(Operating System)</span><br><span class="line">控制和协调各用户的应用程序对硬件的使用</span><br><span class="line">应用程序(Application programs) – 规定了用户按何种方式使用系统资源</span><br><span class="line">字处理程序, 编译器, 网络浏览器, 数据库系统, 视频游戏</span><br><span class="line">用户(Users)</span><br><span class="line">人, 机器, 其他计算机</span><br><span class="line">操作系统的目标:</span><br><span class="line">运行用户程序  ---核心目标</span><br><span class="line">更方便使用计算机 ---面向用户</span><br><span class="line">更高效使用计算机 ---面向系统</span><br></pre></td></tr></table></figure> - + - + - + - + + +
@@ -853,29 +854,30 @@ - blacksouls人物解析 - - https://thinklive1.github.io/2023/09/29/black%20souls%E4%BA%BA%E7%89%A9%E8%A7%A3%E6%9E%90/ - 2023-09-29T02:18:45.993Z + 基于c++ primer plus的读书笔记 + + https://thinklive1.github.io/2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ + 2023-10-05T14:45:42.281Z 2023-11-27T12:47:59.687Z - 尸龙贾巴沃克
1
在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!

象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),尸龙姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对尸龙的整个人物进行解析 尸龙在爱丽丝镜中奇遇的原型是一首小诗,这首诗的大意是勇者手提沃伯尔之剑斩杀邪龙贾巴沃克,游戏中也承袭了这一设定,贾巴沃克一直都以死尸的形象登场 要解析这一角色,我们首先从最直接的行为说起,按游戏的时间线,尸龙姐姐大概做了以下这些事 1把童话(具体哪本未知,根据混沌迷宫的狼外婆信息推测可能是小红帽)给了渴望母爱的玛丽.苏,从而激发了虫虫的创作能力,导致她创造出一代的箱庭。顺便一提,关于尸龙玛丽苏的关系,游戏里没有直接证据支持姐妹说,混沌迷宫提到黑山羊有两个子嗣,米兰达认为尸龙有黑山羊的气息,且明显尸龙玛丽苏有一定关系,这些是确定的,但并未明说姐妹,有人从克苏鲁的设定中寻找论据,但本人对克系了解不多在此不评价。 2红偶像约会中电影《三人的茶会》提及茶会时期的三人曾经打倒过贾巴沃奇,不知是否和尸龙有关,此外尸龙也曾被昔日的勇者,如今的猎头兔打倒,自称在之后洗心革面,但相关资料太少,我们不知道是不是她放水或另有隐情 3格林被引导进玛丽苏的箱庭开始一代的故事,此时尸龙(不知道玛丽苏是否知情)已经乱入到一代的不思议之国,为格林一行人提供帮助,通关d结局后找她对话,她会直接把二代给剧透了,不过由于时间线上d结局应该直接接上二代,所以“正史”上可能没有这件事,顺便一提,一代的不思议之国是爱丽丝的箱庭,或者说玛丽苏的仿造品,也没有定论,所以很难推测尸龙是入侵还是本来就在那里 4来到二代时间线,由于不思议之国是奈亚的箱庭,而黑山羊则是奈亚的“配偶”,所以尸龙出现在这倒是理所应当,此时的尸龙以四噩梦之一的身份登场,,但工作内容则是在卡罗尔川上堆雪人,以及在格林面前装出温柔大姐姐的形象,十足的关系户做派。 里路线中,格林和米兰达等人可以先后对战三噩梦,以及杀死其余两个噩梦后现出真身的尸龙,值得一提的是这似乎是她全系列中唯一一次全力出手,并且在此战中死亡,但考虑到支配者的特性,是否死透了依旧存疑 以上就是尸龙在系列中的行动,接下来我将对这些行动的目的与尸龙的性格进行归纳。 尸龙首先是一个安静的观察者,一代中她只是在一棵树下扮尸体,二代则在河边堆雪人,如果格林不找她,在里线之前不会和她有任何交集,然而,隐藏和善表面下的真相是尸龙其实是个性格扭曲唯恐天下不乱的乐子人,是她启发了玛丽苏创造自己的黑童话箱庭,间接引发之后所有的故事,而一开始的目的可能只是以玛丽苏面对求而不得的母爱痛苦挣扎的样子为乐,也是她诅咒了狩猎邪龙的英雄,使兔子一族成为贪食尸体的魔兽,其中被沃波尔斩下头颅可能是她行事风格的分界线,其自述死前曾是无恶不作的邪龙,在复活后变得收敛,但其实依旧不改邪龙本质,只是变得只在关键时刻推波助澜 而将这两种性格统一起来的则是她的创作欲,没错,和玛丽苏一样,尸龙对创作也有自己的执念,在玛丽苏涌现起黑暗的创作力之后,尸龙意识到,玛丽苏那邪恶的灵魂一定程度其实是自己的作品,如果说玛丽苏是支配者中第一个创造故事的人,尸龙就是第一个“创作者”,这激发出她内心最深层的欲望,那就是创作出足够黑暗污秽的灵魂,方法则是让一个灵魂在无尽的痛苦与求而不得中循环。 可以说在这点上尸龙和奈亚有一定的共同点,就是让格林经历无数次的痛苦循环,但二者还是有着分歧,奈亚想要的是格林求而不得的爱,尸龙则想要格林本就污秽的灵魂更加黑暗。 这时我们就可以理解尸龙的行为了,由于里线实际上也处于轮回之中,所以对尸龙来说,告诉格林一些真相只会让他的反抗更加激烈,也会在反抗之后更加绝望,这样才符合她的目的。 而以上依旧是贾巴沃克的表层性格,而她隐藏最深的性格则是扭曲的独占欲,在卡罗尔川的地牢中有个四个雪人,分别是玛丽苏,小红帽,爱丽丝和格林,此外,班达斯奈奇的住处也有着一个写着想将其变为收藏品的雪人(sen0才能看到真相),可见尸龙内心最深的欲望其实是独占欲,培育最污秽的灵魂,随后将其收藏起来,这才是尸龙的愿景,但她为何要隐藏这一欲望呢,在qf尸龙失败的逆监禁剧情里,由于尸龙发现格林的灵魂已经黑暗到想要独占自己,尸龙就会唯一一次直接暴露自己的独占欲来收割这个丰硕的成果,然而,奈亚或者其他支配者绝不会容忍这种行为,所以一旦尸龙试图独占格林就会立刻被排除出世界,这就是尸龙一直压抑着独占欲的原因。 此外,根据dlc3入口处的对话以及数量庞大的雪人,或许可以猜测尸龙曾经一边观察一边玩弄过很多灵魂,但这些灵魂最后都因为经历过多的痛苦和绝望后变得麻木,因此才会对有着无穷成长性的格林视若珍宝 一切温柔的言语都不过是为了将格林引导向更绝望的结局,独占污秽的黑之魂,玩到腻后就扔掉,对贾巴沃克之魂的描述为包藏在虚伪的母性之下的独占欲之影可谓恰如其分。 值得一提的是,独占欲这种感情不止在尸龙一人上出现,大部分支配者都有着这种感情,如白之女王诺登就承认自己多次有独占格林的想法,爱丽丝01也曾吐露自己害怕不可控制地想要独占格林,但她们与尸龙的区别则是,她们能够理解人类的爱,并为了人类的幸福选择放手,与红白女王的对比或许也是尸龙人物形象设计的一个目的 现在可以做一个总结了,尸龙姐姐是一个对格林有着强烈爱意的角色,她的母性是虚伪的,但这种爱意却不是,尽管她扭曲,残酷,自私,虚伪,但是她始终知道自己要做什么并理性地付出行动,即使失败了也不失风度从容自若,相较于虫虫几乎写在脸上的扭曲性格,直截了当的作恶行径,以及一有挫败就大呼小叫的行径,尸龙的感情更加内敛,行事也更加隐秘,但可谓是个很有恶人魅力的反派角色 同时,由于bs的碎片化叙事并且尚未完结,关于尸龙依旧有很多谜团,例如她和玛丽苏以及其他支配者的具体关系,里线中她是不是仍然在演戏,她究竟为何会给玛丽苏童话书,尸龙等三噩梦和三个爱丽丝的关系等等,就期待续作的解答了 大家都来和尸龙姐姐做朋友吧,尸门

玛丽苏

玛丽苏,作为bs中自称的女主角,是bs唯二个三代都有出场(包括红森)的支配者,还有一个是贾巴沃克),在此过程中做过的好事可谓数不胜数,罄竹难书,我们来按着时间线整理一下 1一开始的玛丽苏是个渴望母爱的孩子,尽管我们不知道bs设定下一开始的支配者到底会不会有类似人类的亲情,她掌管自己的世界,倾听子民的祈祷,开始感到厌烦,这时贾巴沃克不知出于什么目的,送了她一本童话书,这本书,我们不知道是哪个童话,但本人猜测很可能这本书的作者是玛丽苏第一个抓住的,并在黑之魂的融合中有重要地位,根据青鸟的文本,卡罗尔并不是第一个抓住的素材,所以基本可以排除梦游仙境,结合男主角格林的名字和混沌迷宫的狼外婆,我个人猜测是小红帽,她开始渴望创作自己的故事来打动母亲,至少一开始是这样,她派遣属下四处收集童话作者的灵魂作为素材,同时肆意进行同人创作。 2玛丽苏的处女作是小红帽,也是她第二得意的作品,根据一些信息,小红帽的灵魂可能以现实世界的一个女学生为素材,在魔改剧情的同时,她还给了小红帽注定20岁早逝的设定,并可能赋予了小红帽通过镜子穿梭位面之类的特殊能力来担任女主角,但不知道为什么她又不满意,想做一个男主角出来,但她对小红帽的善后却颇有些问题,小红帽不仅杀穿了红森,而且还能意识到她这个黑幕的存在。 3缝合了众多童话作家灵魂的格林诞生了,并被赋予了给周围的女主角带来不幸的设定,格林污秽的黑之魂有成为支配者的潜质,玛丽苏甚至还大胆地保留了他的部分创作能力,因为最关键的改变权能在她手上,为什么叫做格林则未知,可能是最初的童话书就是格林童话的一本,这之后格林不知道为什么,以什么身份在一个叫不思议之国的地方和叫爱丽丝和祈祷主的存在开起了茶会,随后格林与爱丽丝01相恋,嫉妒的祈祷主呼唤了玛丽苏,导致格林被带走了,连同格林不知何时创造出的故事们也被篡改 4基于以上提到的各种童话故事素材,玛丽苏魔改出了失落帝国的箱庭,把格林放进去经历一次次绝望故事的轮回,自己则担任女主角欣赏故事,还设计把母亲叫了进来欣赏自己的大作。不知多少次循环后,这个大好局面被打破了,母亲黑山羊为了逃离这个世界和她战斗,连圣森都磨灭了,战胜母亲后,奈亚丽丝前来捡漏带走格林进行新一轮追寻爱的游戏,本来想顺带着把玛丽苏也灭了,但在诺登的劝阻以及可能的其他考量下放过了她 5奈亚,红女王,白女王中的某位或若干位剥夺了她的改变权能,把她囚禁在库因兰德,失去权能的她改名为玛丽安,但不知何时也不知何人前来探访了她,到格林试图从梦中醒来的里线,玛丽安乘乱逃出,由于正史上不太可能发生f结局,所以此时应该是g结局,也有可能正史上g结局有少许与游戏不同,不管怎么说此时的玛丽安应该被格林小红帽两人打败,但h结局中可以看到她没有死,而且不知道怎么逃了出来 可以说,bs中的一切悲剧,玛丽苏至少有五成功劳,接下来让我们来分析一下玛丽苏的角色特质。 首先,最直接的一点,玛丽苏是个典型的支配者,高高在上地支配着人类这样的低等种族,但玛丽苏特殊之处在于,她可能是最能理解人类感情的支配者之一,首先我们就可以看到她居然渴望所谓的母爱,而根据2代大部分支配者的表现,即使因融入皮套逐渐有了感情,也没有第二个有亲情这种非常类似人类感情的支配者,此外,她还以玩弄人类的灵魂为乐,当然有这种兴趣的支配者恐怕不少,但这股风气可以说是玛丽苏带起来的,也是她最先玩出各种花样。 因此可以引出玛丽苏的第二个特点了,她是很像人类的一个支配者,尽管理解非常片面,但她确实懂得并拥有不少人性,而她为什么这么喜欢玩弄人类呢?这也很容易理解,一般来说越通人性的动物越被人类亲近,逗猫逗狗远远比逗蚂蚁有意思,因为这些宠物的智力和人类更接近,人类可以很容易地理解它们在想什么,然后在逗弄它们的过程中获得一种智力上的优越感,以及一种“支配感”,这恐怕就是玛丽苏看到自己编排的好戏上演的感觉。 这点可以说是我们对玛丽苏进行解析的基石,毕竟任何角色首先都是人的投影,而人性越丰富,就有越多的性格侧面。 玛丽苏第三个特点就是由此衍生的纯粹性,当然,此处并不是说纯洁善良云云,而是某种意义上的纯粹之恶,很多支配者在扮演人类后都会被皮套影响而恐慌或纠结,但玛丽苏却没有这种烦恼,她以融入人类扮演人类为乐(小精灵也算类人种族),她作为支配者的漆黑本性和人性之恶完美地兼容了,不会有徘徊二者之间的身份认同问题,而她大部分所作所为也就是为了践行人性之恶,什么是恶呢,比较狭隘的解释就是为了为了自己的利益或者取乐而伤害他人,而玛丽苏的邪恶就很纯粹,就是为了取乐,甚至有损自己利益也要作恶,如果解救了被囚禁的玛丽苏,此时她会自认为东山再起,但她想的不是第一时间抹杀已经成长了的格林或者藏起来,而是想再让格林经历一次悲惨的故事,可以说她作恶的动机相当纯粹,也相当执着。 在此之上的第四个特点,就是她的创作者身份,很多支配者都会赞扬她的创作能力,连奈亚构建的不思议之国都有不少玛丽苏箱庭的影子,但这种创造力也只是对于支配者来说了,如果我们用人类的视角看如何呢?寿司在访谈时轻蔑地说到“她说到底也只是玛丽苏,也只能整点二次创作了”可以说道出了玛丽苏所谓创作的本质,说到底,玛丽苏就是那种典型的黑深残小鬼,把一个可能有很多种解释的作品曲解为单一的猎奇世界观,当然不是说这样不行,如果原创一个黑深残世界观自娱自乐当然是可以接受的,但玛丽苏的行为就是最恶劣的一种同人女行为,魔改原来的作品,把自己做成角色代入进去搞cp,还要把所有其他角色踩一遍,情节和人物关系只要对自己代入的角色有利就行,然后把这部除了自己看谁也不会喜欢的同人拿给原作者看,我就不详细说这种行为的恶劣程度了,但这种作品折射出来的创作观我必须要辩驳一下。 当然,本视频所有讨论只局限于二次元文化内, 荒木飞吕彦认为漫画有四要素,角色、剧情、世界观、主题,我们就用这四个维度来剖析玛丽苏的所谓创作。 首先是角色,直接创作一个鲜活的灵魂对强大的支配者来说也是一件难事,所以对于角色的选取,玛丽苏很可能都是使用现实存在的灵魂然后再魔改来适配进童话或者传说的人物,因此她笔下所谓角色虽然很多但其实并不是她自己的功劳,而她为了把这些灵魂塞进角色对设定随意删改,把小红帽的外婆和母亲缝成了一笔烂账,人物关系更是一团乱麻,怎么方便怎么来,角色设定连基本的自洽也做不到,水平着实不敢恭维 随后是世界观,失落帝国这个箱庭本质上来说就是个童话故事的缝合体,没有历史演化,没有详细设定,这并不是一个鲜活的世界观,只不过是一个临时搭建的舞台而已,当然,很多线性的故事并不需要一个多详尽的世界观,在这点上玛丽苏只能说无功无过 最后是剧情和主题,玛丽苏的主题是简单粗暴的黑深残,剧情则是当常规的rpg剧本演到最后的happy end时毫无铺垫伏笔地急转直下变成bad end,当然,能设置这么大规模的箱庭,还写了不少支线剧情,证明玛丽苏确实是有一些笔力的,但首先,她的角色基本靠抓人,故事则都有童话原型,故事演变她只需要把握大方向,其他可以让角色自己来,而最后没有任何铺垫的bad end依旧表明了她创作的失败,如果一个设定没有任何铺垫和暗示,直到使用时才抛出,那只能证明这部作品情节编排的失败,因为一部作品的生命周期不是作者创作出来就结束了的,而要等到读者看完理解了故事才会结束,这个过程作者读者应该处于相对公平的地位,根据故事的设定,人物有充分的理由这样行动,这样才能让读者认同这个故事,而玛丽苏却完全相反,滥用作者的权能让故事不仅没有逻辑,还自相矛盾,很明显,对玛丽苏来说她是作者也自认为是唯一的读者,那些被抓走被改造的灵魂不过是用完即扔的工具罢了,不需要自圆其说,只要自己看得高兴就行了,或许就支配者的立场来说她不过是自娱自乐罢了,但对人类(至少灵魂上是人类),以及同样作为创作者的格林来说,首先就绝不可能认同这种恶行,更不可能认同自己的作品被改成这样的烂作 说到这里,就可以讨论一下玛丽苏对于格林的看法了,直观地说,是玛丽苏创造了名为格林的污秽黑之魂,但其实在最初,是格林等童话作家激发了玛丽苏的创作欲,因此,事实上,两者是相互创造的关系,玛丽苏创造格林的目的,首先是为了成为她作品的男主角,让她能够代入女主角的位置欣赏这个故事,这样说来似乎格林除了男主角的身份和其他角色也没什么本质的不同。但格林还有一点对玛丽苏有着重大意义,就是他童话作家灵魂集合体的身份,即使自我中心如玛丽苏这种存在,也会有对别人欣赏自己作品的渴望,因此玛丽苏特地设置了一个c结局,用演戏的形式让格林得以了解她的整个创作生涯,至于目的,除了单纯的表现欲和欣赏格林的痛苦以外,恐怕也有一丝希望作为原作者的格林认同自己的心情,哪怕是厌恶,玛丽苏也想得到一些对创作的反馈,而格林是唯一能在创作这个领域和她有一些共鸣的人,作者,读者,男主角,格林三位一体的身份对玛丽苏来说,可以说是难得的知己,尽管这种关系非常扭曲,但不能否认,在这点上玛丽苏作为创作者的心情是有些真心的。而玛丽苏会渴望认同这点,一开始是希望得到母爱,但在得到格林这个玩具之后,玛丽苏就一点也不在意黑山羊的死活了,这也是佐证。 最后不得不提的是,玛丽苏的特殊性质,很大程度上她是寿司这个作者的投影,我个人觉得玛丽苏这个角色有不少表达寿司自己创作观的成分,这也解释了寿司为何这么偏爱她当然,一部好的作品,任何角色都是基于自己的设定和世界观行动,不可能因为是作者的投影就有特别待遇,所以可以说,玛丽苏虽然很大程度上是寿司的投影,但投影的目的其实是对比,玛丽苏的创作肤浅,笔下的故事只是无聊的黑深残,但寿司却喜欢在绝望时写一些希望,在希望中铺设绝望,最后的反转再怎么说都是有因可循,单论创作的层次来说就高出绿虫子太多了,当然,我也不是在吹寿司笔力多高,因为高出玛丽苏这个水平的创作者多如牛毛。 寿司设置玛丽苏这个角色,其实是使用了一种嵌套的结构来讲故事,首层是童话的原作,这些是毋庸置疑的好故事,随后是虫子和奈亚魔改出的箱庭,是烂故事的典型,最后一层寿司想讲的重点其实是格林怎么察觉真相,挣脱出烂故事的循环,书写自己的结局的故事,在这三层中,第一层玛丽苏是读者,格林等人是作者,只出现在设定层面,第二层玛丽苏是一半作者一半角色,格林是一半读者一半角色,体现在abc结局,最后一层中寿司是唯一的作者,玛丽苏和格林就都是角色了,体现在d结局以及之后的二代,这种层层演变虽然有些炫技,但确实非常有意思。 就玛丽苏这个角色而言,整个泛二次元文化里她这样的反派也不常见,究其原因,则是因为一个有能力玩弄主角取乐的boss必然会导致战力失衡,冲突不起来,让读者感到憋屈,因此想要打败这种boss要么机械降神唯心爆发,比如一代c结局(虽然是演的),要么引入新的boss和同伴体系取代她如d结局,也因此,虽然我个人很喜欢一代,但一代的真结局d结局远没有2代h结局震撼 来做个总结吧,玛丽苏无疑是个纯粹邪恶的支配者,一个烂到骨子里的创作者,她作为创作者无疑是失败的,但作为bs这个故事里的角色反而是很成功的,不仅纯粹有特点,还有很多角色侧面可以挖掘,寿司巧妙地利用她读者,创作者和角色的三重身份来塑造她的多面性,颇有荒木在漫画术中写的“在作恶道路上高歌猛进”的成功反派角色风格。

]]>
+ c语言部分

基本函数构成

将数组传递为函数参数

1
int fcname(int arg[],int n)

基本输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- cin及其衍生函数返回一个iostream函数的引用,即支持
cin,get().get()
iostream的其他成员
- cout.put()显示字符
- cout.write()显示字符串
- cout<<flush刷新缓冲区
- cout<<endl刷新缓冲区并提供换行符
- dec,hex,oct控制输出数制
hex(cout)控制cout为16进制
- int width()返回字段宽度当前设置
int width(int i)设置字段宽度,返回以前字段宽度
只影响下一次输出
- fill()设置填充用字符
- precision()设置精度,即保留几位小数
- setf()设置各种输出格式
- 流状态stream_state(eof,fail,bad)
- cin.get(ch)读取下一个字符,跳过换行符和空白
- cin.get()读取空白和换行符
- cin.get()get的基础上读取到换行符并丢弃
- cin.read()读取内容,但不会在末尾加空字符
- cin.peek()读取输入流下一个字符但不抽取
- cin.putback(ch)把一个字符放到输入流最前

文件输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
写入文件
ofstream fout;//ofstream继承ostream
fout.open("hello.txt");
fout << "i'm adding sth"
|| ofstream fout("hello.txt");
读取文件也类似
fin >> ch||string
关闭流
fout.close()
fin.close()
检测文件是否打开
if (!fin.is_open())
设置文件输入输出格式
ios_base::

基本逻辑运算符

break打断循环 continue,跳到更新表达式前开始执行 非const引用的函数不接受const参数

基本数据类型

结构数组

stname;
1
2
3
4
5
6
7
8
9
10
11
stname stobj\[int x] =
{
{}
{}
}
union(类似结构,但相同数据类型只存一种)
每个指针需要一个*用于初始化
int * intlist=new int [10]
delete-new
delete []-new []
typedef typename aliasname

名称空间

1
2
3
4
5
#ifndef HNAME_H
#define HNAME_H


#endif

如果在遇到另一个定义HNAME_H的头文件时,将他忽略

作用域: 1默认情况下,函数中声明的变量作用域位于代码块内,如果函数内外都声明一个同名变量,运行至内部代码块使用内部,离开代码块使用外部 2静态变量存在于整个程序运行周期,脱离作用域后只是无法使用并不消失 代码块外声明且不带static关键字:链接性外部,可以在其他程序使用 代码块外声明,且使用static:链接性内部,可以在整个程序使用 代码块内声明,且使用static:作用域于代码块内,但始终存在//由于静态变量只可以定义一次,所以即使离开代码块后变量依旧存在,且值不变,直到下一次修改 3运算符::放置于变量前时,使用同名变量(如果有)的全局版本 4namespace{

} 无法放置于代码块内,因此默认为全局名称,可以囊括声明和定义,可以随时添加 定义于类声明的函数自动成为内联函数

c++特性

class

1声明构造函数时,尽量使用explicit(显性转换)前缀,防止隐性转换带来的问题 mutable(摆动的)前缀声明变量,表示这些变量可能在const成员函数内被更改 用const_cast<>和static_cast<>与this指针可以实现const成员函数向非const的转变,反之则是错误的

2class初始化成员时,按构造函数声明变量的顺序,因此初始化成员时最好也以此顺序初始化 如果不希望class有copy和赋值(=)操作,则应该在private里定义copy和=运算符

3基类引用可以指向派生类对象,无需进行强制类型转换

4定义于类声明的函数自动成为内联函数

5类的函数对所有对象共用,但数据则各自私有

6要创造类对象数组,该类必须有默认构造函数

7只有一个构造函数参数的构造函数可以用于类的自动转换 classname t; t=20; 如果想禁止这种转换,可以声明explicit给构造函数

8类声明中可定义对于某种基本类型的转换函数 operator int();//可声明为显式转换,尽量避免过多的转换造成二义性

9如果定义类成员参数为static,则它在程序中只有一个地址,可以被所有类成员共享 但通过static实现共享成员时,需要重新定义复制和赋值函数来避免问题

动态类的注意事项

*构造函数中如果用new初始化指针成员,则应该在析构函数中使用delete new对应delete,new[]对应delete[] 对多个构造函数,应用和析构函数兼容的new来初始化成员 重构复制和赋值运算符来实现深复制

10对于使用new创建的类,使用delete时其析构函数才会被调用 如果在使用new时,将对象地址赋予一个指针时,如果删除指针,则对应的对象会调用自己的析构函数 对与使用定位new创建的类对象,需要显式调用析构函数 object->~classname(); 且应该以创建顺序的相反顺序调用,因为后创建的对象可能依赖于前者

类继承

公有继承

class sonclassname: public fatherclassname 派生类继承了基类的公有接口和数据 但只能用基类public和protected函数访问基类私有数据 派生类可添加函数和数据成员 派生类需要自己的构造函数,并由于权限问题,其构造函数必须包括基类构造函数,并且同样可以使用成员初始化列表 指针 基类指针和引用可以在不显式转化的情况下指向派生类对象反过来却不行 虚函数

纯虚函数 virual typename func() const=0; 含有虚函数的类不能创建实例,只能用作基类

访问控制(protected) 派生类成员函数可以访问protected成员,不能访问private成员

私有继承

使用私有继承,基类的公有成员和保护成员都成为派生类的私有成员,只可以在派生类的成员函数中使用,可以实现has_a关系 私有继承访问基类方法时需要调动基类的命名空间 访问基类对象 如果要直接访问基类对象,则需要调用强制类型转化将派生类转化为基类

保护继承

保护继承时,基类的公有和保护成员都成为派生类的保护成员,基类接口在派生类中可用

通过using指令可以让私有函数被当前作用域可用

命令行参数

int main(int argc,char* argv[]) argc为参数个数 argv为参数组成的字符串

字符输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流
<string>
重载符号+实现拼接
str.size()
输入字符串使用getline(cin,str)
结构数组
struct stname;
stname stobj[int x] =
{
{}
{}
}
字符函数库<cctype>
isspace(ch)测试是否空白
isalpha(ch)是否字符
isdigit()是否数字
ispunct()是否标点

1
2
3
4
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流

<string> 重载符号+实现拼接 str.size() 输入字符串使用getline(cin,str) 结构数组 struct stname; stname stobj[int x] = { {} {} } 字符函数库<cctype> isspace(ch)测试是否空白 isalpha(ch)是否字符 isdigit()是否数字 ispunct()是否标点

指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1,c++没有溢出检测机制,
char name[]="hello";
char c =name[10]导致未定义行为
2,用一个常量指针指向常量需要两次const
const char* const name="hhh"
如果需要一个class专属常量,则使用
static const ***
实现文件中,const int classname:: ***
对于宏:
template <typename T>
inline functionname
3,const 出现在*左侧表示被指物为常量,右侧表示指针为常量指针
4,函数名就是函数的地址
double pam(int);
double(*pt)(int);
pt即为函数指针
如果需要一个函数以相同相同返回值和参数的函数为一个参数,则可以考虑函数指针
5,内联函数不能递归
6,引用容器时,如果迭代器不引用,仍然传递临时副本o
7,函数传递指针时按值传递,当向函数传递指针时,指针是按值传递的!这意味着你可以改变被指向的数组内容,因为在调用函数时,这些元素不会被复制!这意味着你可以改变被指向的数组的内容,因为这些元素在函数被调用时并没有被复制。另一方面,如果你改变了所指向的数组,这种改变在函数之外不会持续,因为你只改变了指针的拷贝,而不是原来的指针本身。

智能指针

auto_ptr<string> 和<unique_ptr>指针采用所有权模型,对特定对象只有一个智能指针可以拥有它,只有拥有它的指针可以删除它 shared_ptr<string>追踪引用对象的智能指针数量,最后一个指针过期时才会调用delete 使用new分配内存才能使用auto_ptr,unique_ptr

异常

try_catch

1
2
3
4
5
6
7
8
9
10
11
try{
func();
}
catch(errortype e1){

}
func()
{
do sth;
throw(error_type e1);8
}

栈解退 假设try块没有直接调用引发异常的函数,而是调用对引发异常的函数进行调用的函数,则程序从引发异常的函数跳到包含try块和处理程序的函数(追踪到一个地址位于try块的返回地址) 其他异常特性

exception类

exception类可作为其他异常类的基类,用what的虚函数(返回一个字符串)重载来指示错误类型 失败时返回空指针的语法

1
int * pi= new (std::nothrow) int;

未捕获异常

未捕获的异常会使程序调用函数terminate(),默认情况下,terminate()调用abort()函数,可以指定terminate()调用的函数来修改其行为

一些新特性

关键字

关键字nullptr表示空指针

RTTI(运行阶段类型识别)

dynamic——cast

danamic_cast<type *> (pt) 如果可以安全将pt转化为type*指针,返回对象地址,否则返回空指针 如果对引用使用,错误时返回bad_cast异常

typeid和type_info

typeid返回对type_info对象的引用,type_ifo是定义在typeinfo的类,重载==和!=预算符,例如 typeid(obj1)==typeid(obj2)

类型转换运算符

1
2
//用于执行各种类型的数值转换static_cast <typename> (expression)
//转换是允许隐式转换时才能通过(派生类和基类可以互相转换)

移动语义 通过指针转移右值的地址给新对象 或通过std::move()将左值转化为右值

someclass()=default default关键字显式声明编译器创建默认构造函数,复制构造函数 delete用于禁止类中的函数

关键字override可用于覆盖虚函数定义

匿名函数

返回类型编译器自动确定,可直接作为函数指针使用

1
[] (double x) {return x%3==0;} 

可以返回类型后置

1
[] (double x)-> double{int y = x;return y-x;}

可以给匿名函数命名

]]>
- <h1 id="尸龙贾巴沃克">尸龙贾巴沃克</h1> -<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!</span><br></pre></td></tr></table></figure> -<p>象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),<code>尸龙</code>姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对<code>尸龙</code>的整个人物进行解析 + <h1 id="c语言部分">c语言部分</h1> +<h2 id="基本函数构成">基本函数构成</h2> +<p>将数组传递为函数参数</p> +<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">int fcname(int arg[],int n)</span><br></pre></td></tr></table></figure> - + - + - + - +
@@ -906,86 +908,85 @@ - blacksouls原著梗解析 - - https://thinklive1.github.io/2023/09/29/blacksouls%E5%8E%9F%E8%91%97%E6%A2%97%E8%A7%A3%E6%9E%90/ + 基于斯坦福cs106b的c++数据结构笔记 + + https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.687Z - 01

众所周知,black souls的原型,或者说最重要的灵感来源就是爱丽丝梦游仙境以及它衍生的爱丽丝镜中奇遇,我本人一直对游戏和原著的对应关系感到很好奇,但由于工作量很大,一直没下定决心做这件事,但最近突然想到,如果分期做一些整理会不会就没那么麻烦了呢,于是决定开启这个系列。 由于是第一期,我就扯一些闲话,爱丽丝的原著可谓有着非常深远的影响,首先,他就是最著名的童话之一,在儿童里的传播极为广泛,在我小时候就听说并读过这个作品,但说实话爱丽丝的原著对孩童来说实在太过思维跳脱,导致我虽然通读了几遍但完全没看进去,考虑到当时的儿童文学相比现在的完善可以说几乎不存在,这本书可谓有着相当的意义,不过我毕竟没有研究过相关文学史所以不多评价了,对于爱丽丝的原著,我最深刻的印象就是其无比丰富的想象力以及跳脱的情节(由于卡罗尔是数学家,他还塞了不少数学梗进去),可能这就是莉耶芙喜欢这本书的初衷吧。 此外,爱丽丝这一形象与整个不思议之国以无数的二次创作形象疯狂地在各种娱乐作品里传播,关于这点,我认为是爱丽丝原著符号性强烈的特点导致的,永无止境的茶会,跳进兔子洞等元素非常具有符号性,它们奇怪到引人注目,但谁也不知道到底指的什么,可能有意义,可能没有意义,二次创作者可以非常自由地阐释这些元素,因此导致了在二次元文化里,爱丽丝近乎成了最常见的一个人名或者说符号 最后则是它的现实作者,金属冶炼在欧美文化里是个很敏感的话题,关于原作者此方面的谣言可以说满天飞,但对此我只能说疑罪从无,没有直接证据表明这一点,就连一些间接证据在我看来也很明显是牵强附会,基于道德的角度,我们不该用一些间接证据指责两个世纪前人物的私事,此外,black souls是毋庸置疑的架空世界观作品,不管怎么编故事也和现实中的卡罗尔毫无关系。 当然black souls设定下的卡罗尔也是个经常被讨论的问题,由于冬之钟那个崩坏的adv,很多人认为black souls的卡罗尔是个炼金术师,但是很明显小剧场不过是哪个支配者的大作,而且是个很有虫虫风格的作品,没有任何证据表明black souls设定下现实的卡罗尔干了相同的事,总的来说我认为black souls世界观的卡罗尔,除了他一直深爱爱丽丝以外和爱丽丝一家的关系是没有确切信息的,而且这种爱也可能不是男女之爱,只是柏拉图之恋罢了。 好吧,关于原著以外的讨论就说到这里,接下来我们开始具体情节的对照分析。 第一章的开头,小爱丽丝和姐姐一起坐在河边,姐姐在看一本没有插图没有对话的书,让小爱丽丝感到无聊。 书在black souls中是个很常见的意象,没有插图的书只在牛津学院的回忆中提到过一次,读书的倒是有几个,一代的爱丽丝02一直看着书,书上的内容似乎是格林被玛丽苏毁灭时的遗言,此外,一代的尸龙也在读着书,而且二代时她也在河边,根据她念出来的部分,其实就是我们这个世界的卡罗尔描写邪龙贾巴沃克被打倒的那首诗,个人猜测有可能black souls中卡罗尔没有给爱丽丝送出去的礼物其实是他的作品集,后来卡罗尔被玛丽苏捉走,这本书则被尸龙拿走,最后,二代的白女王诺登也是个看书人,这本书格林无法阅读,但0sen下能看到轮回次数 由于02不是任何人的姐姐,白女王虽然很御姐,但原型明显是白兔先生,所以对应度最高的其实是贾巴沃克,此外尸龙摸鱼的时候摘花,而此时的爱丽丝也有摘花的意图,可能暗指温柔的尸龙姐姐摘花编成花环想送给爱丽丝(迫真) 随后就是经典的爱丽丝跟着匆忙的白兔先生进了兔子洞的环节,此时的白兔先生声称自己是急着去找公爵夫人 兔子洞在一二代都有对应,一代追寻着原著顺序,跟着白兔,从兔子洞跳下就能到达不思议之国,二代却是相反的,格林先到坠落之间,然后才到兔子洞 此外,原著对坠落的描述是,途中有很多书架以及各种柜子,这点在坠落之间和兔子洞都有体现,爱丽丝在坠落后第二次见到了匆忙的白兔先生,而按通常的流程,也是格林过了兔子洞后进行度为1才能见到白兔诺登,此外原著中爱丽丝第一次来到的门厅顶上有一排灯,这可能是图书馆的进行度灯的灵感来源,原著中爱丽丝用钥匙打开一扇门后来到了放有变大变小药的房间,游戏可以直接到达,喝了我和吃了我是非常经典的原作梗。 以上是爱丽丝原著第一章和游戏的对应关系,那么今天就到此为止了

02

接下来开始第二章的分析 吃下蛋糕后的爱丽丝身形变得非常巨大,也因此挤不进她想去的花园,此时她哭泣的眼泪形成了泪水池,对应bs的血泪之池,有种说法是红偶像紫餐产生的血泪形成了血泪之池,如果从致敬原著看的角度倒是不无可能 这时白兔先生经过,被爱丽丝吓跑,留下了手套和扇子,扇子有着让人变小的能力,但此时不知情的爱丽丝一边扇扇子一边开始自我怀疑,正是这时她提到了梅贝尔这个名字。 根据爱丽丝的说法,梅贝尔什么都不知道,住在又破又小的房子,没有玩具还要天天念书,对应bs中的梅贝尔,某种程度上讲还挺还原的 随后被扇子变小的爱丽丝掉进了泪水池,并在池子里遇到了一只耗子以及其他动物,她们一起游上了岸。 接下来就是第三章了 此时耗子开始上起了历史课,这段剧情在bs有两个对应点,一个就在酒馆里耗子直接出场给我们上课,而则是牛津学院的回忆提到爱丽丝讨厌历史课。 随后为了让湿透的衣服变干,渡渡鸟为她的动物朋友们召开了一场赛跑会,跑完宣布大家都赢了,但奖品让爱丽丝颁发,甚至包括爱丽丝自己的奖品,于是爱丽丝给所有人每人一颗糖,给自己发了一只丁真,很对应游戏血泪之池的渡渡赛跑会,但游戏中只有杀害渡渡会得到一颗糖果,杀害其它动物没有奖品(私藏奖品的屑),附近可以捡到糖果,此外,游戏和原著中的赛跑参与者是不完全对应的,赛跑中白鹅会提到鹦鹉和鹰缺席了,原因吗,因为涉及一些书本以外的东西我们以后再说 此后螃蟹母子的对话会提到好脾气的牡蛎,可能对应bs的dlc1嚣张的牡蛎 第四章中爱丽丝被白兔错认为了玛丽.安,白兔家的女仆,这就是为什么被白兔诺登剥夺神力的虫虫改名成玛丽.安并且穿着女仆装。 爱丽丝喝了让自己再次变大的药水,然后被挤进了房子里无法动弹,此时她吐露了自己不想长大的愿望,随后,蜥蜴比尔被派去搬来梯子,爬进烟囱里查探情况,被爱丽丝一脚踢飞出去,这段对应bs大圣堂里比尔搭梯子的剧情,顺便一提,比尔除了倒霉蛋属性外在bs里几乎全被魔改了,合理怀疑是莉耶芙加了什么私货进去。 随后爱丽丝吃下了被扔进来的蛋糕,再次变小,并逃进了一个长着高大蘑菇的森林,并在蘑菇上遇到了抽烟的青虫,对应游戏中的孢子之森,第四章结束 也就是说原作爱丽丝的路线就是兔子洞-血泪之池-孢子之森,这也是为什么进行度0时会在森林遇到爱丽丝的幻象,虽然这一路线并不一定遇到比尔 格林和希夏的对话基本对应原作爱丽丝和它的见面,一开始不理不睬,但离去时希夏开口挽留,原著毛虫让爱丽丝背了首威廉老爹的诗,对应孢子之森的boss,游戏与原作不同的是,原作的虫子告诉爱丽丝吃下蘑菇可以变大变小,游戏中直接让格林去找公爵夫人 爱丽丝见过青虫后有段剧情,爱丽丝吃下蘑菇后脖子变得很长,被一只孵蛋的鸽子认作来吃蛋的长虫,这里译本的长虫其实就是大蛇的意思,这段剧情在游戏也有两个对应,一是游戏中的物品鸽子蛋,孢子之森能捡到鸽子蛋,杀害希夏会掉落鸽子蛋,正好符合原作顺序,对其的描述是少女不吃生蛋,蛇却很喜欢吃,也符合原作,bs中的蛇只有蛇神,而0sen下看到他的脖子很长,也对应原著情节;第二个疑似的对应点则是卡罗尔川的矮胖子,可以孵化出雏鸟,但除此以外和原著没什么对应

03

接下来我们开始第六章,公爵夫人的章节 公爵夫人馆外能遇到名为幼犬的怪物,这应该对应书中第四章,遇到青虫前爱丽丝遇到的小狗,馆内可以遇到鱼和蛙之听差,原作中他们分别是女王派来邀请打縋球和公爵夫人处接受邀请信的佣人。 公爵夫人是比较还原原著的一个角色,基本上所有行为举止都有对应。爱丽丝初见她的场景和游戏中几乎完全对得上,婴儿和猪的转化则用sen值来实现(顺便一提屠宰场也有类似的转换),只有柴郡猫没有出现,但馆内一张挂画上则会出现柴郡猫,这张挂画上随着sen值不同也会出现猪和婴儿的转变,此外,由于公爵夫人还原度很高,我把台词中的对应点用图整理如下 公爵夫人另一个原型,也是她名字和贪食属性的由来则是一幅画作,这幅画作(比较哈人就不放了)可能的历史原型是一位贵族女性,她在历史上有大嘴的外号,并且和丈夫并不恩爱(甚至没同过房?),这解释了里线中她的台词 游戏中柴郡猫瞬忽隐忽现,还有标志性的微笑都出自此章,不过对她来说似乎更认同爱丽丝家的猫的身份,然而她又部分否定了戴娜的身份 值得一提的是,此前我们提到的原作路线都是有着某种程度上的认证的,到森林的路线有爱丽丝幻影,随后有希夏的指引,但从公爵夫人开始跳脱出了梦游仙境,让我们去了镜中奇遇,并且地图到了这里也确实是死路,如果继续按公爵夫人的指引,到达库因兰德这条死路后也确实找到了爱丽丝,虽然格林并不知情。 而如果我们想要继续原著路线,就要踏上不同的路,经过牛津学院到达永不终焉的茶会,为什么呢? 关于茶会我很有些个人想法,但我们先从原著的角度说起 虽然一二代都有茶会,但比较对应原著茶会一段的是二代的茶会,原著中帽匠和三月兔被柴郡猫钦定为疯子,可以说是整部作品里最荒诞的一段,在bs中也不遑多让,我们先从三人的现实原型说起,帽子屋的原型是中世纪的帽匠,由于工艺会用到水银,所以有着疯疯癫癫的形象(游戏也提到这点),三月兔的原型是一句俗语,这句俗语的由来据说是兔子三月处于繁殖期而狂躁不安,所以会有这种人设,睡鼠原型则是一种常见的宠物,非常嗜睡,当时人们喜欢把它养在茶壶里。 我们分人物说起,首先是帽匠 原著一见到爱丽丝,帽匠就大喊没位置了,并且抛出了乌鸦桌子的谜语,和游戏一样,这段谜语若干年后卡罗尔才公布答案,所以游戏的帽子屋说不知道答案。 随后,爱丽丝说自己说的和想的一样,三人一人一句地反驳了她,其中除了三月兔抛出的两句话,都是主语宾语单项包含关系,但游戏中爱丽丝的话由帽子屋说出,并只有睡鼠保留着这种逻辑关系。 面包黄油的对话几乎完全致敬原著。 原著爱丽丝与柴郡猫对话提及此刻是五月,和帽子屋对话提及今天是4号,游戏中时计塔的密码1852正是爱丽丝的生年,所以游戏中帽子屋会说擅长happy birthday 帽匠会提及,自己和时间闹翻了(红心女王的说法是谋杀时间),所以茶会被永远定格到这个时间,餐盘只能越积越多,这可能是游戏中帽子屋不死能力的来源,监禁后她离开了茶会,所以又可以杀死了,此外,游戏中狂鸟一定程度上和时间有着关系,并且帽子屋很讨厌她,或许和原著这段情节有关(但帽子屋又称呼时间为先生) 随后是三月兔,原著中三月兔头顶缠着稻草,卡罗尔说这表示她疯了,游戏致敬了这点。 原著的三月兔打翻了牛奶,游戏中是红茶 最后是睡鼠,睡鼠在原著中唱歌和讲故事都和游戏里对应,故事中三个小姑娘的名字对应利德尔三姐妹,讲故事时,三人责怪爱丽丝打岔,在游戏中里线战斗对话有体现。 好了,以上是和游戏原著比较对应的地方,接下来我就说说对茶会的个人理解,再强调一下,都是个人理解。 茶会可以说是bs2中一个很重要的地图,它和牛津学院直接相连,并且两张地图连续有一个回忆,而进入牛津学院主流的路线就是从精神病院开始通过路德维希市街,见证伊迪斯和杰克的悲剧,顺便一提关于利德尔三姐妹,我之后会出个特辑,这里先不谈,漫布迷雾的街道明显是在neta伦敦,并且卡罗尔是英国人,曾在牛津学院任职,这条路线可以说是最贴近现实的一条路。 此外,如果要防止狂鸟唱歌,就必须先来到茶会去往时计塔,并且时计和箱庭的运转息息相关,而狂鸟唱歌的目的应该就是让格林别乱跑了去找爱丽丝,此外,不思议之国的大部分地方都很有着阴森的氛围,而且弯弯绕绕,只有茶会非常狭小却坐拥一个篝火而且阳光明媚氛围悠闲,几乎可以磨灭格林的斗志了,茶会的三个参与者就更有意思了 如果我们给三人归纳一个关键词,一个是疯狂,一个是爱欲,一个是睡梦,三者加在一起几乎概括出了整个二代的特点,这恐怕是奈亚不想让格林意识到的,此外,来到茶会必然会遇到伊迪斯,按原作顺序之后就是红心女王罗丽娜,两人是乱入者,且都曾和卡罗尔关系亲密,奈亚不希望她们引发卡罗尔的回忆,所以才会让夫人把我们支开。 对这三人和她们的象征意义,疯狂和爱欲其实不必多说,但睡梦其实是一条相对的暗线,我一直认为寿司是一个很喜欢前后对照的作者,所以就让我们来分析一下,不少npc会提及此处是个梦境,但最早是在op,游戏的开头是格林苏醒,看到爱丽丝,然后不知道为什么再次睡去,因此我们如果认真看开头就会知道不思议之国是个梦境,那么为什么设定成梦境呢,首先是由于协助创造箱庭的诺登的原型是所谓的幻梦境之主,其次呢就是因为原著的结局会发现爱丽丝的奇遇是一场梦,光是这点就很有意思,两者揭露梦境的时间点完全相反。 那么问题来了,已经在梦境了,如果再次做梦不就有了梦中梦?而如果是梦境是虚假,梦中梦则是虚假的虚假,会不会是真实呢?格林做过几次梦中梦呢,第一次是精神病院看到师匠,第二次是孢子之森的幻觉爱丽丝,第三次是海底的旅社,第四次是冬之钟adv,牛津学院的月面比较特殊就不论了,这几次梦中梦,虽然未必都是真实,但都揭示了部分真相或者现实。 既然如此,有一个人就很奇怪了,睡鼠,她是格林外唯一一个能在梦境中沉睡的人,如果是格林自己的梦还可以做梦中梦,但睡鼠一个梦境中的角色怎么还能入梦呢?除非她只是装睡,对话中睡鼠会说她没有睡,所有人的对话她都没有听漏,这很有可能就是真相(虽然里线又说真在睡),并且她随后说了一句要杀了所有人,然后辩解说是梦话,结果全监禁后她真的这么做了。 因此个人猜测睡鼠表面虽然入梦,但其实是最清醒敏锐的,她有着监视格林的任务,一旦格林不照着剧本做梦,滞留在一次轮回中,就会把风险清除掉,逼迫他进入下个轮回。 而h结局中在冬之钟我们能看到三月兔和帽子屋,她们的对话反过来看就是冬之钟的本质,为什么只有这两个人呢?一是三人的对话提到除了睡鼠两人都想来冬之钟,二则是根据我的想法,此时格林意识上已经从梦里醒来,剩下的问题就是奈亚的爱欲,以及舞台带来的疯狂,也就是茶会的这两个人的象征。 当然,以上不过是个人解读,大家看个乐就行。 可能有人问,那么一代的茶会呢?这个由于时间线的原因我们以后再讲。

04

让我们开始第八章的分析 七章末尾,爱丽丝被疯疯癫癫的三人惹恼,离开了茶会,进入了一片森林,在她迷路时出现了一道门,让她回到了最初的兔子洞大厅,随后她利用变大变小的能力走进了最初看到的庭院。 这段路线,如果我们忽略茶会怎么回到兔子洞这个问题,可能对应利德尔墓地到心脏庭院,墓地这块确实是森林,并且进入庭院的入口确实是一道门,虽然顺序颇有些问题。 原著中,入口旁的三个扑克园丁忙着把种错的白玫瑰刷成红心王后喜欢的红色,随后被王后发现要杀头,游戏中只有一个庭师在干活,而且不是上漆而是上血,另外两个则在说格里芬的闲话。可能是rpgmaker的素材问题,原著和游戏的扑克种类对不上 原著中红心王后杀头的表达翻译过来大概是这样的:他们的头没了吗?士兵的回答是:“他们的头不见了”由此王后认为确实杀头了,这里是个文字游戏,原著中这三个园丁藏了起来,头确实看不见了,但没有杀头,这可能是游戏中红心女王不看处刑场面的由来。 杀头后王后邀请爱丽丝打追球,但是球棍是火烈鸟,球是刺猬,两者都会在游戏出现,区别是火烈鸟0sen变成弯曲的球棍,球则在0sen才出现 打球的时候公爵夫人来向爱丽丝搭话送了她几句教训,对应游戏中公爵夫人出现在追球场并且满口教训,随后王后再次出现在爱丽丝面前,带她回去打球,这次过程中王后把除了国王的所有人判了死刑,随后国王赦免了他们。 可能是由于实际上外来者的缘故,红心王后也被魔改得很厉害,基本上只有性格和杀头的口头禅是还原原著的,此外,原著的红心王后虽然没杀过一个人的头(狮鹫的说法),但被所有身边人畏惧,这点也沿用到了游戏中,红心王后可能的原型是当时的英国女王,这也是为什么游戏中红城bgm是掷弹兵进行曲。公爵夫人会说红女王和红心女王一样残暴,这段可能来自于卡罗尔自己对两位皇后的解释。原著的红心国王直接删掉了,是梦游仙境唯二个游戏里没有对应的主要人物(还有个是红桃杰克),当然也有可能对应格林(笑)。 之后,王后让狮鹫带爱丽丝去听假海龟的故事,对应游戏里罗丽娜发布布告让部下去讨伐食尸鬼,因为会在那里见到假海龟。原著中在女王走远后,狮鹫说到女王从来没有成功杀过一个人的头,对应游戏中格里芬说女王不敢看处刑场面 这里顺便一提,狮鹫是卡罗尔任职的牛津学院的三一学院的院徽,假海龟出自当时用牛肉汤代替昂贵海龟汤的习惯,原著中狮鹫懒散,假海龟则惶恐不安,和游戏对应,假海龟哭哭啼啼地讲起了自己的故事,它曾在深海的学校上课云云,这里是非常典型卡罗尔造生词环节,游戏中有原台词化用 说完上课的事后,狮鹫提出跳龙虾方块舞,游戏中则是龙虾舞,为什么呢,我给大家三秒钟猜一下,因为格里芬是方块骑士,所以已经有方块了,这很可能是方块骑士身份的来源,因为除此以外原著只有一些方块廷臣,其中的歌是假海龟唱的,游戏中也有体现,格里芬说自己不记得歌词 随后狮鹫让爱丽丝背了几首诗,最后假海龟唱了一首海龟汤,对应游戏中让假海龟做料理的台词 关于爱丽丝的线索,女王和格里菲会引导格林去市街,市街的卡面来打会引导格林去墓地方向,随后线索就断了。 这之后就是梦游仙境最后一个场景,审判庭,关于审判这件事的信息,翻遍二代也只能找到狮鹫去邀请比尔当陪审员这件事,其中,他们会说审判已经发生过一遍,那么是在哪呢? 很有可能是在一代的不思议之国。已然终结的茶会,最明显的是守门的班达斯奈奇,他提出的问题和答案部分和原著的审判相对应,茶会中的一只兔子会提到疯帽子三人以及爱丽丝的消失,这正是原著剧情,收集童话出现的里门,爱丽丝排列成类似法庭陪审团的形式面朝格林,这很有可能也是表示审判。 此外,我也有些个人想法,杀害02得到的缎带物品描述是追寻梦中的爱丽丝,这几乎可以肯定指的二代,而爱丽丝原著正是在最后的审判后告诉我们一切都是梦,然后见到了姐姐,而这和一代也在读书的尸龙姐姐勉强对得上,审判后的爱丽丝消失了,奈亚丽丝用格林取代了她的位置一直梦游到了审判剧情前,这样一来就构成了一个循环,爱丽丝梦游仙境结束后开始格林梦游仙境,这是很有寿司风格的前后对照。 此外,还有一种可能的解读是,审判其实是奈亚丽丝内部召开的,最后判决结果是把爱丽丝01驱逐出去,产生了红偶像 总之,审判这段原著情节在bs有没有对应大家就见仁见智吧 好了,这样一来对梦游仙境的解析就结束了,下一期作为拾遗篇,我会说说卡罗尔和利德尔三姐妹在游戏中的暗线。

拾遗篇

查尔斯·道奇森,一个天赋型的数学家,笔名刘易斯.卡罗尔,最知名的作品是两本以知名幻想角色爱丽丝为主角的作品,与同时代知名的柯南道尔(福尔摩斯系列的作者)同是一个灵异研究学会的成员,还有一个较晚出生的知名的同时代人是克苏鲁体系的作者洛夫克拉夫特 有意思的是以上提到的三人分别是三种文学流派的奠基人,并且这三种衍生文化不同程度地影响了bs系列 1855年,卡罗尔23岁,结识了自己任职学院的院长一家,一年后认识了三姐妹,随后的时间他时常和这家的三姐妹一起聚会,1962年7月4日,一个黄金的午后,当时三姐妹的长女罗丽娜13岁,次女10岁,三女8岁,与卡罗尔一起泛舟湖上,卡罗尔讲了一个日后成为梦游仙境原稿的故事,两年后整理成了一部名为地底冒险的手稿送给次女。 1863 年 6 月,利德尔一家和卡罗尔之间的关系突然破裂,没有直接证据能说明原因,几个月后有所缓和,但已经无法还原如初的美好了。 再之后,长女没有在历史上留下痕迹,次女和三女都和一位王子有过绯闻,但可能因为身份原因没有成,可怜的三女在即将结婚时22岁因病早逝(精神病院的开门次数),似乎最受上天关爱的次女于28岁结婚,成为哈格里夫斯夫人。 这是我们这个世界历史上的卡罗尔和三姐妹的故事。那么bs世界里这四人发生了什么呢?

最直接的证据是六段苦涩的回忆,虽然对他们的来龙去脉或是真假完全没有确论,但它们提供了大部分相关信息,我们按现实时间顺序一个一个说起。 卡罗尔川的回忆直接用了梦游仙境的卷首诗,描述了这个故事的原初,并且由于卡罗尔生活时期正是英国盛世,泰晤士河污染严重,黄金午后的那条河流从属于泰晤士河,和游戏中污染的描述也对得上 按现实顺序随后的应该是牛津学院的回忆,卡罗尔和利德尔一家的交恶 随后则是槌球场,这里应该对应现实中黄金午后的两年后,卡罗尔送给了爱丽丝地底冒险手稿,这部手稿有卡罗尔自己的插画,但并非圣诞礼物,卡罗尔曾和爱丽丝一家打槌球玩,因此会出现在槌球场,但游戏中此时二家似乎没有交恶,因此bs中可能存在顺序调换。 之后就是纯粹的架空时间线了 之后是叹息的海边,回忆中摄影的阁楼有现实对应,正是牛津大学的建筑,回忆描述了两人的再次重逢,至于为什么是海边,可能是因为卡罗尔在1876年出版的《猎蛇鲨记》,这是他最后一部知名作品,次女和卡罗尔的重逢历史上没有什么资料,事实上,即使卡罗尔逝世时,次女也就46岁,不可能是老婆婆,但梦游仙境的改编的戏剧于1886年圣诞节期间上映,卡罗尔也去看了,顺便一提,演睡鼠的是一位叫多萝西的女士。这是有记载的卡罗尔最后一次见到次女,而有记载的次女最后一次与卡罗尔有交集,是在1932年卡罗尔逝后的100年诞辰,这时她已经80岁了 再后面是库因兰德的回忆,库因兰德的女王原型是镜中奇遇的红女王,而镜中奇遇出版于1871年。这段回忆似乎提到卡罗尔把另一个人当做代餐,可能是bs世界观的罗丽娜? 最后是完全架空的茶会回忆,和现实基本没有关系了。 其次还有若干原著彩蛋在游戏中使用,如卷首诗,也就是第一段回忆的little和利德尔同音,血泪之池的鹦鹉和小鹰分别是长女和三女的书中化身,睡鼠的故事也化用了三姐妹的名字等

卡罗尔在bs中和现实基本对应得上,但还有的问题是,猎蛇鲨记,贾巴沃克等作品的来源没有交代,其中贾巴沃克这首诗尸龙基本给我们念了一遍,有可能原稿在她手上,此外卡罗尔虽然终身未婚,但依然有很多朋友,如猎蛇鲨记就受一位忘年交的启发,可能是冬之钟小剧场那张照片中的女人 顺便一提,现实中的弗朗西斯.利德尔1965年出生,自他记事起卡罗尔和利德尔一家应该都不怎么来往了,现实中的三姐妹和当时的大部分贵族女性一样在家中由私教授课,不可能叫卡罗尔老师

之后我们来分别探讨一下三姐妹在bs的暗线 现实中的长女资料最少,但书中的鹦鹉有卖弄自己年纪大的特点,并且有一种说法是,当年的长女对卡罗尔非常依恋,这些特点沿用到了游戏中,有可能bs中的卡罗尔倾吐虚假爱意的对象就是她。根据其自述,罗丽娜向邪神献祭灵魂才会来到不思议之国,但时间点未知,如果是在次女后,那么游戏中的罗丽娜是完全的少女心性就很奇怪了。还有一种说法是,罗丽娜和她的母亲名字一样,所以小剧场那张照片的真身有可能是……不过我觉得这可能很小就是了 心脏女王也是个谜点重重的角色,如果我们给有梦游仙境原型的誓约角色所需魂数量排序,那么由小到大依次是白兔,渡渡,比尔,希夏,公爵夫人与假海龟,帽子屋,心脏女王 其中除了假海龟都参照原作出场顺序,她虽然是乱入者,但不思议之国大部分住民都会提到并认同女王是名义上的统治者,她不知为何能指挥魔兽化的手下,让唯一有理智的格里菲去全国巡逻,每天用审判来控制人口,还给大工批了大把建筑费用来上达天听,不知道是奈亚的命令还是什么其他原因,她确实做了很多管理不思议之国的事,此外,还是唯一一个非格林子女却有里线战斗的 三女伊迪丝在游戏中是精神病院的boss,对于她怎么来到箱庭,仅有的线索是混沌迷宫和电影院的两段没头没尾的故事,游戏里和三女私奔的王子,很可能也是杰克,这位角色现实原型之一很可能是利奥波德王子,正如前文所说,据传他曾与伊迪丝相爱,伊迪丝22岁早夭后,王子为她抬棺,王子和伊迪丝一样病弱,患有血友病,三女辞世的8年后,王子以30岁的年龄逝世,这或许是游戏中他也住院的原因,另外两个明显原型是开膛手杰克和福尔摩斯,或许是因为卡罗尔曾被看做开膛手杰克的嫌疑人,而同时代柯南道尔也曾经研究过这个案件,顺便一提上文王子的一个侄子也是一大嫌疑人 伊迪丝在冬之钟小剧场里头戴着枯萎的花圈,可能暗示着她的早逝,并且多次有小鹰的元素出现,但罗丽娜除了大姐作风却没有明显的鹦鹉元素,这点也有些让人在意 最后是次女,这里的次女指的是观星引来奈亚的人类个体,关于这个个体的信息反而是最少的,只知道她和卡罗尔心心相惜却被拆散,她和现实次女的履历是否一样未知,她的最终去向未知,牛津学院的学寮长是否就是她父亲的灵魂所化也未知。 关于现实中的对应,现实的次女并非常见的金发形象而是黑发,并且和梦游仙境的爱丽丝有很多差异,游戏中似乎没怎么提到过发色,不知道如何设定,次女和南丁格尔是同时代的人,因此院长认识爱丽丝可能是认识人类状态的次女,此外,小剧场的次女会有很多致敬原著的台词,出示如下 在群星之夜后,似乎她的名字成为了禁忌,也是里线剧情的关键,关于次女我还有一个,, 等等,次女的名字,为什么,我想不起来次女的名字,对了,她的名字,她的名字不就是 爱丽丝.利德尔 勿呼其名,唤则得知,蠕动前行而来 縺ゥ縺?@縺ヲ遘√'谤「縺辅↑縺代l縺ー縺ェ繧峨↑縺??縺ァ縺呐° 繧「繝ェ繧ケ繧呈尔縺励※缧ゅい繝ェ繧ケ繧呈?縺励※缧ゅい繝ェ繧ケ繧贞ソ倥l縺ェ縺?〒缧 诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ 诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ

ex01

相较梦游仙境,镜中奇遇在bs中的对应情节明显变少,但依旧有分析的价值 首先是镜中奇遇的卷首诗,这首诗提到了卡罗尔此时和现实的爱丽丝年龄相差一倍,语气中某种程度上可能透露了卡罗尔对无法回到往日时光的惋惜,不管怎么说,此时爱丽丝已经长大了,看童话故事的美好时光已经不会回来了 开篇剧情中爱丽丝在和戴娜生下的小猫玩,对应普通结局少女的房间中柴郡猫说自己产下小猫后死去,虽然我们不知道现实的戴娜是怎么死的。 随后爱丽丝会提到镜子屋,也就是镜子里的相反的房间,这在之后成为整本书的主题,在bs中镜子屋对应公爵夫人提到了通过血泪之池镜子才能到达的镜之国,但同样和镜子有莫大关系的还有一位小红帽,值得一提的是,镜之国库因兰德是为数不多没有柴郡猫出现的篝火。 随后爱丽丝在镜子屋看到了一些会说话的棋子,并随意摆布它们,这段有点像bs奈亚的作风 她翻到了一首叫贾巴沃克的诗,当然这里其实是卡罗尔引用之前的作品,贾巴沃克这首诗非常晦涩难懂,以后有机会我会谈谈在它在bs里的对应。 之后爱丽丝飞跃滑下楼梯,想跑去屋外的花园,这里的下楼梯法在冬之钟小剧场有对应

爱丽丝想走到一座小山丘俯视花园上,但怎么走都会回到原点,这 里可能对应精神病院的走法,也可能对应库因兰德的迷宫,于是她只能转而去往一个小花园,遇到了一群会说话的花,这些花对应一代圣森和不思议之国的会说话的花,以及在bs2中,红女王的房间里的花,一些花很吵闹,爱丽丝威胁把它们拔下来,对应道具咒骂之花, 随后爱丽丝遇到了红王后,原著中的红王后被卡罗尔描述为典型的家庭教师,原型可能就是爱丽丝的家教,bs中红女王的名字直接用了这位家教的名字,有一种说法是卡罗尔利用三姐妹来追求她造成两家决裂 爱丽丝羡慕地说想成为王后,红王后告诉她需要前进八格,然后拉着她全力奔跑,贡献了一句经典台词,前进八格成后这是国际象棋的规则,而红王后的台词在bs中对应库因兰德的一个留言和冬之钟柴郡猫的台词 值得一提的是在原著中有重要意义的棋盘在bs中也有同样的重要性,红女王的库因兰德遍布着棋子,梅贝尔在自己的箱庭部下棋局,而白女王则把王冠,也就是走了八步后成王的关键放在了冬之钟,可以推测原著中想要成后的爱丽丝其实对应着bs中想要得到改变权能而成王的格林。 红王后指引爱丽丝成后的走法,提到了需要乘火车,对应去库因兰德的火车 火车上爱丽丝遇到了一只会说话的虫子,在一阵颠簸后她们发现自己安静地坐在树下,爱丽丝和它讨论了一下命名学,虫子告诉爱丽丝前方有着无名之森,对应bs里的那张地图,这只虫子可能也对应无名之森的一只虫形怪物 无名之森里爱丽丝遇到了一只小鹿,对应bs中无名之森的小鹿,但bs中通过无名之森才能坐火车,与原著相反 本章的末尾,爱丽丝遇到了双子

ex02

爱丽丝接下来遇到的是崔德尔双子,二者一开始站立不动,让爱丽丝觉得他们是蜡人偶,也就是蜡像,游戏中反了过来,游戏中双子提到了站立不动的格林是蜡像的可能 两兄弟的原型是一首英国童谣,童谣提到了丢失的拨浪鼓和飞来筑巢的乌鸦,在游戏双子的台词有体现,筑巢的大鸟应该就是伊迪丝 随后两兄弟给爱丽丝背了首海象和木匠的诗,大意是海象和木匠偏小牡蛎来做客,然后把它们吃完了,游戏中很明显海象对应希伏契,木匠对应大工,吃牡蛎的剧情也在希伏契对话中有体现,且,双子誓约对话会提到两人 之后,爱丽丝发现了附近正在做梦的红王,在双子对话中有原意复用 双子中的蒂看到了他弄坏的拨浪鼓,让两兄弟起了矛盾,对应游戏中的台词,随后两人约定决斗,可能对应游戏里的双子相残,就在这时乌鸦飞了过来,打断了决斗 书中的两兄弟按棋谱来说是白方,这解释了她们为何与dlc3的克里米亚有一定关系

为了躲避大鸟,爱丽丝逃进树林遇到了白王后,与严肃的红王后不同,白王后非常随和友好,并且她声称自己是倒着过日子的,这解释了白女王诺登管理重启轮回的职能 交谈一会后,爱丽丝突然转移到了一间商店里,店主是一只绵羊,发生了很多怪事后爱丽丝又闪现到了小船上和绵羊一起划船,对应游戏里老羊的台词 书中这段空间转换非常频繁,可能因此寿司在老羊商店里放了一堆来源不明的谏言

一连串的转换后爱丽丝看到了矮胖子,这位角色也来自于一首英国民谣,矮胖子很多台词台词在游戏里有直接对应,整理如下 值得一提的是矮胖子解释了一些贾巴沃克诗的生造词,为后世的译者提供了不少信息。 在爱丽丝和它不欢而散后,听到了蛋壳碎裂的声音,暗示它的跌落,但游戏中矮胖子是因为孵化而裂开

爱丽丝再次前进,遇到了白国王和他的部下,信差告诉了他独角兽和狮子为了王冠争斗,这里的两只动物对应苏格兰和英格兰,并且依旧来源于一首民谣,游戏中冬之钟小剧场长女会引用,并且冬之钟也有很多争斗的对应情节,整理如下 独角兽傲慢,狮子凶恶,游戏中有一定程度上的体现,两者对应的棋子走法一个诡异难测,一个横冲直撞,也在游戏中对应

随后,爱丽丝遇到了前来将她军的红骑士,但埋伏在旁的白骑士反吃了红骑士,护送爱丽丝成王前的最后一段路,这段几乎没有在游戏里的直接对应,除了冬之钟小剧场he中卡罗尔让三姐妹为他挥手帕用了原台词,并且也有说法是白骑士是作者的投影。 但我个人对此有一些猜测,这段很可能对应整个冬之钟剧场,根据一些主流猜测,这段其实是梅贝尔和古兰合谋困住了追击的奈亚,如果我们认为红方是敌方,那么就对应奈亚,指引爱丽丝成王的红王后对应反水的红女王,红骑士表示前来追击的奈亚,白骑士就可能是白女王方的梅贝尔,那么这段剧情就成了,奈亚前来将住格林,梅贝尔前来解围,护送格林到了成王之路

终于,爱丽丝戴上了王冠,格林成了“王”,在此之后的剧情对应很少,青蛙佣人招待爱丽丝去了晚宴,对应游戏中去往古兰晚宴前向海因里希托付女儿,爱丽丝梦醒后红白王后成了黑白两只小猫,对应红女王的台词,可能会在续作有进一步的阐释

至此,对卡罗尔爱丽丝系列的作品就完全结束了,之后有机会可以说说贾巴沃克和猎蛇鲨记

]]>
+ 一些查找和排序算法

二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

容器类

set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

哈希表

哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

检查表中是否存在元素

● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

将元素插入表中

● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

从表中删除一个元素

● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

“罗宾汉哈希表”

string类

str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// count is npos, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

// both pos and pos+count are within bounds, returns [pos, pos+count)
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

// pos is within bounds, pos+count is not, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
// this is effectively equivalent to
// std::string sub4 = a.substr(17, 3);
// since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

try {
// pos is out of bounds, throws
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
} catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
}
}
输出:
abcdefghij
567
hij
pos exceeds string size

`replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

一些实现

优先队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# include "HeapPQueue.h"
using namespace std;

HeapPQueue::HeapPQueue() {
elems = new DataPoint[INITIAL_SIZE] {};
for (int i=0;i<INITIAL_SIZE;i++)
{
elems[i].weight=0;
}
allocatedSize=INITIAL_SIZE;
}

HeapPQueue::~HeapPQueue() {
delete [] elems;
}

int HeapPQueue::size() const {
return logicalSize;
}

bool HeapPQueue::isEmpty() const {
return logicalSize==0;
}

void HeapPQueue::enqueue(const DataPoint& data) {
if (logicalSize+1<allocatedSize)
{
if (logicalSize==0)
{
elems[1]=data;
logicalSize++;
}
else
{
logicalSize++;
int i=1;
while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
{
i++;
}
if (i<logicalSize)
{
DataPoint temp=elems[i];
elems[i]=data;
for(i;i<logicalSize;i++)
{
DataPoint temp_plus=elems[i+1];
elems[i+1]=temp;
temp=temp_plus;

}
}
else
{
elems[i]=data;
}

}
}
}

DataPoint HeapPQueue::peek() const {
return elems[logicalSize];
}

DataPoint HeapPQueue::dequeue() {
DataPoint to_return=elems[1];
if(!isEmpty())
{

for (int i=1;i<logicalSize;i++)
{
elems[i]=elems[i+1];
}
elems[logicalSize]={};
logicalSize--;
}
return to_return;
}

计数排序

首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* Given a Vector<int>, returns the largest number in that Vector. */
int maxOf(const Vector<int>& values) {
/* Bounds-check inputs. */
if (values.isEmpty()) {
error("Can't find the maximum of no values.");
}

int result = values[0];
for (int i = 1; i < values.size(); i++) {
result = max(result, values[i]);
}
return result;
}

/* Given a list of numbers, creates a histogram from those numbers. */
Vector<int> histogramFor(const Vector<int>& values) {
/* Create a histogram with the right number of slots. Initially, all values
* in the histogram will be zero.
*/
Vector<int> histogram(maxOf(values) + 1);

/* Scan across the input vector, incrementing the histogram values. */
for (int value: values) {
histogram[value]++;
}

return histogram;
}

void countingSort(Vector<int>& values) {
/* Edge Case: If the array is empty, then it's already sorted. This is
* needed because we can't take the maximum value of an empty vector.
*/
if (values.isEmpty()) {
return;
}

/* Form the histogram. */
auto histogram = histogramFor(values);

/* Scan across the histogram writing out the appropriate number of copies
* of each value. We track the index of the next free spot to write to,
* as it varies based on how many items we've written out so far.
*/
int next = 0;
for (int value = 0; value < histogram.size(); value++) {
/* Write out the right number of copies. */
for (int copy = 0; copy < histogram[value]; copy++) {
values[next] = value;
next++;
}
}
}

错题集

递归的效率优化

每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

递归计算给定元素的不同结构哈夫曼树的数量

对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int numBSTsOfSize(int n) {

/* Base case: There’s only one tree of size 0, namely, the empty BST. */
if (n == 0) return 1;

/* Recursive case: Imagine all possible ways to choose a root and build the
* left and right subtrees.
*/
int result = 0;

/* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
for (int i = 0; i < n; i++) {
/* Each combination of a BST of i elements and a BST of n - 1 - i elements
* can be used to build one BST of n elements. The number of pairs of
* trees we can make this way is given by the product of the number of
* trees of each type.
*/
result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
}

return result;
}

递归解决吃巧克力问题

求出吃法数量

1
2
3
4
5
6
7
8
9
10
11
12
if (numSquares<0)
{
error("输入数据不能为负数");
}
else if (numSquares<=1)
{
return 1;
}
else
{
return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
}

打印每种吃法

`需要一个辅助向量储存历史记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Print all ways to eat numSquares more squares, given that we've
* already taken the bites given in soFar.
*/
void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
/* Base Case: If there are no squares left, the only option is to use
* the bites we've taken already in soFar.
*/
if (numSquares == 0) {
cout << soFar << endl;
}
/* Base Case: If there is one square lfet, the only option is to eat
* that square.
*/
else if (numSquares == 1) {
cout << soFar + 1 << endl;
}
/* Otherwise, we take take bites of size one or of size two. */
else {
printWaysToEatRec(numSquares - 1, soFar + 1);
printWaysToEatRec(numSquares - 2, soFar + 2);
}
}

void printWaysToEat(int numSquares) {
if (numSquares < 0) {
error("You owe me some chocolate!");
}

/* We begin without having made any bites. */
printWaysToEatRec(numSquares, {});
}

递归解决翻煎饼问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
bool isSorted(Stack<double> pancakes) {
double last = -1; // No pancakes have negative size;

while (!pancakes.isEmpty()) {
/* Check the next pancake. */
double next = pancakes.pop();
if (next < last) {
return false;
}

last = next;
}

/* Pancakes are in increasing order! */
return true;
}

/* Given a stack of pancakes and a flip size, flips that many pancakes
* on the top of the stack.
*/
Stack<double> flip(Stack<double> pancakes, int numToFlip) {
/* Take the top pancakes off the stack and run them into a queue.
* This preserves the order in which they were removed.
*/
Queue<double> buffer;
for (int i = 0; i < numToFlip; i++) {
buffer.enqueue(pancakes.pop());
}

/* Move the pancakes back. */
while (!buffer.isEmpty()) {
pancakes.push(buffer.dequeue());
}

return pancakes;
}

Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
/* Base Case: If the stack is sorted, great! We're done, and no flips
* were needed.
*/
if (isSorted(pancakes)) {
return { }; // No flips
}
/* Base Case: If the stack isn't sorted and we're out of flips, then
* there is no way to sort things.
*/
else if (numFlips == 0) {
return Nothing;
}
/* Recursive Case: The stack isn't sorted and we still have flips left.
* The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
* Try each option and see whether any of them work.
*/
for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
/* Make the flip and see if it works. */
auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
if (result != Nothing) {
/* The result holds all the remaining flips but doesn't know about
* the flip we just did. Insert that flip at the beginning.
*/
result.value().insert(0, numToFlip);
return result;
}
}

/* If we're here, then no matter which flip we make first, we cannot
* get the pancakes sorted. Give up.
*/
return Nothing;
}

递归解决天平问题

1
2
3
4
5
6
7
8
9
10
11
12
13
bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
if (index == weights.size()) {
return amount == 0;
} else {
return isMeasurableRec(amount, weights, index + 1) ||
isMeasurableRec(amount + weights[index], weights, index + 1) ||
isMeasurableRec(amount - weights[index], weights, index + 1);
}
}

bool isMeasurable(int amount, const Vector<int>& weights) {
return isMeasurableRec(amount, weights, 0);
}

想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

递归解决找零问题

不使用记忆的情况

`从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}
/* Base case: You need no coins to give change for no cents. */
else if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (coins.isEmpty()) {
return cents + 1;
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;
/* Pick a coin. */
int coin = coins.first();
/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
coins - coin);
/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}
/* Return whatever worked best. */
return bestSoFar;
}
}

使用记忆进行优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* How few coins are needed to make the total, given that we can only use
* coins from index startIndex and onward?
*/
int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
/* Base case: You need no coins to give change for no cents. */
if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (startIndex == coins.size()) {
return cents + 1;
}
/* Base case: We already know the answer. */
else if (memo[cents][startIndex] != -1) {
return memo[cents][startIndex];
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;

/* Pick a coin. */
int coin = coins[startIndex];

/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
coins, startIndex + 1,
memo);

/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}

/* Return whatever worked best. */
memo[cents][startIndex] = bestSoFar;
return bestSoFar;
}
}

int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}

/* Convert from a Set<int> to a Vector<int> so we have a nice ordering
* on things.
*/
Vector<int> coinVec;
for (int coin: coins) {
coinVec += coin;
}

/* Build our memoization table. Since the number of cents left ranges from
* 0 to cents, we need cents+1 rows. Since the start index of the coin
* ranges from 0 to coins.size(), we make coins.size() + 1 columns.
*
* -1 is used as a sentinel to indicate "nothing has been computed here
* yet."
*/
Grid<int> memo(cents + 1, coins.size() + 1, -1);

/* Now ask how many coins are needed to make the total, using any coins
* from index 0 onward.
*/
return fewestCoinsRec(cents, coinVec, 0, memo);
}

递归穷举付账单

递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
/* Base case: if there's one person left, they have to pay the whole bill. */
if (people.size() == 1) {
Map<string, int> finalPayments = payments;
finalPayments[people.first()] = total;
cout << finalPayments << endl;
}
/* Recursive case: The first person has to pay some amount between 0 and the
* total amount. Try all of those possibilities.
*/
else {
for (int payment = 0; payment <= total; payment++) {
/* Create a new assignment of people to payments in which this first
* person pays this amount.
*/
Map<string, int> updatedPayments = payments;
updatedPayments[people.first()] = payment;
listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
}
}
}
void listPossiblePayments(int total, const Set<string>& people) {
/* Edge cases: we can't pay a negative total, and there must be at least one
* person.
*/
if (total < 0) error("Guess you're an employee?");
if (people.isEmpty()) error("Dine and dash?");
listPossiblePaymentsRec(total, people, {});
}

递归寻找完全平方数列

主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Optional<Vector<int>> findSquareSequence(int n) {
/*Validate input.*/
if (n < 0) {
error("Don't be so negative!");
}

/* Build a set of the numbers 1, 2, 3, ..., n. */
Set<int> options;
for (int i = 1; i <= n; i++) {
options += i;
}
return findSequenceRec(options, { });
}

Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
const Vector<int>& soFar) {
/*Base Case: If all numbers are used, we have our sequence!*/
if (unused.isEmpty()) {
return soFar;
}

/* Recursive Case: Some number comes next. Try each of them and see which
* one we should pick.
*/
for (int next: unused) {
/* We can use this if either
*
* 1. the sequence is empty, so we're first in line, or
* 2. the sequence is not empty, but we sum to a perfect square
* with the previous term.
*/
if (soFar.isEmpty() ||
isPerfectSquare(next + soFar[soFar.size() - 1])) {
/* See what happens if we extend with this number. */
auto result = findSequenceRec(unused - next, soFar + next);
if (result != Nothing) {
return result;
}
}
}

/* Tried all options and none of them worked. Oh well! */
return Nothing;
}

汉诺塔递归

假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

1
2
3
4
5
6
7
8
9
10
11
int moveTower(int numDisks, char start, char finish, char temp) {
if (numDisks == 0) {
return 0;
} else {
int movesOne = moveTower(numDisks - 1, start, temp, finish);
moveSingleDisk(start, finish);
int movesTwo = moveTower(numDisks - 1, temp, finish, start);

return 1 + movesOne + movesTwo;
}
}
]]>
- <h1 id="section">01</h1> -<p>众所周知,black souls的原型,或者说最重要的灵感来源就是爱丽丝梦游仙境以及它衍生的爱丽丝镜中奇遇,我本人一直对游戏和原著的对应关系感到很好奇,但由于工作量很大,一直没下定决心做这件事,但最近突然想到,如果分期做一些整理会不会就没那么麻烦了呢,于是决定开启这个系列。 + <h2 id="一些查找和排序算法">一些查找和排序算法</h2> +<p>二分查找法 <img src="/images/obsidian/20230226101843.png" title="image" alt="图片" /> 最坏情况:log2n - + - + - + - + + + + +
- 基于c++ primer plus的读书笔记 - - https://thinklive1.github.io/2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ - 2023-10-05T14:45:42.281Z + blacksouls原著梗解析 + + https://thinklive1.github.io/2023/09/29/blacksouls%E5%8E%9F%E8%91%97%E6%A2%97%E8%A7%A3%E6%9E%90/ + 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.687Z - c语言部分

基本函数构成

将数组传递为函数参数

1
int fcname(int arg[],int n)

基本输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- cin及其衍生函数返回一个iostream函数的引用,即支持
cin,get().get()
iostream的其他成员
- cout.put()显示字符
- cout.write()显示字符串
- cout<<flush刷新缓冲区
- cout<<endl刷新缓冲区并提供换行符
- dec,hex,oct控制输出数制
hex(cout)控制cout为16进制
- int width()返回字段宽度当前设置
int width(int i)设置字段宽度,返回以前字段宽度
只影响下一次输出
- fill()设置填充用字符
- precision()设置精度,即保留几位小数
- setf()设置各种输出格式
- 流状态stream_state(eof,fail,bad)
- cin.get(ch)读取下一个字符,跳过换行符和空白
- cin.get()读取空白和换行符
- cin.get()get的基础上读取到换行符并丢弃
- cin.read()读取内容,但不会在末尾加空字符
- cin.peek()读取输入流下一个字符但不抽取
- cin.putback(ch)把一个字符放到输入流最前

文件输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
写入文件
ofstream fout;//ofstream继承ostream
fout.open("hello.txt");
fout << "i'm adding sth"
|| ofstream fout("hello.txt");
读取文件也类似
fin >> ch||string
关闭流
fout.close()
fin.close()
检测文件是否打开
if (!fin.is_open())
设置文件输入输出格式
ios_base::

基本逻辑运算符

break打断循环 continue,跳到更新表达式前开始执行 非const引用的函数不接受const参数

基本数据类型

结构数组

stname;
1
2
3
4
5
6
7
8
9
10
11
stname stobj\[int x] =
{
{}
{}
}
union(类似结构,但相同数据类型只存一种)
每个指针需要一个*用于初始化
int * intlist=new int [10]
delete-new
delete []-new []
typedef typename aliasname

名称空间

1
2
3
4
5
#ifndef HNAME_H
#define HNAME_H


#endif

如果在遇到另一个定义HNAME_H的头文件时,将他忽略

作用域: 1默认情况下,函数中声明的变量作用域位于代码块内,如果函数内外都声明一个同名变量,运行至内部代码块使用内部,离开代码块使用外部 2静态变量存在于整个程序运行周期,脱离作用域后只是无法使用并不消失 代码块外声明且不带static关键字:链接性外部,可以在其他程序使用 代码块外声明,且使用static:链接性内部,可以在整个程序使用 代码块内声明,且使用static:作用域于代码块内,但始终存在//由于静态变量只可以定义一次,所以即使离开代码块后变量依旧存在,且值不变,直到下一次修改 3运算符::放置于变量前时,使用同名变量(如果有)的全局版本 4namespace{

} 无法放置于代码块内,因此默认为全局名称,可以囊括声明和定义,可以随时添加 定义于类声明的函数自动成为内联函数

c++特性

class

1声明构造函数时,尽量使用explicit(显性转换)前缀,防止隐性转换带来的问题 mutable(摆动的)前缀声明变量,表示这些变量可能在const成员函数内被更改 用const_cast<>和static_cast<>与this指针可以实现const成员函数向非const的转变,反之则是错误的

2class初始化成员时,按构造函数声明变量的顺序,因此初始化成员时最好也以此顺序初始化 如果不希望class有copy和赋值(=)操作,则应该在private里定义copy和=运算符

3基类引用可以指向派生类对象,无需进行强制类型转换

4定义于类声明的函数自动成为内联函数

5类的函数对所有对象共用,但数据则各自私有

6要创造类对象数组,该类必须有默认构造函数

7只有一个构造函数参数的构造函数可以用于类的自动转换 classname t; t=20; 如果想禁止这种转换,可以声明explicit给构造函数

8类声明中可定义对于某种基本类型的转换函数 operator int();//可声明为显式转换,尽量避免过多的转换造成二义性

9如果定义类成员参数为static,则它在程序中只有一个地址,可以被所有类成员共享 但通过static实现共享成员时,需要重新定义复制和赋值函数来避免问题

动态类的注意事项

*构造函数中如果用new初始化指针成员,则应该在析构函数中使用delete new对应delete,new[]对应delete[] 对多个构造函数,应用和析构函数兼容的new来初始化成员 重构复制和赋值运算符来实现深复制

10对于使用new创建的类,使用delete时其析构函数才会被调用 如果在使用new时,将对象地址赋予一个指针时,如果删除指针,则对应的对象会调用自己的析构函数 对与使用定位new创建的类对象,需要显式调用析构函数 object->~classname(); 且应该以创建顺序的相反顺序调用,因为后创建的对象可能依赖于前者

类继承

公有继承

class sonclassname: public fatherclassname 派生类继承了基类的公有接口和数据 但只能用基类public和protected函数访问基类私有数据 派生类可添加函数和数据成员 派生类需要自己的构造函数,并由于权限问题,其构造函数必须包括基类构造函数,并且同样可以使用成员初始化列表 指针 基类指针和引用可以在不显式转化的情况下指向派生类对象反过来却不行 虚函数

纯虚函数 virual typename func() const=0; 含有虚函数的类不能创建实例,只能用作基类

访问控制(protected) 派生类成员函数可以访问protected成员,不能访问private成员

私有继承

使用私有继承,基类的公有成员和保护成员都成为派生类的私有成员,只可以在派生类的成员函数中使用,可以实现has_a关系 私有继承访问基类方法时需要调动基类的命名空间 访问基类对象 如果要直接访问基类对象,则需要调用强制类型转化将派生类转化为基类

保护继承

保护继承时,基类的公有和保护成员都成为派生类的保护成员,基类接口在派生类中可用

通过using指令可以让私有函数被当前作用域可用

命令行参数

int main(int argc,char* argv[]) argc为参数个数 argv为参数组成的字符串

字符输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流
<string>
重载符号+实现拼接
str.size()
输入字符串使用getline(cin,str)
结构数组
struct stname;
stname stobj[int x] =
{
{}
{}
}
字符函数库<cctype>
isspace(ch)测试是否空白
isalpha(ch)是否字符
isdigit()是否数字
ispunct()是否标点

1
2
3
4
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流

<string> 重载符号+实现拼接 str.size() 输入字符串使用getline(cin,str) 结构数组 struct stname; stname stobj[int x] = { {} {} } 字符函数库<cctype> isspace(ch)测试是否空白 isalpha(ch)是否字符 isdigit()是否数字 ispunct()是否标点

指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1,c++没有溢出检测机制,
char name[]="hello";
char c =name[10]导致未定义行为
2,用一个常量指针指向常量需要两次const
const char* const name="hhh"
如果需要一个class专属常量,则使用
static const ***
实现文件中,const int classname:: ***
对于宏:
template <typename T>
inline functionname
3,const 出现在*左侧表示被指物为常量,右侧表示指针为常量指针
4,函数名就是函数的地址
double pam(int);
double(*pt)(int);
pt即为函数指针
如果需要一个函数以相同相同返回值和参数的函数为一个参数,则可以考虑函数指针
5,内联函数不能递归
6,引用容器时,如果迭代器不引用,仍然传递临时副本o
7,函数传递指针时按值传递,当向函数传递指针时,指针是按值传递的!这意味着你可以改变被指向的数组内容,因为在调用函数时,这些元素不会被复制!这意味着你可以改变被指向的数组的内容,因为这些元素在函数被调用时并没有被复制。另一方面,如果你改变了所指向的数组,这种改变在函数之外不会持续,因为你只改变了指针的拷贝,而不是原来的指针本身。

智能指针

auto_ptr<string> 和<unique_ptr>指针采用所有权模型,对特定对象只有一个智能指针可以拥有它,只有拥有它的指针可以删除它 shared_ptr<string>追踪引用对象的智能指针数量,最后一个指针过期时才会调用delete 使用new分配内存才能使用auto_ptr,unique_ptr

异常

try_catch

1
2
3
4
5
6
7
8
9
10
11
try{
func();
}
catch(errortype e1){

}
func()
{
do sth;
throw(error_type e1);8
}

栈解退 假设try块没有直接调用引发异常的函数,而是调用对引发异常的函数进行调用的函数,则程序从引发异常的函数跳到包含try块和处理程序的函数(追踪到一个地址位于try块的返回地址) 其他异常特性

exception类

exception类可作为其他异常类的基类,用what的虚函数(返回一个字符串)重载来指示错误类型 失败时返回空指针的语法

1
int * pi= new (std::nothrow) int;

未捕获异常

未捕获的异常会使程序调用函数terminate(),默认情况下,terminate()调用abort()函数,可以指定terminate()调用的函数来修改其行为

一些新特性

关键字

关键字nullptr表示空指针

RTTI(运行阶段类型识别)

dynamic——cast

danamic_cast<type *> (pt) 如果可以安全将pt转化为type*指针,返回对象地址,否则返回空指针 如果对引用使用,错误时返回bad_cast异常

typeid和type_info

typeid返回对type_info对象的引用,type_ifo是定义在typeinfo的类,重载==和!=预算符,例如 typeid(obj1)==typeid(obj2)

类型转换运算符

1
2
//用于执行各种类型的数值转换static_cast <typename> (expression)
//转换是允许隐式转换时才能通过(派生类和基类可以互相转换)

移动语义 通过指针转移右值的地址给新对象 或通过std::move()将左值转化为右值

someclass()=default default关键字显式声明编译器创建默认构造函数,复制构造函数 delete用于禁止类中的函数

关键字override可用于覆盖虚函数定义

匿名函数

返回类型编译器自动确定,可直接作为函数指针使用

1
[] (double x) {return x%3==0;} 

可以返回类型后置

1
[] (double x)-> double{int y = x;return y-x;}

可以给匿名函数命名

]]>
+ 01

众所周知,black souls的原型,或者说最重要的灵感来源就是爱丽丝梦游仙境以及它衍生的爱丽丝镜中奇遇,我本人一直对游戏和原著的对应关系感到很好奇,但由于工作量很大,一直没下定决心做这件事,但最近突然想到,如果分期做一些整理会不会就没那么麻烦了呢,于是决定开启这个系列。 由于是第一期,我就扯一些闲话,爱丽丝的原著可谓有着非常深远的影响,首先,他就是最著名的童话之一,在儿童里的传播极为广泛,在我小时候就听说并读过这个作品,但说实话爱丽丝的原著对孩童来说实在太过思维跳脱,导致我虽然通读了几遍但完全没看进去,考虑到当时的儿童文学相比现在的完善可以说几乎不存在,这本书可谓有着相当的意义,不过我毕竟没有研究过相关文学史所以不多评价了,对于爱丽丝的原著,我最深刻的印象就是其无比丰富的想象力以及跳脱的情节(由于卡罗尔是数学家,他还塞了不少数学梗进去),可能这就是莉耶芙喜欢这本书的初衷吧。 此外,爱丽丝这一形象与整个不思议之国以无数的二次创作形象疯狂地在各种娱乐作品里传播,关于这点,我认为是爱丽丝原著符号性强烈的特点导致的,永无止境的茶会,跳进兔子洞等元素非常具有符号性,它们奇怪到引人注目,但谁也不知道到底指的什么,可能有意义,可能没有意义,二次创作者可以非常自由地阐释这些元素,因此导致了在二次元文化里,爱丽丝近乎成了最常见的一个人名或者说符号 最后则是它的现实作者,金属冶炼在欧美文化里是个很敏感的话题,关于原作者此方面的谣言可以说满天飞,但对此我只能说疑罪从无,没有直接证据表明这一点,就连一些间接证据在我看来也很明显是牵强附会,基于道德的角度,我们不该用一些间接证据指责两个世纪前人物的私事,此外,black souls是毋庸置疑的架空世界观作品,不管怎么编故事也和现实中的卡罗尔毫无关系。 当然black souls设定下的卡罗尔也是个经常被讨论的问题,由于冬之钟那个崩坏的adv,很多人认为black souls的卡罗尔是个炼金术师,但是很明显小剧场不过是哪个支配者的大作,而且是个很有虫虫风格的作品,没有任何证据表明black souls设定下现实的卡罗尔干了相同的事,总的来说我认为black souls世界观的卡罗尔,除了他一直深爱爱丽丝以外和爱丽丝一家的关系是没有确切信息的,而且这种爱也可能不是男女之爱,只是柏拉图之恋罢了。 好吧,关于原著以外的讨论就说到这里,接下来我们开始具体情节的对照分析。 第一章的开头,小爱丽丝和姐姐一起坐在河边,姐姐在看一本没有插图没有对话的书,让小爱丽丝感到无聊。 书在black souls中是个很常见的意象,没有插图的书只在牛津学院的回忆中提到过一次,读书的倒是有几个,一代的爱丽丝02一直看着书,书上的内容似乎是格林被玛丽苏毁灭时的遗言,此外,一代的尸龙也在读着书,而且二代时她也在河边,根据她念出来的部分,其实就是我们这个世界的卡罗尔描写邪龙贾巴沃克被打倒的那首诗,个人猜测有可能black souls中卡罗尔没有给爱丽丝送出去的礼物其实是他的作品集,后来卡罗尔被玛丽苏捉走,这本书则被尸龙拿走,最后,二代的白女王诺登也是个看书人,这本书格林无法阅读,但0sen下能看到轮回次数 由于02不是任何人的姐姐,白女王虽然很御姐,但原型明显是白兔先生,所以对应度最高的其实是贾巴沃克,此外尸龙摸鱼的时候摘花,而此时的爱丽丝也有摘花的意图,可能暗指温柔的尸龙姐姐摘花编成花环想送给爱丽丝(迫真) 随后就是经典的爱丽丝跟着匆忙的白兔先生进了兔子洞的环节,此时的白兔先生声称自己是急着去找公爵夫人 兔子洞在一二代都有对应,一代追寻着原著顺序,跟着白兔,从兔子洞跳下就能到达不思议之国,二代却是相反的,格林先到坠落之间,然后才到兔子洞 此外,原著对坠落的描述是,途中有很多书架以及各种柜子,这点在坠落之间和兔子洞都有体现,爱丽丝在坠落后第二次见到了匆忙的白兔先生,而按通常的流程,也是格林过了兔子洞后进行度为1才能见到白兔诺登,此外原著中爱丽丝第一次来到的门厅顶上有一排灯,这可能是图书馆的进行度灯的灵感来源,原著中爱丽丝用钥匙打开一扇门后来到了放有变大变小药的房间,游戏可以直接到达,喝了我和吃了我是非常经典的原作梗。 以上是爱丽丝原著第一章和游戏的对应关系,那么今天就到此为止了

02

接下来开始第二章的分析 吃下蛋糕后的爱丽丝身形变得非常巨大,也因此挤不进她想去的花园,此时她哭泣的眼泪形成了泪水池,对应bs的血泪之池,有种说法是红偶像紫餐产生的血泪形成了血泪之池,如果从致敬原著看的角度倒是不无可能 这时白兔先生经过,被爱丽丝吓跑,留下了手套和扇子,扇子有着让人变小的能力,但此时不知情的爱丽丝一边扇扇子一边开始自我怀疑,正是这时她提到了梅贝尔这个名字。 根据爱丽丝的说法,梅贝尔什么都不知道,住在又破又小的房子,没有玩具还要天天念书,对应bs中的梅贝尔,某种程度上讲还挺还原的 随后被扇子变小的爱丽丝掉进了泪水池,并在池子里遇到了一只耗子以及其他动物,她们一起游上了岸。 接下来就是第三章了 此时耗子开始上起了历史课,这段剧情在bs有两个对应点,一个就在酒馆里耗子直接出场给我们上课,而则是牛津学院的回忆提到爱丽丝讨厌历史课。 随后为了让湿透的衣服变干,渡渡鸟为她的动物朋友们召开了一场赛跑会,跑完宣布大家都赢了,但奖品让爱丽丝颁发,甚至包括爱丽丝自己的奖品,于是爱丽丝给所有人每人一颗糖,给自己发了一只丁真,很对应游戏血泪之池的渡渡赛跑会,但游戏中只有杀害渡渡会得到一颗糖果,杀害其它动物没有奖品(私藏奖品的屑),附近可以捡到糖果,此外,游戏和原著中的赛跑参与者是不完全对应的,赛跑中白鹅会提到鹦鹉和鹰缺席了,原因吗,因为涉及一些书本以外的东西我们以后再说 此后螃蟹母子的对话会提到好脾气的牡蛎,可能对应bs的dlc1嚣张的牡蛎 第四章中爱丽丝被白兔错认为了玛丽.安,白兔家的女仆,这就是为什么被白兔诺登剥夺神力的虫虫改名成玛丽.安并且穿着女仆装。 爱丽丝喝了让自己再次变大的药水,然后被挤进了房子里无法动弹,此时她吐露了自己不想长大的愿望,随后,蜥蜴比尔被派去搬来梯子,爬进烟囱里查探情况,被爱丽丝一脚踢飞出去,这段对应bs大圣堂里比尔搭梯子的剧情,顺便一提,比尔除了倒霉蛋属性外在bs里几乎全被魔改了,合理怀疑是莉耶芙加了什么私货进去。 随后爱丽丝吃下了被扔进来的蛋糕,再次变小,并逃进了一个长着高大蘑菇的森林,并在蘑菇上遇到了抽烟的青虫,对应游戏中的孢子之森,第四章结束 也就是说原作爱丽丝的路线就是兔子洞-血泪之池-孢子之森,这也是为什么进行度0时会在森林遇到爱丽丝的幻象,虽然这一路线并不一定遇到比尔 格林和希夏的对话基本对应原作爱丽丝和它的见面,一开始不理不睬,但离去时希夏开口挽留,原著毛虫让爱丽丝背了首威廉老爹的诗,对应孢子之森的boss,游戏与原作不同的是,原作的虫子告诉爱丽丝吃下蘑菇可以变大变小,游戏中直接让格林去找公爵夫人 爱丽丝见过青虫后有段剧情,爱丽丝吃下蘑菇后脖子变得很长,被一只孵蛋的鸽子认作来吃蛋的长虫,这里译本的长虫其实就是大蛇的意思,这段剧情在游戏也有两个对应,一是游戏中的物品鸽子蛋,孢子之森能捡到鸽子蛋,杀害希夏会掉落鸽子蛋,正好符合原作顺序,对其的描述是少女不吃生蛋,蛇却很喜欢吃,也符合原作,bs中的蛇只有蛇神,而0sen下看到他的脖子很长,也对应原著情节;第二个疑似的对应点则是卡罗尔川的矮胖子,可以孵化出雏鸟,但除此以外和原著没什么对应

03

接下来我们开始第六章,公爵夫人的章节 公爵夫人馆外能遇到名为幼犬的怪物,这应该对应书中第四章,遇到青虫前爱丽丝遇到的小狗,馆内可以遇到鱼和蛙之听差,原作中他们分别是女王派来邀请打縋球和公爵夫人处接受邀请信的佣人。 公爵夫人是比较还原原著的一个角色,基本上所有行为举止都有对应。爱丽丝初见她的场景和游戏中几乎完全对得上,婴儿和猪的转化则用sen值来实现(顺便一提屠宰场也有类似的转换),只有柴郡猫没有出现,但馆内一张挂画上则会出现柴郡猫,这张挂画上随着sen值不同也会出现猪和婴儿的转变,此外,由于公爵夫人还原度很高,我把台词中的对应点用图整理如下 公爵夫人另一个原型,也是她名字和贪食属性的由来则是一幅画作,这幅画作(比较哈人就不放了)可能的历史原型是一位贵族女性,她在历史上有大嘴的外号,并且和丈夫并不恩爱(甚至没同过房?),这解释了里线中她的台词 游戏中柴郡猫瞬忽隐忽现,还有标志性的微笑都出自此章,不过对她来说似乎更认同爱丽丝家的猫的身份,然而她又部分否定了戴娜的身份 值得一提的是,此前我们提到的原作路线都是有着某种程度上的认证的,到森林的路线有爱丽丝幻影,随后有希夏的指引,但从公爵夫人开始跳脱出了梦游仙境,让我们去了镜中奇遇,并且地图到了这里也确实是死路,如果继续按公爵夫人的指引,到达库因兰德这条死路后也确实找到了爱丽丝,虽然格林并不知情。 而如果我们想要继续原著路线,就要踏上不同的路,经过牛津学院到达永不终焉的茶会,为什么呢? 关于茶会我很有些个人想法,但我们先从原著的角度说起 虽然一二代都有茶会,但比较对应原著茶会一段的是二代的茶会,原著中帽匠和三月兔被柴郡猫钦定为疯子,可以说是整部作品里最荒诞的一段,在bs中也不遑多让,我们先从三人的现实原型说起,帽子屋的原型是中世纪的帽匠,由于工艺会用到水银,所以有着疯疯癫癫的形象(游戏也提到这点),三月兔的原型是一句俗语,这句俗语的由来据说是兔子三月处于繁殖期而狂躁不安,所以会有这种人设,睡鼠原型则是一种常见的宠物,非常嗜睡,当时人们喜欢把它养在茶壶里。 我们分人物说起,首先是帽匠 原著一见到爱丽丝,帽匠就大喊没位置了,并且抛出了乌鸦桌子的谜语,和游戏一样,这段谜语若干年后卡罗尔才公布答案,所以游戏的帽子屋说不知道答案。 随后,爱丽丝说自己说的和想的一样,三人一人一句地反驳了她,其中除了三月兔抛出的两句话,都是主语宾语单项包含关系,但游戏中爱丽丝的话由帽子屋说出,并只有睡鼠保留着这种逻辑关系。 面包黄油的对话几乎完全致敬原著。 原著爱丽丝与柴郡猫对话提及此刻是五月,和帽子屋对话提及今天是4号,游戏中时计塔的密码1852正是爱丽丝的生年,所以游戏中帽子屋会说擅长happy birthday 帽匠会提及,自己和时间闹翻了(红心女王的说法是谋杀时间),所以茶会被永远定格到这个时间,餐盘只能越积越多,这可能是游戏中帽子屋不死能力的来源,监禁后她离开了茶会,所以又可以杀死了,此外,游戏中狂鸟一定程度上和时间有着关系,并且帽子屋很讨厌她,或许和原著这段情节有关(但帽子屋又称呼时间为先生) 随后是三月兔,原著中三月兔头顶缠着稻草,卡罗尔说这表示她疯了,游戏致敬了这点。 原著的三月兔打翻了牛奶,游戏中是红茶 最后是睡鼠,睡鼠在原著中唱歌和讲故事都和游戏里对应,故事中三个小姑娘的名字对应利德尔三姐妹,讲故事时,三人责怪爱丽丝打岔,在游戏中里线战斗对话有体现。 好了,以上是和游戏原著比较对应的地方,接下来我就说说对茶会的个人理解,再强调一下,都是个人理解。 茶会可以说是bs2中一个很重要的地图,它和牛津学院直接相连,并且两张地图连续有一个回忆,而进入牛津学院主流的路线就是从精神病院开始通过路德维希市街,见证伊迪斯和杰克的悲剧,顺便一提关于利德尔三姐妹,我之后会出个特辑,这里先不谈,漫布迷雾的街道明显是在neta伦敦,并且卡罗尔是英国人,曾在牛津学院任职,这条路线可以说是最贴近现实的一条路。 此外,如果要防止狂鸟唱歌,就必须先来到茶会去往时计塔,并且时计和箱庭的运转息息相关,而狂鸟唱歌的目的应该就是让格林别乱跑了去找爱丽丝,此外,不思议之国的大部分地方都很有着阴森的氛围,而且弯弯绕绕,只有茶会非常狭小却坐拥一个篝火而且阳光明媚氛围悠闲,几乎可以磨灭格林的斗志了,茶会的三个参与者就更有意思了 如果我们给三人归纳一个关键词,一个是疯狂,一个是爱欲,一个是睡梦,三者加在一起几乎概括出了整个二代的特点,这恐怕是奈亚不想让格林意识到的,此外,来到茶会必然会遇到伊迪斯,按原作顺序之后就是红心女王罗丽娜,两人是乱入者,且都曾和卡罗尔关系亲密,奈亚不希望她们引发卡罗尔的回忆,所以才会让夫人把我们支开。 对这三人和她们的象征意义,疯狂和爱欲其实不必多说,但睡梦其实是一条相对的暗线,我一直认为寿司是一个很喜欢前后对照的作者,所以就让我们来分析一下,不少npc会提及此处是个梦境,但最早是在op,游戏的开头是格林苏醒,看到爱丽丝,然后不知道为什么再次睡去,因此我们如果认真看开头就会知道不思议之国是个梦境,那么为什么设定成梦境呢,首先是由于协助创造箱庭的诺登的原型是所谓的幻梦境之主,其次呢就是因为原著的结局会发现爱丽丝的奇遇是一场梦,光是这点就很有意思,两者揭露梦境的时间点完全相反。 那么问题来了,已经在梦境了,如果再次做梦不就有了梦中梦?而如果是梦境是虚假,梦中梦则是虚假的虚假,会不会是真实呢?格林做过几次梦中梦呢,第一次是精神病院看到师匠,第二次是孢子之森的幻觉爱丽丝,第三次是海底的旅社,第四次是冬之钟adv,牛津学院的月面比较特殊就不论了,这几次梦中梦,虽然未必都是真实,但都揭示了部分真相或者现实。 既然如此,有一个人就很奇怪了,睡鼠,她是格林外唯一一个能在梦境中沉睡的人,如果是格林自己的梦还可以做梦中梦,但睡鼠一个梦境中的角色怎么还能入梦呢?除非她只是装睡,对话中睡鼠会说她没有睡,所有人的对话她都没有听漏,这很有可能就是真相(虽然里线又说真在睡),并且她随后说了一句要杀了所有人,然后辩解说是梦话,结果全监禁后她真的这么做了。 因此个人猜测睡鼠表面虽然入梦,但其实是最清醒敏锐的,她有着监视格林的任务,一旦格林不照着剧本做梦,滞留在一次轮回中,就会把风险清除掉,逼迫他进入下个轮回。 而h结局中在冬之钟我们能看到三月兔和帽子屋,她们的对话反过来看就是冬之钟的本质,为什么只有这两个人呢?一是三人的对话提到除了睡鼠两人都想来冬之钟,二则是根据我的想法,此时格林意识上已经从梦里醒来,剩下的问题就是奈亚的爱欲,以及舞台带来的疯狂,也就是茶会的这两个人的象征。 当然,以上不过是个人解读,大家看个乐就行。 可能有人问,那么一代的茶会呢?这个由于时间线的原因我们以后再讲。

04

让我们开始第八章的分析 七章末尾,爱丽丝被疯疯癫癫的三人惹恼,离开了茶会,进入了一片森林,在她迷路时出现了一道门,让她回到了最初的兔子洞大厅,随后她利用变大变小的能力走进了最初看到的庭院。 这段路线,如果我们忽略茶会怎么回到兔子洞这个问题,可能对应利德尔墓地到心脏庭院,墓地这块确实是森林,并且进入庭院的入口确实是一道门,虽然顺序颇有些问题。 原著中,入口旁的三个扑克园丁忙着把种错的白玫瑰刷成红心王后喜欢的红色,随后被王后发现要杀头,游戏中只有一个庭师在干活,而且不是上漆而是上血,另外两个则在说格里芬的闲话。可能是rpgmaker的素材问题,原著和游戏的扑克种类对不上 原著中红心王后杀头的表达翻译过来大概是这样的:他们的头没了吗?士兵的回答是:“他们的头不见了”由此王后认为确实杀头了,这里是个文字游戏,原著中这三个园丁藏了起来,头确实看不见了,但没有杀头,这可能是游戏中红心女王不看处刑场面的由来。 杀头后王后邀请爱丽丝打追球,但是球棍是火烈鸟,球是刺猬,两者都会在游戏出现,区别是火烈鸟0sen变成弯曲的球棍,球则在0sen才出现 打球的时候公爵夫人来向爱丽丝搭话送了她几句教训,对应游戏中公爵夫人出现在追球场并且满口教训,随后王后再次出现在爱丽丝面前,带她回去打球,这次过程中王后把除了国王的所有人判了死刑,随后国王赦免了他们。 可能是由于实际上外来者的缘故,红心王后也被魔改得很厉害,基本上只有性格和杀头的口头禅是还原原著的,此外,原著的红心王后虽然没杀过一个人的头(狮鹫的说法),但被所有身边人畏惧,这点也沿用到了游戏中,红心王后可能的原型是当时的英国女王,这也是为什么游戏中红城bgm是掷弹兵进行曲。公爵夫人会说红女王和红心女王一样残暴,这段可能来自于卡罗尔自己对两位皇后的解释。原著的红心国王直接删掉了,是梦游仙境唯二个游戏里没有对应的主要人物(还有个是红桃杰克),当然也有可能对应格林(笑)。 之后,王后让狮鹫带爱丽丝去听假海龟的故事,对应游戏里罗丽娜发布布告让部下去讨伐食尸鬼,因为会在那里见到假海龟。原著中在女王走远后,狮鹫说到女王从来没有成功杀过一个人的头,对应游戏中格里芬说女王不敢看处刑场面 这里顺便一提,狮鹫是卡罗尔任职的牛津学院的三一学院的院徽,假海龟出自当时用牛肉汤代替昂贵海龟汤的习惯,原著中狮鹫懒散,假海龟则惶恐不安,和游戏对应,假海龟哭哭啼啼地讲起了自己的故事,它曾在深海的学校上课云云,这里是非常典型卡罗尔造生词环节,游戏中有原台词化用 说完上课的事后,狮鹫提出跳龙虾方块舞,游戏中则是龙虾舞,为什么呢,我给大家三秒钟猜一下,因为格里芬是方块骑士,所以已经有方块了,这很可能是方块骑士身份的来源,因为除此以外原著只有一些方块廷臣,其中的歌是假海龟唱的,游戏中也有体现,格里芬说自己不记得歌词 随后狮鹫让爱丽丝背了几首诗,最后假海龟唱了一首海龟汤,对应游戏中让假海龟做料理的台词 关于爱丽丝的线索,女王和格里菲会引导格林去市街,市街的卡面来打会引导格林去墓地方向,随后线索就断了。 这之后就是梦游仙境最后一个场景,审判庭,关于审判这件事的信息,翻遍二代也只能找到狮鹫去邀请比尔当陪审员这件事,其中,他们会说审判已经发生过一遍,那么是在哪呢? 很有可能是在一代的不思议之国。已然终结的茶会,最明显的是守门的班达斯奈奇,他提出的问题和答案部分和原著的审判相对应,茶会中的一只兔子会提到疯帽子三人以及爱丽丝的消失,这正是原著剧情,收集童话出现的里门,爱丽丝排列成类似法庭陪审团的形式面朝格林,这很有可能也是表示审判。 此外,我也有些个人想法,杀害02得到的缎带物品描述是追寻梦中的爱丽丝,这几乎可以肯定指的二代,而爱丽丝原著正是在最后的审判后告诉我们一切都是梦,然后见到了姐姐,而这和一代也在读书的尸龙姐姐勉强对得上,审判后的爱丽丝消失了,奈亚丽丝用格林取代了她的位置一直梦游到了审判剧情前,这样一来就构成了一个循环,爱丽丝梦游仙境结束后开始格林梦游仙境,这是很有寿司风格的前后对照。 此外,还有一种可能的解读是,审判其实是奈亚丽丝内部召开的,最后判决结果是把爱丽丝01驱逐出去,产生了红偶像 总之,审判这段原著情节在bs有没有对应大家就见仁见智吧 好了,这样一来对梦游仙境的解析就结束了,下一期作为拾遗篇,我会说说卡罗尔和利德尔三姐妹在游戏中的暗线。

拾遗篇

查尔斯·道奇森,一个天赋型的数学家,笔名刘易斯.卡罗尔,最知名的作品是两本以知名幻想角色爱丽丝为主角的作品,与同时代知名的柯南道尔(福尔摩斯系列的作者)同是一个灵异研究学会的成员,还有一个较晚出生的知名的同时代人是克苏鲁体系的作者洛夫克拉夫特 有意思的是以上提到的三人分别是三种文学流派的奠基人,并且这三种衍生文化不同程度地影响了bs系列 1855年,卡罗尔23岁,结识了自己任职学院的院长一家,一年后认识了三姐妹,随后的时间他时常和这家的三姐妹一起聚会,1962年7月4日,一个黄金的午后,当时三姐妹的长女罗丽娜13岁,次女10岁,三女8岁,与卡罗尔一起泛舟湖上,卡罗尔讲了一个日后成为梦游仙境原稿的故事,两年后整理成了一部名为地底冒险的手稿送给次女。 1863 年 6 月,利德尔一家和卡罗尔之间的关系突然破裂,没有直接证据能说明原因,几个月后有所缓和,但已经无法还原如初的美好了。 再之后,长女没有在历史上留下痕迹,次女和三女都和一位王子有过绯闻,但可能因为身份原因没有成,可怜的三女在即将结婚时22岁因病早逝(精神病院的开门次数),似乎最受上天关爱的次女于28岁结婚,成为哈格里夫斯夫人。 这是我们这个世界历史上的卡罗尔和三姐妹的故事。那么bs世界里这四人发生了什么呢?

最直接的证据是六段苦涩的回忆,虽然对他们的来龙去脉或是真假完全没有确论,但它们提供了大部分相关信息,我们按现实时间顺序一个一个说起。 卡罗尔川的回忆直接用了梦游仙境的卷首诗,描述了这个故事的原初,并且由于卡罗尔生活时期正是英国盛世,泰晤士河污染严重,黄金午后的那条河流从属于泰晤士河,和游戏中污染的描述也对得上 按现实顺序随后的应该是牛津学院的回忆,卡罗尔和利德尔一家的交恶 随后则是槌球场,这里应该对应现实中黄金午后的两年后,卡罗尔送给了爱丽丝地底冒险手稿,这部手稿有卡罗尔自己的插画,但并非圣诞礼物,卡罗尔曾和爱丽丝一家打槌球玩,因此会出现在槌球场,但游戏中此时二家似乎没有交恶,因此bs中可能存在顺序调换。 之后就是纯粹的架空时间线了 之后是叹息的海边,回忆中摄影的阁楼有现实对应,正是牛津大学的建筑,回忆描述了两人的再次重逢,至于为什么是海边,可能是因为卡罗尔在1876年出版的《猎蛇鲨记》,这是他最后一部知名作品,次女和卡罗尔的重逢历史上没有什么资料,事实上,即使卡罗尔逝世时,次女也就46岁,不可能是老婆婆,但梦游仙境的改编的戏剧于1886年圣诞节期间上映,卡罗尔也去看了,顺便一提,演睡鼠的是一位叫多萝西的女士。这是有记载的卡罗尔最后一次见到次女,而有记载的次女最后一次与卡罗尔有交集,是在1932年卡罗尔逝后的100年诞辰,这时她已经80岁了 再后面是库因兰德的回忆,库因兰德的女王原型是镜中奇遇的红女王,而镜中奇遇出版于1871年。这段回忆似乎提到卡罗尔把另一个人当做代餐,可能是bs世界观的罗丽娜? 最后是完全架空的茶会回忆,和现实基本没有关系了。 其次还有若干原著彩蛋在游戏中使用,如卷首诗,也就是第一段回忆的little和利德尔同音,血泪之池的鹦鹉和小鹰分别是长女和三女的书中化身,睡鼠的故事也化用了三姐妹的名字等

卡罗尔在bs中和现实基本对应得上,但还有的问题是,猎蛇鲨记,贾巴沃克等作品的来源没有交代,其中贾巴沃克这首诗尸龙基本给我们念了一遍,有可能原稿在她手上,此外卡罗尔虽然终身未婚,但依然有很多朋友,如猎蛇鲨记就受一位忘年交的启发,可能是冬之钟小剧场那张照片中的女人 顺便一提,现实中的弗朗西斯.利德尔1965年出生,自他记事起卡罗尔和利德尔一家应该都不怎么来往了,现实中的三姐妹和当时的大部分贵族女性一样在家中由私教授课,不可能叫卡罗尔老师

之后我们来分别探讨一下三姐妹在bs的暗线 现实中的长女资料最少,但书中的鹦鹉有卖弄自己年纪大的特点,并且有一种说法是,当年的长女对卡罗尔非常依恋,这些特点沿用到了游戏中,有可能bs中的卡罗尔倾吐虚假爱意的对象就是她。根据其自述,罗丽娜向邪神献祭灵魂才会来到不思议之国,但时间点未知,如果是在次女后,那么游戏中的罗丽娜是完全的少女心性就很奇怪了。还有一种说法是,罗丽娜和她的母亲名字一样,所以小剧场那张照片的真身有可能是……不过我觉得这可能很小就是了 心脏女王也是个谜点重重的角色,如果我们给有梦游仙境原型的誓约角色所需魂数量排序,那么由小到大依次是白兔,渡渡,比尔,希夏,公爵夫人与假海龟,帽子屋,心脏女王 其中除了假海龟都参照原作出场顺序,她虽然是乱入者,但不思议之国大部分住民都会提到并认同女王是名义上的统治者,她不知为何能指挥魔兽化的手下,让唯一有理智的格里菲去全国巡逻,每天用审判来控制人口,还给大工批了大把建筑费用来上达天听,不知道是奈亚的命令还是什么其他原因,她确实做了很多管理不思议之国的事,此外,还是唯一一个非格林子女却有里线战斗的 三女伊迪丝在游戏中是精神病院的boss,对于她怎么来到箱庭,仅有的线索是混沌迷宫和电影院的两段没头没尾的故事,游戏里和三女私奔的王子,很可能也是杰克,这位角色现实原型之一很可能是利奥波德王子,正如前文所说,据传他曾与伊迪丝相爱,伊迪丝22岁早夭后,王子为她抬棺,王子和伊迪丝一样病弱,患有血友病,三女辞世的8年后,王子以30岁的年龄逝世,这或许是游戏中他也住院的原因,另外两个明显原型是开膛手杰克和福尔摩斯,或许是因为卡罗尔曾被看做开膛手杰克的嫌疑人,而同时代柯南道尔也曾经研究过这个案件,顺便一提上文王子的一个侄子也是一大嫌疑人 伊迪丝在冬之钟小剧场里头戴着枯萎的花圈,可能暗示着她的早逝,并且多次有小鹰的元素出现,但罗丽娜除了大姐作风却没有明显的鹦鹉元素,这点也有些让人在意 最后是次女,这里的次女指的是观星引来奈亚的人类个体,关于这个个体的信息反而是最少的,只知道她和卡罗尔心心相惜却被拆散,她和现实次女的履历是否一样未知,她的最终去向未知,牛津学院的学寮长是否就是她父亲的灵魂所化也未知。 关于现实中的对应,现实的次女并非常见的金发形象而是黑发,并且和梦游仙境的爱丽丝有很多差异,游戏中似乎没怎么提到过发色,不知道如何设定,次女和南丁格尔是同时代的人,因此院长认识爱丽丝可能是认识人类状态的次女,此外,小剧场的次女会有很多致敬原著的台词,出示如下 在群星之夜后,似乎她的名字成为了禁忌,也是里线剧情的关键,关于次女我还有一个,, 等等,次女的名字,为什么,我想不起来次女的名字,对了,她的名字,她的名字不就是 爱丽丝.利德尔 勿呼其名,唤则得知,蠕动前行而来 縺ゥ縺?@縺ヲ遘√'谤「縺辅↑縺代l縺ー縺ェ繧峨↑縺??縺ァ縺呐° 繧「繝ェ繧ケ繧呈尔縺励※缧ゅい繝ェ繧ケ繧呈?縺励※缧ゅい繝ェ繧ケ繧贞ソ倥l縺ェ縺?〒缧 诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ 诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ诨帙@縺ヲ

ex01

相较梦游仙境,镜中奇遇在bs中的对应情节明显变少,但依旧有分析的价值 首先是镜中奇遇的卷首诗,这首诗提到了卡罗尔此时和现实的爱丽丝年龄相差一倍,语气中某种程度上可能透露了卡罗尔对无法回到往日时光的惋惜,不管怎么说,此时爱丽丝已经长大了,看童话故事的美好时光已经不会回来了 开篇剧情中爱丽丝在和戴娜生下的小猫玩,对应普通结局少女的房间中柴郡猫说自己产下小猫后死去,虽然我们不知道现实的戴娜是怎么死的。 随后爱丽丝会提到镜子屋,也就是镜子里的相反的房间,这在之后成为整本书的主题,在bs中镜子屋对应公爵夫人提到了通过血泪之池镜子才能到达的镜之国,但同样和镜子有莫大关系的还有一位小红帽,值得一提的是,镜之国库因兰德是为数不多没有柴郡猫出现的篝火。 随后爱丽丝在镜子屋看到了一些会说话的棋子,并随意摆布它们,这段有点像bs奈亚的作风 她翻到了一首叫贾巴沃克的诗,当然这里其实是卡罗尔引用之前的作品,贾巴沃克这首诗非常晦涩难懂,以后有机会我会谈谈在它在bs里的对应。 之后爱丽丝飞跃滑下楼梯,想跑去屋外的花园,这里的下楼梯法在冬之钟小剧场有对应

爱丽丝想走到一座小山丘俯视花园上,但怎么走都会回到原点,这 里可能对应精神病院的走法,也可能对应库因兰德的迷宫,于是她只能转而去往一个小花园,遇到了一群会说话的花,这些花对应一代圣森和不思议之国的会说话的花,以及在bs2中,红女王的房间里的花,一些花很吵闹,爱丽丝威胁把它们拔下来,对应道具咒骂之花, 随后爱丽丝遇到了红王后,原著中的红王后被卡罗尔描述为典型的家庭教师,原型可能就是爱丽丝的家教,bs中红女王的名字直接用了这位家教的名字,有一种说法是卡罗尔利用三姐妹来追求她造成两家决裂 爱丽丝羡慕地说想成为王后,红王后告诉她需要前进八格,然后拉着她全力奔跑,贡献了一句经典台词,前进八格成后这是国际象棋的规则,而红王后的台词在bs中对应库因兰德的一个留言和冬之钟柴郡猫的台词 值得一提的是在原著中有重要意义的棋盘在bs中也有同样的重要性,红女王的库因兰德遍布着棋子,梅贝尔在自己的箱庭部下棋局,而白女王则把王冠,也就是走了八步后成王的关键放在了冬之钟,可以推测原著中想要成后的爱丽丝其实对应着bs中想要得到改变权能而成王的格林。 红王后指引爱丽丝成后的走法,提到了需要乘火车,对应去库因兰德的火车 火车上爱丽丝遇到了一只会说话的虫子,在一阵颠簸后她们发现自己安静地坐在树下,爱丽丝和它讨论了一下命名学,虫子告诉爱丽丝前方有着无名之森,对应bs里的那张地图,这只虫子可能也对应无名之森的一只虫形怪物 无名之森里爱丽丝遇到了一只小鹿,对应bs中无名之森的小鹿,但bs中通过无名之森才能坐火车,与原著相反 本章的末尾,爱丽丝遇到了双子

ex02

爱丽丝接下来遇到的是崔德尔双子,二者一开始站立不动,让爱丽丝觉得他们是蜡人偶,也就是蜡像,游戏中反了过来,游戏中双子提到了站立不动的格林是蜡像的可能 两兄弟的原型是一首英国童谣,童谣提到了丢失的拨浪鼓和飞来筑巢的乌鸦,在游戏双子的台词有体现,筑巢的大鸟应该就是伊迪丝 随后两兄弟给爱丽丝背了首海象和木匠的诗,大意是海象和木匠偏小牡蛎来做客,然后把它们吃完了,游戏中很明显海象对应希伏契,木匠对应大工,吃牡蛎的剧情也在希伏契对话中有体现,且,双子誓约对话会提到两人 之后,爱丽丝发现了附近正在做梦的红王,在双子对话中有原意复用 双子中的蒂看到了他弄坏的拨浪鼓,让两兄弟起了矛盾,对应游戏中的台词,随后两人约定决斗,可能对应游戏里的双子相残,就在这时乌鸦飞了过来,打断了决斗 书中的两兄弟按棋谱来说是白方,这解释了她们为何与dlc3的克里米亚有一定关系

为了躲避大鸟,爱丽丝逃进树林遇到了白王后,与严肃的红王后不同,白王后非常随和友好,并且她声称自己是倒着过日子的,这解释了白女王诺登管理重启轮回的职能 交谈一会后,爱丽丝突然转移到了一间商店里,店主是一只绵羊,发生了很多怪事后爱丽丝又闪现到了小船上和绵羊一起划船,对应游戏里老羊的台词 书中这段空间转换非常频繁,可能因此寿司在老羊商店里放了一堆来源不明的谏言

一连串的转换后爱丽丝看到了矮胖子,这位角色也来自于一首英国民谣,矮胖子很多台词台词在游戏里有直接对应,整理如下 值得一提的是矮胖子解释了一些贾巴沃克诗的生造词,为后世的译者提供了不少信息。 在爱丽丝和它不欢而散后,听到了蛋壳碎裂的声音,暗示它的跌落,但游戏中矮胖子是因为孵化而裂开

爱丽丝再次前进,遇到了白国王和他的部下,信差告诉了他独角兽和狮子为了王冠争斗,这里的两只动物对应苏格兰和英格兰,并且依旧来源于一首民谣,游戏中冬之钟小剧场长女会引用,并且冬之钟也有很多争斗的对应情节,整理如下 独角兽傲慢,狮子凶恶,游戏中有一定程度上的体现,两者对应的棋子走法一个诡异难测,一个横冲直撞,也在游戏中对应

随后,爱丽丝遇到了前来将她军的红骑士,但埋伏在旁的白骑士反吃了红骑士,护送爱丽丝成王前的最后一段路,这段几乎没有在游戏里的直接对应,除了冬之钟小剧场he中卡罗尔让三姐妹为他挥手帕用了原台词,并且也有说法是白骑士是作者的投影。 但我个人对此有一些猜测,这段很可能对应整个冬之钟剧场,根据一些主流猜测,这段其实是梅贝尔和古兰合谋困住了追击的奈亚,如果我们认为红方是敌方,那么就对应奈亚,指引爱丽丝成王的红王后对应反水的红女王,红骑士表示前来追击的奈亚,白骑士就可能是白女王方的梅贝尔,那么这段剧情就成了,奈亚前来将住格林,梅贝尔前来解围,护送格林到了成王之路

终于,爱丽丝戴上了王冠,格林成了“王”,在此之后的剧情对应很少,青蛙佣人招待爱丽丝去了晚宴,对应游戏中去往古兰晚宴前向海因里希托付女儿,爱丽丝梦醒后红白王后成了黑白两只小猫,对应红女王的台词,可能会在续作有进一步的阐释

至此,对卡罗尔爱丽丝系列的作品就完全结束了,之后有机会可以说说贾巴沃克和猎蛇鲨记

]]>
- <h1 id="c语言部分">c语言部分</h1> -<h2 id="基本函数构成">基本函数构成</h2> -<p>将数组传递为函数参数</p> -<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">int fcname(int arg[],int n)</span><br></pre></td></tr></table></figure> + <h1 id="section">01</h1> +<p>众所周知,black souls的原型,或者说最重要的灵感来源就是爱丽丝梦游仙境以及它衍生的爱丽丝镜中奇遇,我本人一直对游戏和原著的对应关系感到很好奇,但由于工作量很大,一直没下定决心做这件事,但最近突然想到,如果分期做一些整理会不会就没那么麻烦了呢,于是决定开启这个系列。 - + - + - + - +
- 基于斯坦福cs106b的c++数据结构笔记 - - https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ + blacksouls人物解析 + + https://thinklive1.github.io/2023/09/29/black%20souls%E4%BA%BA%E7%89%A9%E8%A7%A3%E6%9E%90/ 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.687Z - 一些查找和排序算法

二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

容器类

set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

哈希表

哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

检查表中是否存在元素

● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

将元素插入表中

● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

从表中删除一个元素

● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

“罗宾汉哈希表”

string类

str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// count is npos, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

// both pos and pos+count are within bounds, returns [pos, pos+count)
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

// pos is within bounds, pos+count is not, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
// this is effectively equivalent to
// std::string sub4 = a.substr(17, 3);
// since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

try {
// pos is out of bounds, throws
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
} catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
}
}
输出:
abcdefghij
567
hij
pos exceeds string size

`replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

一些实现

优先队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# include "HeapPQueue.h"
using namespace std;

HeapPQueue::HeapPQueue() {
elems = new DataPoint[INITIAL_SIZE] {};
for (int i=0;i<INITIAL_SIZE;i++)
{
elems[i].weight=0;
}
allocatedSize=INITIAL_SIZE;
}

HeapPQueue::~HeapPQueue() {
delete [] elems;
}

int HeapPQueue::size() const {
return logicalSize;
}

bool HeapPQueue::isEmpty() const {
return logicalSize==0;
}

void HeapPQueue::enqueue(const DataPoint& data) {
if (logicalSize+1<allocatedSize)
{
if (logicalSize==0)
{
elems[1]=data;
logicalSize++;
}
else
{
logicalSize++;
int i=1;
while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
{
i++;
}
if (i<logicalSize)
{
DataPoint temp=elems[i];
elems[i]=data;
for(i;i<logicalSize;i++)
{
DataPoint temp_plus=elems[i+1];
elems[i+1]=temp;
temp=temp_plus;

}
}
else
{
elems[i]=data;
}

}
}
}

DataPoint HeapPQueue::peek() const {
return elems[logicalSize];
}

DataPoint HeapPQueue::dequeue() {
DataPoint to_return=elems[1];
if(!isEmpty())
{

for (int i=1;i<logicalSize;i++)
{
elems[i]=elems[i+1];
}
elems[logicalSize]={};
logicalSize--;
}
return to_return;
}

计数排序

首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* Given a Vector<int>, returns the largest number in that Vector. */
int maxOf(const Vector<int>& values) {
/* Bounds-check inputs. */
if (values.isEmpty()) {
error("Can't find the maximum of no values.");
}

int result = values[0];
for (int i = 1; i < values.size(); i++) {
result = max(result, values[i]);
}
return result;
}

/* Given a list of numbers, creates a histogram from those numbers. */
Vector<int> histogramFor(const Vector<int>& values) {
/* Create a histogram with the right number of slots. Initially, all values
* in the histogram will be zero.
*/
Vector<int> histogram(maxOf(values) + 1);

/* Scan across the input vector, incrementing the histogram values. */
for (int value: values) {
histogram[value]++;
}

return histogram;
}

void countingSort(Vector<int>& values) {
/* Edge Case: If the array is empty, then it's already sorted. This is
* needed because we can't take the maximum value of an empty vector.
*/
if (values.isEmpty()) {
return;
}

/* Form the histogram. */
auto histogram = histogramFor(values);

/* Scan across the histogram writing out the appropriate number of copies
* of each value. We track the index of the next free spot to write to,
* as it varies based on how many items we've written out so far.
*/
int next = 0;
for (int value = 0; value < histogram.size(); value++) {
/* Write out the right number of copies. */
for (int copy = 0; copy < histogram[value]; copy++) {
values[next] = value;
next++;
}
}
}

错题集

递归的效率优化

每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

递归计算给定元素的不同结构哈夫曼树的数量

对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int numBSTsOfSize(int n) {

/* Base case: There’s only one tree of size 0, namely, the empty BST. */
if (n == 0) return 1;

/* Recursive case: Imagine all possible ways to choose a root and build the
* left and right subtrees.
*/
int result = 0;

/* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
for (int i = 0; i < n; i++) {
/* Each combination of a BST of i elements and a BST of n - 1 - i elements
* can be used to build one BST of n elements. The number of pairs of
* trees we can make this way is given by the product of the number of
* trees of each type.
*/
result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
}

return result;
}

递归解决吃巧克力问题

求出吃法数量

1
2
3
4
5
6
7
8
9
10
11
12
if (numSquares<0)
{
error("输入数据不能为负数");
}
else if (numSquares<=1)
{
return 1;
}
else
{
return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
}

打印每种吃法

`需要一个辅助向量储存历史记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Print all ways to eat numSquares more squares, given that we've
* already taken the bites given in soFar.
*/
void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
/* Base Case: If there are no squares left, the only option is to use
* the bites we've taken already in soFar.
*/
if (numSquares == 0) {
cout << soFar << endl;
}
/* Base Case: If there is one square lfet, the only option is to eat
* that square.
*/
else if (numSquares == 1) {
cout << soFar + 1 << endl;
}
/* Otherwise, we take take bites of size one or of size two. */
else {
printWaysToEatRec(numSquares - 1, soFar + 1);
printWaysToEatRec(numSquares - 2, soFar + 2);
}
}

void printWaysToEat(int numSquares) {
if (numSquares < 0) {
error("You owe me some chocolate!");
}

/* We begin without having made any bites. */
printWaysToEatRec(numSquares, {});
}

递归解决翻煎饼问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
bool isSorted(Stack<double> pancakes) {
double last = -1; // No pancakes have negative size;

while (!pancakes.isEmpty()) {
/* Check the next pancake. */
double next = pancakes.pop();
if (next < last) {
return false;
}

last = next;
}

/* Pancakes are in increasing order! */
return true;
}

/* Given a stack of pancakes and a flip size, flips that many pancakes
* on the top of the stack.
*/
Stack<double> flip(Stack<double> pancakes, int numToFlip) {
/* Take the top pancakes off the stack and run them into a queue.
* This preserves the order in which they were removed.
*/
Queue<double> buffer;
for (int i = 0; i < numToFlip; i++) {
buffer.enqueue(pancakes.pop());
}

/* Move the pancakes back. */
while (!buffer.isEmpty()) {
pancakes.push(buffer.dequeue());
}

return pancakes;
}

Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
/* Base Case: If the stack is sorted, great! We're done, and no flips
* were needed.
*/
if (isSorted(pancakes)) {
return { }; // No flips
}
/* Base Case: If the stack isn't sorted and we're out of flips, then
* there is no way to sort things.
*/
else if (numFlips == 0) {
return Nothing;
}
/* Recursive Case: The stack isn't sorted and we still have flips left.
* The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
* Try each option and see whether any of them work.
*/
for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
/* Make the flip and see if it works. */
auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
if (result != Nothing) {
/* The result holds all the remaining flips but doesn't know about
* the flip we just did. Insert that flip at the beginning.
*/
result.value().insert(0, numToFlip);
return result;
}
}

/* If we're here, then no matter which flip we make first, we cannot
* get the pancakes sorted. Give up.
*/
return Nothing;
}

递归解决天平问题

1
2
3
4
5
6
7
8
9
10
11
12
13
bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
if (index == weights.size()) {
return amount == 0;
} else {
return isMeasurableRec(amount, weights, index + 1) ||
isMeasurableRec(amount + weights[index], weights, index + 1) ||
isMeasurableRec(amount - weights[index], weights, index + 1);
}
}

bool isMeasurable(int amount, const Vector<int>& weights) {
return isMeasurableRec(amount, weights, 0);
}

想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

递归解决找零问题

不使用记忆的情况

`从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}
/* Base case: You need no coins to give change for no cents. */
else if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (coins.isEmpty()) {
return cents + 1;
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;
/* Pick a coin. */
int coin = coins.first();
/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
coins - coin);
/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}
/* Return whatever worked best. */
return bestSoFar;
}
}

使用记忆进行优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* How few coins are needed to make the total, given that we can only use
* coins from index startIndex and onward?
*/
int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
/* Base case: You need no coins to give change for no cents. */
if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (startIndex == coins.size()) {
return cents + 1;
}
/* Base case: We already know the answer. */
else if (memo[cents][startIndex] != -1) {
return memo[cents][startIndex];
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;

/* Pick a coin. */
int coin = coins[startIndex];

/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
coins, startIndex + 1,
memo);

/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}

/* Return whatever worked best. */
memo[cents][startIndex] = bestSoFar;
return bestSoFar;
}
}

int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}

/* Convert from a Set<int> to a Vector<int> so we have a nice ordering
* on things.
*/
Vector<int> coinVec;
for (int coin: coins) {
coinVec += coin;
}

/* Build our memoization table. Since the number of cents left ranges from
* 0 to cents, we need cents+1 rows. Since the start index of the coin
* ranges from 0 to coins.size(), we make coins.size() + 1 columns.
*
* -1 is used as a sentinel to indicate "nothing has been computed here
* yet."
*/
Grid<int> memo(cents + 1, coins.size() + 1, -1);

/* Now ask how many coins are needed to make the total, using any coins
* from index 0 onward.
*/
return fewestCoinsRec(cents, coinVec, 0, memo);
}

递归穷举付账单

递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
/* Base case: if there's one person left, they have to pay the whole bill. */
if (people.size() == 1) {
Map<string, int> finalPayments = payments;
finalPayments[people.first()] = total;
cout << finalPayments << endl;
}
/* Recursive case: The first person has to pay some amount between 0 and the
* total amount. Try all of those possibilities.
*/
else {
for (int payment = 0; payment <= total; payment++) {
/* Create a new assignment of people to payments in which this first
* person pays this amount.
*/
Map<string, int> updatedPayments = payments;
updatedPayments[people.first()] = payment;
listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
}
}
}
void listPossiblePayments(int total, const Set<string>& people) {
/* Edge cases: we can't pay a negative total, and there must be at least one
* person.
*/
if (total < 0) error("Guess you're an employee?");
if (people.isEmpty()) error("Dine and dash?");
listPossiblePaymentsRec(total, people, {});
}

递归寻找完全平方数列

主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Optional<Vector<int>> findSquareSequence(int n) {
/*Validate input.*/
if (n < 0) {
error("Don't be so negative!");
}

/* Build a set of the numbers 1, 2, 3, ..., n. */
Set<int> options;
for (int i = 1; i <= n; i++) {
options += i;
}
return findSequenceRec(options, { });
}

Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
const Vector<int>& soFar) {
/*Base Case: If all numbers are used, we have our sequence!*/
if (unused.isEmpty()) {
return soFar;
}

/* Recursive Case: Some number comes next. Try each of them and see which
* one we should pick.
*/
for (int next: unused) {
/* We can use this if either
*
* 1. the sequence is empty, so we're first in line, or
* 2. the sequence is not empty, but we sum to a perfect square
* with the previous term.
*/
if (soFar.isEmpty() ||
isPerfectSquare(next + soFar[soFar.size() - 1])) {
/* See what happens if we extend with this number. */
auto result = findSequenceRec(unused - next, soFar + next);
if (result != Nothing) {
return result;
}
}
}

/* Tried all options and none of them worked. Oh well! */
return Nothing;
}

汉诺塔递归

假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

1
2
3
4
5
6
7
8
9
10
11
int moveTower(int numDisks, char start, char finish, char temp) {
if (numDisks == 0) {
return 0;
} else {
int movesOne = moveTower(numDisks - 1, start, temp, finish);
moveSingleDisk(start, finish);
int movesTwo = moveTower(numDisks - 1, temp, finish, start);

return 1 + movesOne + movesTwo;
}
}
]]>
- - - <h2 id="一些查找和排序算法">一些查找和排序算法</h2> -<p>二分查找法 <img src="/images/obsidian/20230226101843.png" title="image" alt="图片" /> 最坏情况:log2n + 尸龙贾巴沃克
1
在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!

象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),尸龙姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对尸龙的整个人物进行解析 尸龙在爱丽丝镜中奇遇的原型是一首小诗,这首诗的大意是勇者手提沃伯尔之剑斩杀邪龙贾巴沃克,游戏中也承袭了这一设定,贾巴沃克一直都以死尸的形象登场 要解析这一角色,我们首先从最直接的行为说起,按游戏的时间线,尸龙姐姐大概做了以下这些事 1把童话(具体哪本未知,根据混沌迷宫的狼外婆信息推测可能是小红帽)给了渴望母爱的玛丽.苏,从而激发了虫虫的创作能力,导致她创造出一代的箱庭。顺便一提,关于尸龙玛丽苏的关系,游戏里没有直接证据支持姐妹说,混沌迷宫提到黑山羊有两个子嗣,米兰达认为尸龙有黑山羊的气息,且明显尸龙玛丽苏有一定关系,这些是确定的,但并未明说姐妹,有人从克苏鲁的设定中寻找论据,但本人对克系了解不多在此不评价。 2红偶像约会中电影《三人的茶会》提及茶会时期的三人曾经打倒过贾巴沃奇,不知是否和尸龙有关,此外尸龙也曾被昔日的勇者,如今的猎头兔打倒,自称在之后洗心革面,但相关资料太少,我们不知道是不是她放水或另有隐情 3格林被引导进玛丽苏的箱庭开始一代的故事,此时尸龙(不知道玛丽苏是否知情)已经乱入到一代的不思议之国,为格林一行人提供帮助,通关d结局后找她对话,她会直接把二代给剧透了,不过由于时间线上d结局应该直接接上二代,所以“正史”上可能没有这件事,顺便一提,一代的不思议之国是爱丽丝的箱庭,或者说玛丽苏的仿造品,也没有定论,所以很难推测尸龙是入侵还是本来就在那里 4来到二代时间线,由于不思议之国是奈亚的箱庭,而黑山羊则是奈亚的“配偶”,所以尸龙出现在这倒是理所应当,此时的尸龙以四噩梦之一的身份登场,,但工作内容则是在卡罗尔川上堆雪人,以及在格林面前装出温柔大姐姐的形象,十足的关系户做派。 里路线中,格林和米兰达等人可以先后对战三噩梦,以及杀死其余两个噩梦后现出真身的尸龙,值得一提的是这似乎是她全系列中唯一一次全力出手,并且在此战中死亡,但考虑到支配者的特性,是否死透了依旧存疑 以上就是尸龙在系列中的行动,接下来我将对这些行动的目的与尸龙的性格进行归纳。 尸龙首先是一个安静的观察者,一代中她只是在一棵树下扮尸体,二代则在河边堆雪人,如果格林不找她,在里线之前不会和她有任何交集,然而,隐藏和善表面下的真相是尸龙其实是个性格扭曲唯恐天下不乱的乐子人,是她启发了玛丽苏创造自己的黑童话箱庭,间接引发之后所有的故事,而一开始的目的可能只是以玛丽苏面对求而不得的母爱痛苦挣扎的样子为乐,也是她诅咒了狩猎邪龙的英雄,使兔子一族成为贪食尸体的魔兽,其中被沃波尔斩下头颅可能是她行事风格的分界线,其自述死前曾是无恶不作的邪龙,在复活后变得收敛,但其实依旧不改邪龙本质,只是变得只在关键时刻推波助澜 而将这两种性格统一起来的则是她的创作欲,没错,和玛丽苏一样,尸龙对创作也有自己的执念,在玛丽苏涌现起黑暗的创作力之后,尸龙意识到,玛丽苏那邪恶的灵魂一定程度其实是自己的作品,如果说玛丽苏是支配者中第一个创造故事的人,尸龙就是第一个“创作者”,这激发出她内心最深层的欲望,那就是创作出足够黑暗污秽的灵魂,方法则是让一个灵魂在无尽的痛苦与求而不得中循环。 可以说在这点上尸龙和奈亚有一定的共同点,就是让格林经历无数次的痛苦循环,但二者还是有着分歧,奈亚想要的是格林求而不得的爱,尸龙则想要格林本就污秽的灵魂更加黑暗。 这时我们就可以理解尸龙的行为了,由于里线实际上也处于轮回之中,所以对尸龙来说,告诉格林一些真相只会让他的反抗更加激烈,也会在反抗之后更加绝望,这样才符合她的目的。 而以上依旧是贾巴沃克的表层性格,而她隐藏最深的性格则是扭曲的独占欲,在卡罗尔川的地牢中有个四个雪人,分别是玛丽苏,小红帽,爱丽丝和格林,此外,班达斯奈奇的住处也有着一个写着想将其变为收藏品的雪人(sen0才能看到真相),可见尸龙内心最深的欲望其实是独占欲,培育最污秽的灵魂,随后将其收藏起来,这才是尸龙的愿景,但她为何要隐藏这一欲望呢,在qf尸龙失败的逆监禁剧情里,由于尸龙发现格林的灵魂已经黑暗到想要独占自己,尸龙就会唯一一次直接暴露自己的独占欲来收割这个丰硕的成果,然而,奈亚或者其他支配者绝不会容忍这种行为,所以一旦尸龙试图独占格林就会立刻被排除出世界,这就是尸龙一直压抑着独占欲的原因。 此外,根据dlc3入口处的对话以及数量庞大的雪人,或许可以猜测尸龙曾经一边观察一边玩弄过很多灵魂,但这些灵魂最后都因为经历过多的痛苦和绝望后变得麻木,因此才会对有着无穷成长性的格林视若珍宝 一切温柔的言语都不过是为了将格林引导向更绝望的结局,独占污秽的黑之魂,玩到腻后就扔掉,对贾巴沃克之魂的描述为包藏在虚伪的母性之下的独占欲之影可谓恰如其分。 值得一提的是,独占欲这种感情不止在尸龙一人上出现,大部分支配者都有着这种感情,如白之女王诺登就承认自己多次有独占格林的想法,爱丽丝01也曾吐露自己害怕不可控制地想要独占格林,但她们与尸龙的区别则是,她们能够理解人类的爱,并为了人类的幸福选择放手,与红白女王的对比或许也是尸龙人物形象设计的一个目的 现在可以做一个总结了,尸龙姐姐是一个对格林有着强烈爱意的角色,她的母性是虚伪的,但这种爱意却不是,尽管她扭曲,残酷,自私,虚伪,但是她始终知道自己要做什么并理性地付出行动,即使失败了也不失风度从容自若,相较于虫虫几乎写在脸上的扭曲性格,直截了当的作恶行径,以及一有挫败就大呼小叫的行径,尸龙的感情更加内敛,行事也更加隐秘,但可谓是个很有恶人魅力的反派角色 同时,由于bs的碎片化叙事并且尚未完结,关于尸龙依旧有很多谜团,例如她和玛丽苏以及其他支配者的具体关系,里线中她是不是仍然在演戏,她究竟为何会给玛丽苏童话书,尸龙等三噩梦和三个爱丽丝的关系等等,就期待续作的解答了 大家都来和尸龙姐姐做朋友吧,尸门

玛丽苏

玛丽苏,作为bs中自称的女主角,是bs唯二个三代都有出场(包括红森)的支配者,还有一个是贾巴沃克),在此过程中做过的好事可谓数不胜数,罄竹难书,我们来按着时间线整理一下 1一开始的玛丽苏是个渴望母爱的孩子,尽管我们不知道bs设定下一开始的支配者到底会不会有类似人类的亲情,她掌管自己的世界,倾听子民的祈祷,开始感到厌烦,这时贾巴沃克不知出于什么目的,送了她一本童话书,这本书,我们不知道是哪个童话,但本人猜测很可能这本书的作者是玛丽苏第一个抓住的,并在黑之魂的融合中有重要地位,根据青鸟的文本,卡罗尔并不是第一个抓住的素材,所以基本可以排除梦游仙境,结合男主角格林的名字和混沌迷宫的狼外婆,我个人猜测是小红帽,她开始渴望创作自己的故事来打动母亲,至少一开始是这样,她派遣属下四处收集童话作者的灵魂作为素材,同时肆意进行同人创作。 2玛丽苏的处女作是小红帽,也是她第二得意的作品,根据一些信息,小红帽的灵魂可能以现实世界的一个女学生为素材,在魔改剧情的同时,她还给了小红帽注定20岁早逝的设定,并可能赋予了小红帽通过镜子穿梭位面之类的特殊能力来担任女主角,但不知道为什么她又不满意,想做一个男主角出来,但她对小红帽的善后却颇有些问题,小红帽不仅杀穿了红森,而且还能意识到她这个黑幕的存在。 3缝合了众多童话作家灵魂的格林诞生了,并被赋予了给周围的女主角带来不幸的设定,格林污秽的黑之魂有成为支配者的潜质,玛丽苏甚至还大胆地保留了他的部分创作能力,因为最关键的改变权能在她手上,为什么叫做格林则未知,可能是最初的童话书就是格林童话的一本,这之后格林不知道为什么,以什么身份在一个叫不思议之国的地方和叫爱丽丝和祈祷主的存在开起了茶会,随后格林与爱丽丝01相恋,嫉妒的祈祷主呼唤了玛丽苏,导致格林被带走了,连同格林不知何时创造出的故事们也被篡改 4基于以上提到的各种童话故事素材,玛丽苏魔改出了失落帝国的箱庭,把格林放进去经历一次次绝望故事的轮回,自己则担任女主角欣赏故事,还设计把母亲叫了进来欣赏自己的大作。不知多少次循环后,这个大好局面被打破了,母亲黑山羊为了逃离这个世界和她战斗,连圣森都磨灭了,战胜母亲后,奈亚丽丝前来捡漏带走格林进行新一轮追寻爱的游戏,本来想顺带着把玛丽苏也灭了,但在诺登的劝阻以及可能的其他考量下放过了她 5奈亚,红女王,白女王中的某位或若干位剥夺了她的改变权能,把她囚禁在库因兰德,失去权能的她改名为玛丽安,但不知何时也不知何人前来探访了她,到格林试图从梦中醒来的里线,玛丽安乘乱逃出,由于正史上不太可能发生f结局,所以此时应该是g结局,也有可能正史上g结局有少许与游戏不同,不管怎么说此时的玛丽安应该被格林小红帽两人打败,但h结局中可以看到她没有死,而且不知道怎么逃了出来 可以说,bs中的一切悲剧,玛丽苏至少有五成功劳,接下来让我们来分析一下玛丽苏的角色特质。 首先,最直接的一点,玛丽苏是个典型的支配者,高高在上地支配着人类这样的低等种族,但玛丽苏特殊之处在于,她可能是最能理解人类感情的支配者之一,首先我们就可以看到她居然渴望所谓的母爱,而根据2代大部分支配者的表现,即使因融入皮套逐渐有了感情,也没有第二个有亲情这种非常类似人类感情的支配者,此外,她还以玩弄人类的灵魂为乐,当然有这种兴趣的支配者恐怕不少,但这股风气可以说是玛丽苏带起来的,也是她最先玩出各种花样。 因此可以引出玛丽苏的第二个特点了,她是很像人类的一个支配者,尽管理解非常片面,但她确实懂得并拥有不少人性,而她为什么这么喜欢玩弄人类呢?这也很容易理解,一般来说越通人性的动物越被人类亲近,逗猫逗狗远远比逗蚂蚁有意思,因为这些宠物的智力和人类更接近,人类可以很容易地理解它们在想什么,然后在逗弄它们的过程中获得一种智力上的优越感,以及一种“支配感”,这恐怕就是玛丽苏看到自己编排的好戏上演的感觉。 这点可以说是我们对玛丽苏进行解析的基石,毕竟任何角色首先都是人的投影,而人性越丰富,就有越多的性格侧面。 玛丽苏第三个特点就是由此衍生的纯粹性,当然,此处并不是说纯洁善良云云,而是某种意义上的纯粹之恶,很多支配者在扮演人类后都会被皮套影响而恐慌或纠结,但玛丽苏却没有这种烦恼,她以融入人类扮演人类为乐(小精灵也算类人种族),她作为支配者的漆黑本性和人性之恶完美地兼容了,不会有徘徊二者之间的身份认同问题,而她大部分所作所为也就是为了践行人性之恶,什么是恶呢,比较狭隘的解释就是为了为了自己的利益或者取乐而伤害他人,而玛丽苏的邪恶就很纯粹,就是为了取乐,甚至有损自己利益也要作恶,如果解救了被囚禁的玛丽苏,此时她会自认为东山再起,但她想的不是第一时间抹杀已经成长了的格林或者藏起来,而是想再让格林经历一次悲惨的故事,可以说她作恶的动机相当纯粹,也相当执着。 在此之上的第四个特点,就是她的创作者身份,很多支配者都会赞扬她的创作能力,连奈亚构建的不思议之国都有不少玛丽苏箱庭的影子,但这种创造力也只是对于支配者来说了,如果我们用人类的视角看如何呢?寿司在访谈时轻蔑地说到“她说到底也只是玛丽苏,也只能整点二次创作了”可以说道出了玛丽苏所谓创作的本质,说到底,玛丽苏就是那种典型的黑深残小鬼,把一个可能有很多种解释的作品曲解为单一的猎奇世界观,当然不是说这样不行,如果原创一个黑深残世界观自娱自乐当然是可以接受的,但玛丽苏的行为就是最恶劣的一种同人女行为,魔改原来的作品,把自己做成角色代入进去搞cp,还要把所有其他角色踩一遍,情节和人物关系只要对自己代入的角色有利就行,然后把这部除了自己看谁也不会喜欢的同人拿给原作者看,我就不详细说这种行为的恶劣程度了,但这种作品折射出来的创作观我必须要辩驳一下。 当然,本视频所有讨论只局限于二次元文化内, 荒木飞吕彦认为漫画有四要素,角色、剧情、世界观、主题,我们就用这四个维度来剖析玛丽苏的所谓创作。 首先是角色,直接创作一个鲜活的灵魂对强大的支配者来说也是一件难事,所以对于角色的选取,玛丽苏很可能都是使用现实存在的灵魂然后再魔改来适配进童话或者传说的人物,因此她笔下所谓角色虽然很多但其实并不是她自己的功劳,而她为了把这些灵魂塞进角色对设定随意删改,把小红帽的外婆和母亲缝成了一笔烂账,人物关系更是一团乱麻,怎么方便怎么来,角色设定连基本的自洽也做不到,水平着实不敢恭维 随后是世界观,失落帝国这个箱庭本质上来说就是个童话故事的缝合体,没有历史演化,没有详细设定,这并不是一个鲜活的世界观,只不过是一个临时搭建的舞台而已,当然,很多线性的故事并不需要一个多详尽的世界观,在这点上玛丽苏只能说无功无过 最后是剧情和主题,玛丽苏的主题是简单粗暴的黑深残,剧情则是当常规的rpg剧本演到最后的happy end时毫无铺垫伏笔地急转直下变成bad end,当然,能设置这么大规模的箱庭,还写了不少支线剧情,证明玛丽苏确实是有一些笔力的,但首先,她的角色基本靠抓人,故事则都有童话原型,故事演变她只需要把握大方向,其他可以让角色自己来,而最后没有任何铺垫的bad end依旧表明了她创作的失败,如果一个设定没有任何铺垫和暗示,直到使用时才抛出,那只能证明这部作品情节编排的失败,因为一部作品的生命周期不是作者创作出来就结束了的,而要等到读者看完理解了故事才会结束,这个过程作者读者应该处于相对公平的地位,根据故事的设定,人物有充分的理由这样行动,这样才能让读者认同这个故事,而玛丽苏却完全相反,滥用作者的权能让故事不仅没有逻辑,还自相矛盾,很明显,对玛丽苏来说她是作者也自认为是唯一的读者,那些被抓走被改造的灵魂不过是用完即扔的工具罢了,不需要自圆其说,只要自己看得高兴就行了,或许就支配者的立场来说她不过是自娱自乐罢了,但对人类(至少灵魂上是人类),以及同样作为创作者的格林来说,首先就绝不可能认同这种恶行,更不可能认同自己的作品被改成这样的烂作 说到这里,就可以讨论一下玛丽苏对于格林的看法了,直观地说,是玛丽苏创造了名为格林的污秽黑之魂,但其实在最初,是格林等童话作家激发了玛丽苏的创作欲,因此,事实上,两者是相互创造的关系,玛丽苏创造格林的目的,首先是为了成为她作品的男主角,让她能够代入女主角的位置欣赏这个故事,这样说来似乎格林除了男主角的身份和其他角色也没什么本质的不同。但格林还有一点对玛丽苏有着重大意义,就是他童话作家灵魂集合体的身份,即使自我中心如玛丽苏这种存在,也会有对别人欣赏自己作品的渴望,因此玛丽苏特地设置了一个c结局,用演戏的形式让格林得以了解她的整个创作生涯,至于目的,除了单纯的表现欲和欣赏格林的痛苦以外,恐怕也有一丝希望作为原作者的格林认同自己的心情,哪怕是厌恶,玛丽苏也想得到一些对创作的反馈,而格林是唯一能在创作这个领域和她有一些共鸣的人,作者,读者,男主角,格林三位一体的身份对玛丽苏来说,可以说是难得的知己,尽管这种关系非常扭曲,但不能否认,在这点上玛丽苏作为创作者的心情是有些真心的。而玛丽苏会渴望认同这点,一开始是希望得到母爱,但在得到格林这个玩具之后,玛丽苏就一点也不在意黑山羊的死活了,这也是佐证。 最后不得不提的是,玛丽苏的特殊性质,很大程度上她是寿司这个作者的投影,我个人觉得玛丽苏这个角色有不少表达寿司自己创作观的成分,这也解释了寿司为何这么偏爱她当然,一部好的作品,任何角色都是基于自己的设定和世界观行动,不可能因为是作者的投影就有特别待遇,所以可以说,玛丽苏虽然很大程度上是寿司的投影,但投影的目的其实是对比,玛丽苏的创作肤浅,笔下的故事只是无聊的黑深残,但寿司却喜欢在绝望时写一些希望,在希望中铺设绝望,最后的反转再怎么说都是有因可循,单论创作的层次来说就高出绿虫子太多了,当然,我也不是在吹寿司笔力多高,因为高出玛丽苏这个水平的创作者多如牛毛。 寿司设置玛丽苏这个角色,其实是使用了一种嵌套的结构来讲故事,首层是童话的原作,这些是毋庸置疑的好故事,随后是虫子和奈亚魔改出的箱庭,是烂故事的典型,最后一层寿司想讲的重点其实是格林怎么察觉真相,挣脱出烂故事的循环,书写自己的结局的故事,在这三层中,第一层玛丽苏是读者,格林等人是作者,只出现在设定层面,第二层玛丽苏是一半作者一半角色,格林是一半读者一半角色,体现在abc结局,最后一层中寿司是唯一的作者,玛丽苏和格林就都是角色了,体现在d结局以及之后的二代,这种层层演变虽然有些炫技,但确实非常有意思。 就玛丽苏这个角色而言,整个泛二次元文化里她这样的反派也不常见,究其原因,则是因为一个有能力玩弄主角取乐的boss必然会导致战力失衡,冲突不起来,让读者感到憋屈,因此想要打败这种boss要么机械降神唯心爆发,比如一代c结局(虽然是演的),要么引入新的boss和同伴体系取代她如d结局,也因此,虽然我个人很喜欢一代,但一代的真结局d结局远没有2代h结局震撼 来做个总结吧,玛丽苏无疑是个纯粹邪恶的支配者,一个烂到骨子里的创作者,她作为创作者无疑是失败的,但作为bs这个故事里的角色反而是很成功的,不仅纯粹有特点,还有很多角色侧面可以挖掘,寿司巧妙地利用她读者,创作者和角色的三重身份来塑造她的多面性,颇有荒木在漫画术中写的“在作恶道路上高歌猛进”的成功反派角色风格。

]]>
+ <h1 id="尸龙贾巴沃克">尸龙贾巴沃克</h1> +<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!</span><br></pre></td></tr></table></figure> +<p>象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),<code>尸龙</code>姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对<code>尸龙</code>的整个人物进行解析 - - + - + - - + - +
diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" index 677a8c965..c4cb2b996 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" @@ -259,8 +259,8 @@

black souls
-
@@ -279,8 +279,8 @@

black souls
-
@@ -299,8 +299,8 @@

black souls
-
diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" index 0db24ab55..5c6c894df 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" @@ -399,8 +399,8 @@

游戏杂谈
-
@@ -419,8 +419,8 @@

游戏杂谈
-
@@ -439,8 +439,8 @@

游戏杂谈
-
diff --git a/index.html b/index.html index 7a39cb690..0d745643a 100644 --- a/index.html +++ b/index.html @@ -382,7 +382,7 @@

发表于 - +