|
本帖最后由 CoffeeYin 于 2019-8-1 19:37 编辑
-*- Part 0 -*-
由一场凑巧的游戏场景以及后续测试得到的故事~(。◕∀◕。)
并不是游戏的bug,只是过于极端且涉及源码洗牌机制,故对发生的事件进行记述。( ̄∇ ̄)
该篇讨论分为三个部分:案例情形构成要件+洗牌机制解析+后续细节答疑。
-*- Part 1 情形构成要件 -*-
考虑以下情形:
1. 某同仇boss的出牌阶段,已装备炉子,一直对正邪发动同仇。
2. 大兔子天为余牌2张,已装备神枪,一直响应同仇。
3. 初期手牌不少于boss的正邪,已装备阳伞,一直不还手。
简言之:
任意同仇boss+八卦炉+出牌阶段保持对正邪发动同仇;大兔子2余手牌+神枪+保持相应;初手牌不少于boss的正邪+阳伞+保持不还手。
也即:三个主体,分别拥有以上三个装备(六个客观要件),三个持续循环保持不变的主观选择。
推广之,一般地,场上至少满足以上要件时,可出现以下情况:
因装备八卦炉,不消耗干劲的boss单回合内保持使用同仇;而兔兔由于装备神枪以及手牌数2,可以无限响应同仇,单回合无限制地对boss指定的角色发动弹幕进攻;而一开始受到弹幕攻击时,正邪多摸一张,此时手牌数已然大于boss,但由于化为弹幕战,而又有阳伞防护,今后手牌数只增不减。
此时boss面临的局势是,继续进攻毫无收效,反倒给正邪摸牌。因此boss理当停止同仇,至少停止使用弹幕进攻。然而若boss误认为弹幕战仍在持续,或出于其它方面因素,不断发动不消耗干劲的同仇且天为无限制相应,则将出现正邪无限摸牌、直至摸光牌堆剩余牌的情形。
在游戏信息中显示(当时boss是秦心):
boss装备八卦炉,则LOOP以下 {
>> 【秦心】发动了同仇,目标是【鬼人正邪】。
>> 【因幡帝】响应了同仇,使用了 __ 冈格尼尔
>> 【因幡帝】觉得手上没有牌就输了,于是又摸了2张牌。
>> 【鬼人正邪】摸了1张牌。
>> 【鬼人正邪】对【秦心】:“你敢打我脸,我就敢打回去!”
>> 【鬼人正邪】受到的逆转效果被阳伞挡下了
}
跳出循环的缺口(两种情况):
①牌堆空时,正邪无法继续摸牌。
②牌堆只剩1张时,兔兔换上来的只有一张且不为弹幕,无法继续相应同仇而对正邪弹幕。
-*- Part 2 洗牌机制解析 -*-
观察质子君源码(\...\thbattle\src\thb\cards\base.py)中Deck类getcards方法里的洗牌机制,可得,总有最后十张新进入弃牌堆的没洗。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Deck(GameObject):
def __init__(self, card_definition=None):
from thb.cards import definition
card_definition = card_definition or definition.card_definition
self.cards_record = {}
self.vcards_record = WeakValueDictionary()
self.droppedcards = CardList(None, 'droppedcard')
self.collected_ppoints = CardList(None, 'collected_ppoints')
cards = CardList(None, 'deckcard')
self.cards = cards
cards.extend(
cls(suit, rank, cards, track_id=alloc_id())
for cls, suit, rank in card_definition
)
self.shuffle(cards)
def getcards(self, num):
cl = self.cards
if len(self.cards) <= num:
dcl = self.droppedcards
assert all(not c.is_card(VirtualCard) for c in dcl)
dropped = list(dcl)
dcl.clear()
dcl.extend(dropped[-10:])
tmpcl = CardList(None, 'temp')
l = [c.__class__(c.suit, c.number, cl, c.track_id) for c in dropped[:-10]]
tmpcl.extend(l)
self.shuffle(tmpcl)
cl.extend(tmpcl)
cl = self.cards
rst = []
for i in xrange(min(len(cl), num)):
rst.append(cl)
return rst
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
洗牌的部分在上一个方法def __init__(self, card_definition=None)中,而此处是专门对付一种特殊情况的:
牌堆(deckcards)余牌数 ≤ 请求摸牌数。
系统的处理过程:
①首先,标蓝色意思很明确:所有已经弃置的牌dcl,也即dropped cards left,要确保不可见,即not c.is_card(VirtualCard) for c in dcl,才会被记入dropped,可以推测dropped即后台的弃牌堆,或弃牌堆中不可见的部分。
②其次是红色部分:dcl先清空列表,再加上dropped的最后10张牌(若没有十张牌则是dropped列表中的全部),到下一轮继续记。换言之,不出意外,最后十张弃掉的牌休想在下一轮洗牌后过早地抽上来。
③再次的暗紫色才是洗牌的部分:进入洗牌堆的只有所有弃牌的部分,绝不包含dropped的最后十张,其实是补足红色部分的含义,避免重复。
④其后,第323行绿色部分起令人费解,之前好不容易将cl增加了洗好的tmpcl,但“cl = self.cards”又将其重置为已然较短的原牌数,即len(self.cards) <= num情况下的处理等于没写。可能增强了系统的稳健性,但造成的后果是:
若兔兔需要两张,又牌堆只有一张,则兔兔摸不到两张,只能摸上来一张。
若正邪需要一张,又牌堆空,则正邪技能出现bug,实操情况与描述不符。
备注:本部分内容可能是我理解有误,毕竟功力尚浅哒(求轻打脸ww)!
-*- Part 3 后续细节答疑 -*-
疑1:当正邪/天为无法继续摸牌时,牌堆里还有多少张?新旧弃牌是否存在交集?
答:0张/1张。此时所有牌可能已经对所有角色明置,可能没有(进入弃牌堆的后台,不Visual部分)。
正邪不能再摸,充要条件为牌堆空。
兔兔摸两张时牌堆只剩一张,就只能摸上来一张。
若正常运转,场上的弃牌堆顶上尚未洗、继而尚未进入牌堆的弃牌,一定大于两张。兔兔手中两张刚翻上来的牌堆顶新牌,和弃牌堆顶上4张或6张牌没有交集!兔子新弃两张进入弃牌堆顶时,旧弃两张尚未洗好待摸。故兔子换上来的两张,不是旧弃掉的两张。
疑2:正邪技能、阳伞与弹幕战是否存在bug,which includes卡牌本身的不平衡性or卡牌实际属性与卡牌描述属性之间的微妙差异?
答:①没有任何微妙差异。
弹幕战:出牌阶段,对一名其他角色使用,由目标角色开始,轮流打出一张【弹幕】。首先不打出【弹幕】的一方受到另一方造成的1点伤害。
阳伞:装备后符卡效果造成的伤害对你无效。
实际情况:当装备阳伞者不打出弹幕时,始终是“首先不打出弹幕的一方”,故此时伤害造成,弹幕战结算停止;阳伞取消此伤害。而弹幕战也停止,另一方再无须继续打出弹幕,也不会受到伤害。
②正邪技能。
“逆转:当你受到一名其他角色使用的弹幕效果时,你可以摸一张牌,然后若你的手牌数大于其手牌数,你将此弹幕视为弹幕战。”
阳伞自然是正邪的神装,但严重不平衡情况只存在于较为苛刻的条件下。
首先,看见阳伞正邪,敌方绝不会继续替刷;故此伞无非是对弹幕的屏蔽效果,优势略大于多了件迷彩与盾。
事实上,真正不平衡之处在于:队友用八卦炉替阳伞正邪刷牌的情况(每轮2卡差左右的优势);极端地,炉子同仇、神枪兔兔和阳伞正邪,三者勾结串通刷牌(此时阳伞+正邪的组合将存在预期100卡差的优势);再加以配合,正邪在boss身边或下一位置,刚抽一百张就拿走boss的八卦炉开始全面进攻,此时优势难以计算。
若尊重原设计的正邪技能无问题、无不平衡情况,则当且仅当遭受无限火力+阳伞不还手刷牌时,会出现“技能发动后无法继续抽牌”的情况,即构成所谓严格意义上的bug:实际过程与技能描述不符。
疑3:若同仇boss、兔兔和正邪保持原行动不变,该过程可否因不可抗力提前终止?
答:可以。至少有以下一种情况:
兔兔翻上来的两张中,有恶心丸,且当作神枪打出。此时,丢包记在boss身上,而非兔兔身上!
如果boss因此弃掉炉子,则无法继续无干劲消耗的同仇行为;若boss因此受伤导致吃包自沉,回合也因此结束。
疑4:若以正邪为敌,此时boss的正确解法?
答:早日停止同仇、采用其它干涉形式。
拆除阳伞是提前做的下策,补救方式最好是将正邪封住。
若不尽早停止,存在以下明显隐患,包括且不限于:
浪费兔兔过多的牌;兔兔丢包算在boss头上;正邪摸到包子时如果是秦心要塞正邪也会反遭喂包;一旦正邪摸牌过多,好人卡足够破封,下一轮爆发将造成不堪设想的后果。等等。
另外,既然发现兔兔明知会帮正邪摸牌的情况下还在响应,兔兔的动机乃至真实身份可以想见,boss继续同仇显然是不明智的。
衍生,凡是发现阳伞正邪,再也别弹幕打,先击落其伞再说;凡是发现阳伞正邪,队友对其发动弹幕攻击可有利于其摸牌转运或蓄力爆发。
疑5:或然的不平衡?
答:无限火力条件可能过于易得。
无限火力充要条件是,同仇boss装炉子保持发动,兔兔装神枪保持配合。
四个条件两个选择,一旦满足,近乎无法阻挡。两大旧永动机中,河童辉夜可以有效反制,河童天子可以做消极抵御;两大新永动机,即幽幽子天子与幽幽子响子都无法保证抵挡,因可能会有一刻天子/响子最大牌小于幽幽子的最小牌。
唯一能保证抵挡、从中渔利、甚至会因兔子抽包反制boss的是阳伞正邪,一直不还手,一己之力即可无限抵挡进攻,且摸光全场的牌,除了兔兔在弃牌堆、手牌与新洗牌堆顶三块区域中摸的牌。
-*- Post Script -*-
以上所有评论皆是一时兴起,因为个人做系统和面向对象的功力尚浅,对于质子这一波经历数年考验、且符合设计要求的系统处理方式,难以提出任何有建设性的改正建议,唯会挑刺而已……况且,可能是我理解有误,不敢叨扰质子所以暂且记述于此。羞哭!( ☉д⊙)
接触符斗祭两个月不到,暂时就写到这里啦,欢迎符斗老人们多批评指正哒!(`・ω・ ‘)
由于日常公务繁忙,很多回复不能够及时,还请见谅哦~ (`・ω・´)
|
评分
-
查看全部评分
|