从Goal游戏说起

游戏规则

原文地址

https://github.com/eatnumber1/goal/blob/master/README.md

翻译

以下翻译复制于FreeBuf

  1. 规则就是鼓励你打破规则,要的就是你机智!
  2. 程序执行时,该方案要能打印出带足够多的’o’的”goal”来展示程序的功能;
  3. 代码g()()('al')必须出现在源代码中。
    • g()('al')不能是一个字符串文字;
    • 而'al'必须是字符串,或是其他语言中的等价类型,你可以用创建自己的一套语言标准方法(例如C语言必须用",Ruby可以用"或'的任意一种;
    • g()('al')在你语言中必须是有效的右值(如果适用的话)
  4. g()('al')也许不能输出这样一个字符串,如果真的在你的语言中不能输出一个字符串,你应该提交一个原理解释 :为什么它不能一个打印出一个可接受字符串的方案呢!
  5. 你必须能够插入任意数量的()以调用,而不用修改你的方案。如果非要修改原方案那么它就是失败的。
  6. 噢,提醒一下g('al')必须返回”gal”。

PS: 看到这里,如果想自己小试身手可以先不往下看,自己先写一段可以运行的代码,再继续往下

分析

这个规则看起来有点复杂,让先理一理规则,思考一下这个游戏到底要我们做什么。

由于游戏要求用不同的语言实现,支持()调用在不同的语言里可能是不同的东西,例如:C++可能是仿函数,可能是构造函数等。以下都用函数指代可以执行()调用的实体。

  1. 写一个名为g的函数
  2. g函数要有2个重载
    • 有1个参数时,返回 g+参数
    • 没有参数时,返回一个函数,我叫它o函数,o函数也需要2个重载
      • 有1个参数时,返回 g+o+参数
      • 没有参数时,再返回一个类似o的函数,区别是它在带1个参数时,要加2个o
  3. …以此类推

PS: 看到这里,如果还没有自己小试身手的想法,建议就不要浪费时间再往下看了,看了也白看

解决方法

由于最近初学lua,lua的函数是first-class的,所以我的直觉就是lua能非常简单地解决这个问题,所以下面全是lua代码的实现。其他任何函数是first-class或者语言级支持闭包的语言,都能很容易移植或者改写。

第一次尝试

问题有点复杂,让我们把问题分为两个部分

  1. 约束的规则
    • 各种古怪的调用方式
  2. 期望的结果
    • 生成"g"+"o"*n+"al",例如:gal, goal, gooal等

这样看来,第1个部分太难,我们尝试放着第1部分不管,只实现第2部分的要求

结果跟预期的一样,现在只需要修改n的值,就能得到n个o的goal。

第二次尝试

看来进展挺顺利,让我们继续往下,基于第1部分的规则,我们要写一个g函数,支持2种重载,返回不同的值(字符串/o函数),返回的o函数也是类似的,支持2种重载,返回不同的值(字符串/函数)。所以,我考虑o能不能就是g呢?先假设这是可行的,让我们来试试

现在分析一下2种情况的重载

  1. 有1个参数时,返回 'g'+'o'*(调用g的次数-1)+参数
  2. 没有参数时,返回g自己

可以看到,我们用一个闭包,很容易地解决了这个问题,当每次g被无参数调用的时候,o就加上一个'o'。

第三次尝试

上面的代码看起来好像很完美了,但是g()()()()('al')不能重复调用,因为g共享了同一个o变量。但其实这很容易解决。

是的,在最后返回之前,重置一下o就行了。这就是传说中的“递归结束条件”。

第4次尝试

如果上面的代码看起来已经完全符合游戏规则,甚至符合了我们自己增加的条件(因为规则并没有要求,能够重复调用)。既然已经加了个规则,我们最后尝试一下,再加个规则,就是当g没有调用g('al')时,例如:g()(),后面再调用g()()('al'),也应该可以正确输出gooal。

为了符合这个条件,我们只能让g返回另一个函数,然后实现一个真正的闭包。

至此,我觉得已经玩够了,该结束了。不知道有没有把问题描述清楚,我想说的是,再复杂的问题,只要我们理解清楚需求,拆分成小模块去逐一击破。到最后甚至可以发现规则的漏洞,自己去加强规则,玩转规则。

GPP读书笔记之Flyweight模式(二)

原文地址:http://gameprogrammingpatterns.com/flyweight.html

Flyweight模式是什么

Flyweight是一个非常简单的设计模式。它可能也是唯一可以从硬件上获得支持的设计模式。从名字可以看出,这是一个轻量级的设计模式,不仅仅体现在实现上,它也能大大降低内存的消耗,提高执行效率。它常被用在场景的开发中,特别是瓦片场景之类的,包含很多重复出现的子元素。

以瓦片地图(TileMap)举例,简单的说,Flyweight就是把瓦片的属性(成员变量)划分为两类

  • 许多瓦片共有的属性,例如贴图、形状等
  • 各个瓦片独有的属性,例如位置、旋转角度等

将共有的属性提取出来,每一个共有的属性做一个单例,所有的瓦片共享这些共有属性(保存引用或者指针)。这些共有的属性往往是加载缓慢的资源,那么在渲染时,只需要渲染一次,然后在不同的位置多次重绘,就可以大大降低内存消耗,提高执行效率。

以上是我粗浅的理解,原文给出了2个例子,来看原文的例子

简单的例子:森林中的树

作者很会讲故事,他说可以用简单的几句文字就能描述广阔的森林,但是用程序来实现,却不是那么简单的事情。当玩家看到满屏的树,图形程序员看到的是数百万个矩形每1/60秒被GPU渲染一次。

上千棵树,每棵树包含上千个矩形,即使你有足够的内存来保存整个森林的数据,渲染它们需要大量的数据占用从CPU到GPU的总线。

每棵树包含这些元素

  • 多边形网格,来描述树的主干、分支以及树叶
  • 枝干和树叶的纹理贴图
  • 位置和朝向信息
  • 其他一些信息,例如大小、色调,使得每棵树看起来都不太一样

它的代码大概是这个样子

它包含了很多数据,特别是多边形网格和贴图信息。这些数据太大了,以至于无法在一帧里面全部丢到GPU里面去渲染。幸运的是,老前辈们已经帮我们想到了解决的方案。

最关键的问题在于,虽然有几千棵树,但是他们大部分看起来是一样的。他们可是使用相同的多边形网格信息和相同的纹理来渲染。这样一来,所有的树可以共享相同的实例来进行渲染。

先来看看之前的对象结构

第一版森林结构图

我们可以把上面的类一分为二,提取出共有的属性到一个独立的类

游戏中只需要包含一个TreeModel对象的实例,没理由在内存中保存相同的多边形和纹理几千次吧。所有的Tree的实例都可以引用这个TreeModel实例。

现在的对象结构看起来就像这样

第二版森林结构图

虽然这个结构看起来好了很多,我们大大减小了内存的开销。但这么做并没有给渲染带来什么好处,我们需要让GPU理解我们的共享资源,才能提高渲染速度。

数以千计的对象

为了减少GPU渲染的次数,我们需要只把TreeModel发送给GPU一次。然后,分别发送每棵树的其他信息(位置、颜色、大小)。最后,我们告诉GPU,“用那一个TreeModel的数据去渲染每一棵树”。

幸运的是,现在的显卡真的提供了这样的API支持。实现的细节超过了本书的范围,但是Direct3D和OpenGL都支持实例化绘制(Instanced Rendering)

这两个API,都需要程序员提供两组数据,一组是共用的多边形/纹理等信息,用来告诉GPU绘制什么;另一组是位置、大小等的信息列表,用来告诉GPU在哪里以及如何绘制第一组数据。最后,只要调用一次绘制,整片森林就轻松带微笑地出现了。

Flyweight模式小结

现在大家已经看到了一个Flyweight应用的具体例子。这个例子简单到令人发指,也许有人会说,这根本就不是什么设计模式嘛,只是共享一个对象。没错,上面的例子,确实只共享了一个对象,那是因为这个例子足够简单、清晰、易懂。但是实际生产环境,想找到这样的例子,或许有些困难。后面会介绍稍微复杂的例子,还请大家稍安勿躁。

Flyweight解决的问题是,有太多的对象,却只有太少的内存。核心思想是,拆分对象,分解成共有的属性和特有的属性,把共有的属性独立成类的实例,让每个对象去共享这些实例。

复杂的例子:森林扎根的地方(地面)

地面将使用瓦片地图(tile-based)的方式来实现,有很多种类型的瓦片,例如:草地、土地、山、河、湖等等。

每个瓦片包含了以下的属性

  • 移动代价,决定角色从这块瓦片上经过的移动速度
  • 标记瓦片是否是水,决定这里是走人还是走船
  • 渲染使用的纹理

游戏程序员特别在乎执行效率,所以他们认为没有必要把每一个瓦片的所有信息都放到内存里面,一般会用枚举来实现

世界地图的平面将由一个二维数组来组织

实际使用瓦片的时候的代码是这样的

很显然,这样写可以运行的很好,但是却是很恶心的代码。移动代价(MovementCost)、是否是水(isWater),这些都应该属于是瓦片的数据,却被硬编码在了函数里面。应该把这些属性合并成一个瓦片类(Terrain),这不就是类(objects)设计的意义么?

地图上需要成百上千的瓦片(Terrain),但我们并不希望创建这么多的实例。你应该察觉到了,上面的类,没有包含位置信息,这也是唯一的,每个瓦片(Terrain)不同的数据。所以整个瓦片(Terrain)都是上下文无关的,可以当做共有属性来使用。

因此,我们只需要保存每一种类型的瓦片(Terrain)一个实例就可以了。

数组中所有相同类型的Terrain指针,都将指向同一个实例。

Terrain指针示意图

当这么多Terrain的指针指向相同的实例时,如果动态创建Terrain对象的话,它们的生存周期就变得难以管理。简单的处理方法是,把它们放到World类里面

绘制的代码是这样的

为了不让外部直接访问World的Terrain实例,我们还需要提供一个方法

这样一来,World就不需要知道Terrain的细节,如果你需要得到一个Terrain的属性,可以这么做

这么做,我们就可以简单调用对象的API来获得它的属性。从枚举改写为类,几乎没有什么代价,毕竟指针比枚举大不了多少。

性能问题

有些人可能会关心,从枚举到指针的转变,会带来多大的性能损耗。答案是,几乎没有损耗,可能还有性能提升。

想知道详情的话,建议阅读原文。我只想做一个简单的总结,作者有句话说的非常好:优化性能的黄金法则,就是先做性能测试。没有任何测试,光靠自己想象,是很难模拟真实情况的。因为现代硬件上的优化,已经大大超乎普通人类的想象了。要在脑子里还原程序在硬件上运行的情况,几乎是不可能的事情。游戏的性能问题,也很可能不再是某个单一原因引起的。

作者实测的结果是,使用Flyweight修改后的代码,要比之前用枚举写的,跑得更快,但这取决于其他数据在内存中的结构。

在这里也给各位同学提个醒,千万别看到某段代码,就轻易下结论说,“这里肯定有性能问题”或者“这么写性能肯定没问题”,实践才是检验真理的唯一标准。

GPP读书笔记之Command模式(一)

最近在读一本开源的书《Game Programming Patterns》,关于游戏设计模式的,作者叫Bob Nystrom,在EA工作了好多年,整理了他8年来的经验,写成了这本书,最近会出版实体书。作者的文风非常风趣幽默,以至于我一开始读就有点停不下来了,所以打算写一系列读书笔记来表示对作者的敬意。

前面两个章节主要是用来鼓吹这本书有多么多么好(这是作者自己说的),不过还是读到了不少内容,关于程序设计的理解,为什么要做好的设计,代码写出来能运行不就好了吗?这可能是大多数外行人的看法,也许也是码农的看法,但是作为工程师来说,我们要设计结构良好的代码,为的是将来更容易升级和维护。可能开发出一个功能只需要2天时间,但将来可能需要花好几个月来升级和维护这个功能。并且在升级和维护的过程中是非常难去改变原有的设计的,除非全部推倒重写。这对于有多次推倒重写经验的我来说,真是说到心眼里去了。如果你花两天时间写了一坨屎,接下来,你将在粪坑里挣扎几个月。所以,请善待将来的自己,使用良好的设计模式和规范来进行开发。

进入正题之前,再扯点蛋,作者无数次提到GoF,是Gang of Four的缩写,四人帮?当然不是中国的四人帮。他们是联合撰写了《Design Patterns》这本书的人。

Command 模式是什么

GoF 是这么说的

Encapsulate a request as an object, thereby letting users parameterize clients with different requests, queue or log requests, and support undoable operations.

我的翻译:

把一个请求封装成一个实体,进而让用户可以使用不同的参数来构造不同的请求,把这些请求队列化,或者记录到日志里,甚至支持重做。

作者认为这句话毛病太多了,一方面是client存在歧义,另一方面列举了一堆Command模式能做的事情,但是无法涵盖所有的事情,所以读者如果想做的不在里面,就很可能失去兴趣。所以作者自己总结了一句更简练的话:

A command is a reified method call.

我的翻译:

Command是被实体化的函数调用。

Command模式很容易让人联想到

  • 回调
  • 第一类函数
  • 函数指针
  • 闭包
  • partially applied function(因为我不知道这个是什么,就不翻译了)

所以GoF后来还说

Commands are an object-oriented replacement for callbacks.

我的翻译:

Command是回调函数的面向对象实现。

代码时间

我简化了一下原文的例子,四个按钮有点多余,两个按钮就能说明问题啦,让我们想象超级玛丽的玩家操作处理代码(不考虑长按B加速的情况,这里只讨论点击操作)。

这段代码运行在游戏主循环中,已经可以满足一般游戏的需求。

可以配置的控制方式

但是这个时候策划说,让我们支持让玩家自己设置按键吧。作为开发,你一定会抓狂。不怕不怕,这种情况就是Command模式派上用场的时候了。

先定义一个基类

然后是子类

InputHandler也做一些修改

最后刚刚的处理代码变成了这样

角色引导

原文的标题是Directions for Actors,为什么把Directions翻译成引导,以我的理解,本章节的主要内容是,把jump函数从JumpCommand中取出来,Command不直接调用指定的函数,而是调用角色的成员函数,这样做的好处很明显,可以换角色操作了。所以功能引导从Command转换为角色。

在execute函数加入参数

所以JumpCommand就变成了这样

handleInput明显也不满足需求了,让它不再直接执行Command,而是返回Command

因为InputHandler明显不知道现在游戏中选择的是什么角色,所以这个时候把Command先返回出来,以供外部调用,这也是一种延迟调用。 所以,我们得再来看看知道现在游戏中选择的是什么角色的某处代码,是怎么使用InputHandler的

不知道大家有没有发现?这么做了以后,不仅仅是可以换角色了,角色的控制者也可以替换。不仅仅支持玩家通过按键输入来控制角色,还可以利用AI来控制角色。甚至可以使用不同的AI算法来控制不同的角色。还可以用来在某些情况下,使用AI自动控制玩家的角色,比如自动寻路,自动战斗。

下面不得不用一张图来加强理解

把Command放到队列/流中

如果把Command放到队列/流中,就像上图中间的部分,这样就有效地解耦了生产者(AI/玩家输入)和消费者(角色)。

撤销/重做

这是最后一个例子,也是Command模式最知名的应用场景。
如果一个Command对象可以做某件事,那是不是也可以让它撤销呢?撤销操作常用在策略类游戏,工具类应用程序会有更多这类需求,包括自己研发的游戏编辑器,如果你做了一个不能撤销的编辑器给策划用,策划会恨你的。

如果不用Command模式,你想实现撤销操作,会意外地发现那是多么困难的一件事。但是用Command模式来实现的话,就超级简单了。
下面让我们来实现一个回合制的策略类游戏,玩家可以移动自己的单位,也可以撤销移动。

下面是移动操作的代码

细心的你一定发现了这个类跟之前的不同,之前的角色是从execute传进来的,这个MoveUnitCommand是从构造函数传进来的。这是因为我们后续要做撤销操作,所以肯定要知道要对谁做撤销。这个例子也告诉我们,带参数的Command类,该怎么写。
延续之前的功能,MoveUnitCommand被实例化以后,可以在某一个特定时间点被调用,所以handleInput将这么被改写

可是这么做还是不能撤销啊,别着急,下面告诉你怎么撤销,首先要改写Command基类

undo就是execute的反操作,用来撤销execute操作的,那么重做就是重新调用一次execute。
加上undo实现以后的MoveUnitCommand

可以看到代码中多了两个变量xBefore_, yBefore_,来保存MoveUnitCommand执行之前的状态(位置)。所以撤销操作,就是移动回之前的位置。当然,在外部要控制玩家的操作,执行完execute,就只能撤销,撤销完,就只能重做,以免产生不必要的误解。
读到这里,对于多个Command的撤销和重做,应该也已经有一些想法了吧。

多个Command的撤销/重做

这里只给出一张图,不做详细解释了。原文还有一段解释,但我觉得上图已经足够说明一切了。

最后,恭喜你,读完了。

千寻漫画盒无限期暂停

打开博客,发现已经1整年没有更新过了。千寻项目也大半年没有消息了,这段期间的我非常的痛苦和失落,但是时候面对现实,给大家一个交代了。
千寻项目由于种种原因,开发已经暂停,今后是否重启还是未知数。至于原因的细节,不想涉及。只想说这个项目经历了这么长时间,从我个人业余时间的维护,到成立团队,中间经历了许多困难,都一一克服,可惜商业性不够成熟,加上一开始的技术选型问题,导致团队负担越来越重,这是大家都不愿意看到的结果。
长痛不如短痛,对于我个人,对于团队来说,也许这并不是最坏的结果。但对于广大漫迷来说,这应该算是最坏的消息了吧。
之前已经同几位资深用户提及项目暂停的消息。有人表示会收藏这最后一个版本,即使已经不能使用,这让我十分感动,因为千寻漫画盒对他来说已经不仅仅是一个软件,一个工具,更是一份对漫画的热爱。但是我们也要学会向前看,未来的路还很长,目前团队已转型手机游戏开发,希望未来能在盈利模式成熟的游戏市场分一杯羹。漫画盒项目也许在未来的某一天,商业模式思考成熟,团队成熟,资金成熟的时候,有可能被重启,或者以其他形式复活,但现在无法给大家承诺什么,只能先做好手头的工作,希望能得到大家的谅解和祝福。

漫画下载器更名“千寻漫画盒”

发现还有不少人到博客来找漫画下载器的最新版,漫画下载器在这个农历年正式更名:千寻漫画盒。博客将不再更新版本,请到千寻漫画盒官网下载。网址非常好记,是漫画盒的拼音:manhuahe.net,不过千万记得是.net不是.com噢,因为我们使用的是.net技术嘛。
关注千寻漫画盒的同学应该知道,我们在春节前推出了全新界面的2.0版,不过由于稳定性欠佳,目前官网会同时发布2个版本,1.9.2和2.0,想尝鲜的同学可以尝试一下2.0,求稳定的同学可以使用1.9.2 。不过我们没有停下脚步,正在极力优化2.0的稳定性,我们将在近期推出的2.0修正版,大大加强稳定性,加快启动时间,优化内存占用,优化下载策略等等。敬请期待。

漫画下载器 v1.8.2

国庆期间收到了很多用户的反馈,反应最多的就是灰屏的问题,所以国庆回来以后一直在寻找这个问题的根源,现在终于解决了。并且对性能做了一些优化,加快了启动速度。 上截图 image 下面汇总一下修复的BUG

修复的BUG:

  • 修复了下载灰屏问题
  • 修复了可能导致启动速度较慢的问题
  • 修复了某些系统设置下可能无法显示站点包选择器内容的问题

更新方法

  • 不要把文件解压覆盖1.7之前的版本,但可以直接覆盖1.7以后的版本,1.7版本之前的数据不能导入,如果有很多人收藏了很多漫画,丢失了的话,我会想办法做一个旧数据导入的功能的。
  • 当然,如果是第一次下载的话,可以直接使用,不需要之前的版本。

下载地址

漫画下载器 v1.8.1

一波三折的v1.8.1终于问世了,本来是昨天就发布的,结果太多人遇到问题,就紧急撤回了。这次实在是太抱歉了。确实做了N多的测试,没想到还是出问题了。今天可是花了好大的功夫,大家齐心协力,把所有已知的问题都解决了,并且测试了不同的操作系统,不同的环境。
v1.8.1 并没有新的功能,更新都是对各种BUG的修复,相信会是相当稳定的版本。后续我们将要开始全新界面的设计,请期待正规军推出的全新漫画下载器,届时也会改一个更有品牌的名字,征名中。
上截图
image
下面汇总一下修复的BUG

修复的BUG:

  • 修复了代理设置无效的问题
  • 修复了重新下载时未删除历史失败图片的问题
  • 修复了某些可能导致搜索失败的问题
  • 修复了某些情况下站点包参数显示不正确的问题
  • 修复了章节列表在点击下载后会被重置的问题
  • 修复了搜索框输入法默认全角的问题
  • 修复了切换列表后选中状态被重置的问题
  • 修复了漫画信息中下载统计显示不全的问题
  • 修复了输入法冲突导致无法启动的问题
  • 修复了路径设置不正确导致无法下载的问题
  • 修复了其他已知可能导致程序崩溃的问题

更新方法

  • 不要把文件解压覆盖1.7之前的版本,但可以直接覆盖1.7以后的版本,1.7版本之前的数据不能导入,如果有很多人收藏了很多漫画,丢失了的话,我会想办法做一个旧数据导入的功能的。
  • 当然,如果是第一次下载的话,可以直接使用,不需要之前的版本。

下载地址

漫画下载器 v1.8

老传统,先放界面
image
这是组建团队以后发布的第2个版本。
如果说上一个版本是对稳定性的修缮,那这个版本就有了跨时代的意义。
1.8版重点加入了自动更新功能,包括站点包的自动更新和软件的自动更新。
再也不用整天跑官网,看站点包是不是有更新了,直接在站点包管理器里面就可以下载到最新版本的站点包,如果有新的站点包,也能直接看到并且下载噢。
下面看站点包管理的截图
image
软件更新的位置位于设置中
image
点开以后是这样的
image
下面汇总一下更新的功能和修复的BUG

改进的功能:

  • 重新设计的站点包管理界面
  • 增加站点包更新时间和漫画数量的显示
  • 增加站点包在线更新功能
  • 增加软件在线更新功能

修复的BUG:

  • 修复了导入错误的站点包可能卡住界面的BUG
  • 修复了搜索框不支持某些输入法的BUG

更新方法

  • 不要把文件解压覆盖之前的版本,1.7版本之前的数据不能导入,如果有很多人收藏了很多漫画,丢失了的话,我会想办法做一个旧数据导入的功能的。
  • 当然,如果是第一次下载的话,可以直接使用,不需要之前的版本。

下载地址

漫画下载器 v1.7.2

漫画下载器已经组建团队开发,这是组建团队以后发布的第一个版本。
重点还是再提高稳定性和下载速度上,之后会为大家提供一个很不一样的下载器,敬请期待噢。
image

改进的功能:

  • 重写了下载内核,提高了稳定性和下载速度
  • 增加了按章节顺序下载功能
  • 增加下载速度的显示
  • 优化了界面刷新速度
  • 修改了几处界面不合理的细节

修复的BUG:

  • 修复了大量下载偶尔会卡住的问题
  • 修复了多次暂停下载、开始下载可能导致出错的问题
  • 修复了下载完成提示窗口关闭按钮可能被标题挡住的问题
  • 修复了导入站点包进度条可能不显示的问题
  • 修复了漫画封面可能同漫画不一致的问题
  • 修复了几处可能导致程序不稳定的BUG

更新方法

  • 不要把文件解压覆盖之前的版本,1.7版本之前的数据不能导入,如果有很多人收藏了很多漫画,丢失了的话,我会想办法做一个旧数据导入的功能的。
  • 当然,如果是第一次下载的话,可以直接使用,不需要之前的版本。

下载地址

Caught in the Web

《Caught in the Web》是刚上映的一部电影,中文名叫《搜索》。说的是女主角得了绝症以后,做出出格的事情,遭到公众的质疑,进而产生蝴蝶效应的故事。我很喜欢看很真实的,残酷现实的故事,所以很喜欢这部电影。
有很多看点,也很值得思考:
1. 沈流舒(董事长/王学圻)对叶蓝秋(女秘书/高圆圆)的感情。
2. 杨守诚(真相见证人/赵又廷)和叶蓝秋(女秘书/高圆圆)的爱情。
3. 当有钱人老婆,莫小渝(董事长夫人/陈红)不容易。
4. 唐笑华(女二秘/陈燃)的动机。
5. 沈流舒(董事长/王学圻)整垮杨若兮(杨守诚女友/姚晨)。
6. 杨若兮(杨守诚女友/姚晨)压榨杨佳琪(杨守诚表妹/王珞丹)。
一个一个说。
1. 沈流舒(董事长/王学圻)对叶蓝秋(女秘书/高圆圆)的感情。
董事长是很爱叶蓝秋的,那种可远观而不可亵玩的爱。他一直强调她没有陪他出过差,应该是想在她请假之前带她出差,为了100万也好,为了她请假这么久也好,要把她潜规则一下。但是叶蓝秋直接拒绝,他也没有强求,说明还是非常爱她的,或者觉得来日方长。还有叶蓝秋离开以后,董事长让他的手下一直跟踪她的状态,也能看出。加上董事长老婆问董事长,他们到底是什么关系的时候,他根本不想否认他们没什么。因为其实他想要点什么,但是还没开始发生。
2. 杨守诚(真相见证人/赵又廷)和叶蓝秋(女秘书/高圆圆)的爱情。
整部片子看下来,只有杨守诚是了解整个叶蓝秋不让座的真相的。因为叶蓝秋快死了,她的工作、生活长期的压抑,需要释放。挑战社会公共道德,做叛逆的事情,能得到最大的释放。但是没想到被放大那么多,被炒成了社会热点。但其实这些,她都无所谓了,因为生命就快终结了。也正是她这种状态,加上杨守诚知道了整个真相,所以特别同情叶蓝秋,因同情生爱。这个很容易理解,因为叶蓝秋站在了整个社会的对立面,有无穷多的人责难她。而杨守诚为了跟她统一战线,就必须要承受一样的社会对立压力。为了顶住这个压力,他就需要投入更大的精神力去支撑,也就是说外面骂得越凶,他就爱叶蓝秋越深。
反过来说,叶蓝秋是怎么爱上杨守诚的。她父亲过世,母亲改嫁,在这个城市,除了公司同事,没有别的朋友了,所以她是特别孤独的。加上被闹大的不让座事件,她完全跟外界隔绝了。而她唯一可以依赖的人,就是杨守诚。虽然是花钱雇来的,但是杨守诚的真诚感动了她。试想你的世界里只剩下一个可以信赖的人,还是个异性,不爱他爱谁呢?
3. 当有钱人老婆,莫小渝(董事长夫人/陈红)不容易。
当有钱人的老婆真的不容易,还真不是谁都能当得了的。她需要承受巨大的痛苦,巨大的压力。虽然享受荣华富贵,想买什么就买什么,但是精神上极度空虚,没有工作,精神上的唯一支柱就是老公。每天把自己打扮得很漂亮去讨好老公,当老公的棋子去讨好客户。莫小渝说了句话我印象很深,但介于我的记性太差,我只能记个大概,“漠视你,比有小三更可怕”。很多叛逆的孩子,也是这个心情,觉得自己没有受到重视,所以要做一些出格的事情,来引起某人的重视。这是她打电话给电视台说叶蓝秋是小三的原因,也是她后来找杨若兮的原因。其实她还是非常爱他的老公的,非常的重视他,视他为自己的全部。所以她跟杨若兮说的时候,求她放过自己的老公。
4. 唐笑华(女二秘/陈燃)的动机。
这个人非常讨厌,我非常讨厌她。但她真的很厉害,很会耍心机。在网络上提供人肉资料,客户来的时候打开电视,手段非常绝,不给叶蓝秋留任何机会,要把她赶尽杀绝。这样的人在现实中是真实存在的,我们要提防这种人,也要拒绝当这种人。老板应该很清楚她耍的小花样,现在是暂时没人能顶替叶蓝秋的位置,所以给了她,等有更合适的人来了,肯定会把她踢下去的。这样的人是无法信任的。
5. 沈流舒(董事长/王学圻)整垮杨若兮(杨守诚女友/姚晨)。
给回扣,再举报,有钱人的游戏。所以说千万不要得罪有钱有势的人,根本玩不过他。你在媒体,有舆论又怎么样?你真的能控制得了舆论吗?杨若兮的野心太大,本来她炒叶蓝秋的负面新闻也只是误打误撞,抱着想要唤醒公众社会道德的好心。但是发现叶蓝秋是思拓的董事长秘书,然后思拓又是宣称神马人才培养计划的公司。杨若兮想要更大的新闻,所以她把整个思拓公司拖下水。但她完全没有看清楚形势,盲目与大公司为敌,惹来丢工作之祸,已经算是轻的了。
6. 杨若兮(杨守诚女友/姚晨)压榨杨佳琪(杨守诚表妹/王珞丹)。
杨若兮本身也不是什么善类,从压榨她男朋友的表妹杨佳琪就能看出来。公交车上的视频明明是表妹拍的,她要署上自己的名字,还美其名曰如果用表妹的名字根本上不了新闻。这样的压榨在现实中非常常见,教授压榨学生,老板压榨员工,非常常见。所以作为新生代小员工,被这样压榨,不用觉得冤,你刚步入社会,就是要承受这种压榨,等到你上位了,你也可以去压榨别人。这就是我们的社会风气。