B LOG

  • Home

  • About

  • Categories

  • Archives

2018年通关游戏简评

Posted on 2019-03-28 | In 电子游戏 | Views:

去年在游戏时光App中的一些评论搬运到自己的博客中来,以后同步更新。我在游戏时光的ID是Confutatis

铲子骑士

  • 平台:Nintendo Switch
  • 通关时长:35h
  • 评分:8/10

致敬FC时代的横版过关游戏集大成之作。画面音乐动作都是复古的风格,难度适中,三个角色的玩法各异,可玩性很强。缺点是从FC时代过来的硬核横版游戏玩家可能会觉得缺乏挑战。但是这也不是那个一款游戏要把人虐得死去活来的年代了。

超级马力欧:奥德赛

  • 平台:Nintendo Switch
  • 通关时长:70h
  • 评分:10/10

随处可见的惊喜,童年捉迷藏的乐趣,我能一直玩下去

塞尔达传说:旷野之息

  • 平台:Nintendo Switch
  • 通关时长:100h
  • 评分:10/10

画风优秀,把人物与环境的互动做到了极致。显而易见的塔和藏在各处的神庙和呀哈哈充满了探索的乐趣,开放世界游戏的教科书。盾反和林克时间以及武器耐久度系统使得战斗有趣又刺激。

美中不足的是没有什么令人印象深刻的支线任务。加农的BOSS战比起四神兽差得有点多,甚至不如人马难度大,有种虎头蛇尾的感觉。

但这依然是梦想中的游戏,是会让这么多年经历过各种游戏类型进化到现在的玩家感动的游戏。有幸能在这个时代玩到塞尔达传说旷野之息

Read more »

Java常用容器类盘点

Posted on 2017-04-10 | Edited on 2018-05-16 | In 编程语言 | Views:

ArrayList

底层实现

ArrayList的底层实现为Object[]数组。Add和Remove操作多使用System.arrayCopy()方法。随机访问效率高,插入和删除效率差。

线程安全性

非线程安全

扩容机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* The minimum amount by which the capacity of an ArrayList will increase.
* This tuning parameter controls a time-space tradeoff. This value (12)
* gives empirically good results and is arguably consistent with the
* RI's specified default initial capacity of 10: instead of 10, we start
* with 0 (sans allocation) and jump to 12.
*/
private static final int MIN_CAPACITY_INCREMENT = 12;

/**
* This method controls the growth of ArrayList capacities. It represents
* a time-space tradeoff: we don't want to grow lists too frequently
* (which wastes time and fragments storage), but we don't want to waste
* too much space in unused excess capacity.
*
* NOTE: This method is inlined into {@link #add(Object)} for performance.
* If you change the method, change it there too!
*/
private static int newCapacity(int currentCapacity) {
int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
return currentCapacity + increment;
}
Read more »

Activity各种情形的生命周期

Posted on 2017-03-31 | Edited on 2018-05-16 | In Android开发 | Views:

Android组件中,Activity的生命周期是最复杂的。首先看一下完整的Activity生命周期图。

这张图粗略地表示了一个Activity从启动到销毁完整的生命周期。但是这篇文章想要探究Activity生命周期的更多细节。接下来的内容要看看Activity在一些特殊的场景下会有怎样的表现,生命周期中各个回调的执行顺序。这些会通过一个Demo的Log来展现。Demo的源码可以在这里找到。

Read more »

使用NotificationListenerService监控通知栏

Posted on 2017-03-28 | Edited on 2018-05-16 | In Android开发 | Views:

介绍

NotificationListenerService是Android API Level18新增加的一个服务,当系统通知栏有通知弹出,移除以及位置改变时,会调用这个服务相关的回调方法。因此,我们可以利用这个服务来监控系统通知栏的行为。

如何在App中注册NotificationListenerService,方法很简单,首先在AndroidManifest.xml中添加一个这样的服务:

1
2
3
4
5
6
7
<service android:name=".NotificationListener"
android:label="@string/service_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>

注意的是服务需要申请BIND_NOTIFICATION_LISTENER_SERVICE权限也就是所谓的通知读取权限,并且在intent-filter中加上SERVICE_INTERFACE这个Action。然后创建一个名为@stirng/service_name的服务继承NotificationListenerService。这样在App启动后并且通知读取权限已开启的情况下,我们的NotificationListenerService就可以监控通知栏事件了。

还有一个注意的地方在文档里面也说得很清楚了,除了requestRebind(ComponentName)以外,不应该在onListenerConnected()方法回调之前做任何操作。

Read more »

Raft一致性算法

Posted on 2017-03-19 | Edited on 2018-05-16 | In 分布式系统 | Views:

简介

Raft是分布式一致性算法的一种。通过Leader与Follower之间的日志同步和状态机来实现分布式系统的一致性。它的作用与另外一个著名的算法Paxos类似,但是Paxos过于难以理解,导致使用Paxos的系统难以保证正确性而且出现故障时调试难度也很大。Raft算法将保证一致性的策略分为三个部分,Leader election, Log replication以及Safety,是更容易理解的一致性算法。想要学习Raft算法,这篇论文是很棒的资料 In Search of an Understandable Consensus Algorithm。本文根据这篇论文总结了一下最基本的Raft算法。

基本概念

一个Raft节点的大致结构如图:

Read more »

Go语言Channel的一些Tips

Posted on 2017-03-08 | Edited on 2018-05-16 | In 编程语言 | Views:

基础知识

Golang中的Channel是一个类似于管道的类型,我们可以通过Channel来在不同的Goroutine之间传递数据。

创建Channel:ch := make(chan int) 或 ch := make(chan int, 10)

前者是不带缓冲区的Channel,后者是带缓冲区的Channel。区别在于不带缓冲区的Channel在Send操作后会一直阻塞直到数据被Receive,而带缓冲区的Channel在缓冲区被填满之前都不会阻塞

Send操作:ch <- 1
Receive操作:i := <-ch
关闭操作:close(ch)

Tip1:关闭后Channel的行为

在Channel被执行关闭操作后,继续执行Send操作会导致panic: send on closed channel,而继续执行Receive操作还可以读到Channel中的数据,所有数据读取完后会不断地读到该类型默认初始化的值(如果类型为int则读到0,类型为bool则读到false)。

Tip2:控制退出

该Channel所在的Goroutine在另一个Goroutine执行quit <- true时退出。

1
2
3
4
5
6
7
8
for {
select {
case x := <-ch:
doSomething()
case <-quit:
quit()
}
}

Tip3:控制超时

该Channel所在的Goroutine在等待时间t后ch仍然未接收到数据时退出。

1
2
3
4
5
6
7
8
for {
select {
case x := <-ch:
doSomething()
case <-time.After(t):
timeout()
}
}

Tip4:清空缓冲区

假如ch中已经有数据了,可以使用下面的代码来清空缓冲区。如果ch中没有数据则直接执行后面的代码。

1
2
3
4
select {
case <-ch:
default:
}

Tip5:定时器

下面的代码会阻塞当前Goroutine一秒。

1
2
t := time.NewTimer(time.Second)
<-t.C

还可以使用t.Stop()操作来停止这个定时器。

呐喊众生相

Posted on 2016-11-26 | Edited on 2018-05-16 | In 读书 | Views:

“在我自己,本以为现在是已经并非一个切迫而不能已于言的人了,但或者也还未能忘怀于当日自己的寂寞的悲哀罢,所以有时候仍不免呐喊几声,聊以慰藉那在寂寞里奔驰的猛士,使他不惮于前驱。” ——鲁迅

《狂人日记》
狂人:这个世界所有人实际上都在互相吃人于被吃,却都在伪装自己真正的目的。而作为狂人看清这一切想逃脱却只能被全世界当成“迫害狂”。难见真的人,或许只有孩子还未真正吃过人吧。不想被当成异类就不能轻易地说出“异端邪说”,人们从服从渐渐变得麻木。

《孔乙己》
孔乙己:如今在看孔乙己,于我们大多数人何其相似。文化人自命清高,做不到行业的顶尖(秀才)又不愿委身做一些自己不齿的事情(营生),在这个世界上苟且地活者(偷盗),想靠着自己微薄的能力一点点的向上走。不但被上流社会的人所不屑,还经常遭到比自己差的人的嘲笑。他不愿与这些人同流合污,说君子固穷,但是又没有能力往更高的地方去,于是只能每天忍受着来自这个世界满满的恶意,他想要做出一点改变让世界更美好,教人识字,却又于事无补。最后只能平庸地结束这一生。

《一件小事》
“我”:忽然发现在那个年代人就已经“碰瓷”的警觉了。可是那个年代人与人之间还有信任,看着车夫搀扶着那女人去了巡警分驻所,“我”的内心被震撼了,我也被震撼了。“我还能裁判车夫么?”,我们不能裁判任何人,每个人的心中都存在着恶的一面,圣人是不存在的。

《头发的故事》
N先生:辫子大概就是现在人所说的政治正确吧,一个人只要做了政治不正确的事情,就算他有着自己的执念,也会被这个社会所排挤。你纹身,染发你就是坏孩子,大家都有辫子你没有,你就是坏孩子。那些所谓的坏孩子也在盼望一个“双十节”的到来吧,它可以是电子竞技规范化,同性恋合法化等等。

《故乡》
闰土:这是我们每个人都有的故事,从童年的天真无邪,与人相处真心对待,无视地位,阶级,财富,到长大后的懂得人情世故,经过这个社会一遍又一遍地筛选后认清了自己的地位,对自己地位高的人毕恭毕敬,对地位不如自己的人不屑一顾。唯有见到自己儿时的伙伴,同学,才会重新看到自己压抑伪装了很久的真心。长大后的我们都喜欢像水生宏儿这样的孩子,但我们也知道,他们迟早也会成为闰土。

《阿Q正传》
阿Q:精神胜利法大概是阿Q正传得以出名的原因吧。打游戏输了,我们摔锅给队友。看到别人的成功,我们总以为其中有不正当的勾当。看到别人失败,我们心中有时会偷偷窃喜,还想着如果换了我一定能成功。我们有时都会用这种扭曲的暗示来安慰自己脆弱的内心。经常幻想着自己是赵家人,自己能加入革命党,可是现实总是那么残酷。说到底还是自身的弱小滋生了阴暗的内心。

《端午节》
方玄绰:这是一个虚伪而又爱面子并且胆小怕事的形象,他的口头禅“差不多”一是为了伪装自己假装不屑,二是为了避免发表自己的观点怕露怯丢了面子,三是真正遇到事情时逃避的借口。政府不发工资他不愿自己去要觉得失了身份而且怕受委屈,这或许就是我们通常所说的“玻璃心”吧。这是一个真正的“差不多先生”。

再见,小丸子

Posted on 2016-11-11 | Edited on 2018-05-16 | In 生活 | Views:

macOS Sierra系统Gradle构建速度异常慢的解决方案

Posted on 2016-10-25 | Edited on 2018-05-16 | In Android开发 | Views:

上周刚刚升级了macOS Sierra系统,升级后在使用gradle构建项目时发现在Resolving dependencies这一步变得奇慢无比,本来3分钟能够构建完成的项目用了30多分钟才构建完,这给我带来的不小的困扰。在Google了很多资料后,终于解决了这个问题。

解决方案

首先打开host文件

sudo vim /etc/hosts

把host文件中有localhost的行后面加上yourmacname.local即可。

127.0.0.1   localhost yourmacname.local
::1         localhost yourmacname.local

yourmacname是你计算机的名字,在System Preferences - Sharing中能够找到

根本原因

出现问题的根本原因在于java.net.InetAddress.getLocalHost()这个函数耗时严重,在新版macOS上会耗时5000ms左右,而在其它机器上耗时仅为8ms。因此,gradle在构建时大量调用这个方法就会导致构建异常缓慢。根据这个实验我们知道了解决这个问题的办法就是在localhost后面加上yourmacname.local,这是更新到macOS Sierra的一个坑。

最后,总结一下最近更新macOS Sierra遇到的其它坑,希望以后找到解决方案。

  1. Mou失效了
  2. QQ截图不能直接使用
  3. 使用预览看PDF的时候三指取词功能失效

MapReduce

Posted on 2016-10-23 | Edited on 2018-05-16 | In 分布式系统 | Views:

学习MapReduce最好的资料莫过于Jeffrey Dean和Sanjay Ghemawat的论文MapReduce: Simplified Data Processing on Large Clusters。里面详细地讲述了MapReduce的来龙去脉,实现,执行过程以及在实际中的运用等等。

MapReduce是一种运行于分布式系统上的计算模型,它的思想跟分治的思想很类似,将一个大的问题划分成若干小问题,再将那些小问题并行处理最后将结果汇总得到最终的结果。MapReduce顾名思义由Map和Reduce组成,Map操作将一个大的问题划分成若干份,并以键值对的形式存储,Reduce操作以之前的键通过Hash等手段分配到若干个Reduce worker上进行计算,最终汇总得到结果。

MapReduce的算法逻辑论文中的一张图十分清晰地表现了

有几点需要注意的事所有Map节点和Reduce节点都是普通的Worker节点,而需要分配多少Woker节点,每个Worker是执行Map操作还是Reduce操作都是由一个单独的Master节点决定的。在执行完Map或Reduce后,执行的结果都会存储到本地磁盘进行持久化,这也是为了容灾处理,可以在节点失效后正确地恢复。

这里的讨论可以帮助我们更好地理解MapReduce的细节。

12

唐盛

程序员,Popper,游戏玩家,足球爱好者

16 posts
8 categories
14 tags
RSS
GitHub E-Mail 知乎 Instagram
© 2015 — 2019 唐盛
Powered by Hexo v3.7.1
|
Theme — NexT.Gemini v6.2.0