本帖最后由 乾.坤 于 2016-4-28 22:14 编辑

大家好,我是乾坤。今天带来的是一个偏向算法性的作品——分数智能排序算法。也就是解决一堆分数从高到低排序的问题(这里要说一下,计分板上的排序是给玩家能直观看到的,而能被系统读取的顺序则需要输出到另一个计分板,看图


比如现在有9个玩家玩游戏,分数分别如上所示,虽然系统已经帮我们排好了先后顺序,但这个顺序计分板并不能读取,那就需要排序到另一个计分板:


就像这样,分数从高到低从第一名排到第九名(可见,也是可以处理重分的),这样的话我需要对比赛分数并列第4名的玩家执行命令只需要
/execute @e[score_Order_min=4,score_Order=4] ...
即可)
其实排序算法也是很常用的,小游戏制作选出最高分的问题也一直会被问到,而把排序拓展到n位之后,应用的范围就更广泛了。
下页使用方法





进游戏会看到两排按钮,下面6个,上面3个(最左和最右的按钮在侧面),先用按钮选好分(分数自己随意)之后是这样:


由于没有排过名,所以只有选中的分数,排序(左边第一个按钮)之后就会多出一排分数:


这个分数就是你刚刚设定的那个分数的历史排名,因为第一次排序所以当然是1(历史最高)


这时如果你再选个分,就会有两个分数了。


这是上面的三个命令方块。中间是重置整个系统,左边是查看你曾经选定过的分数,右边是所有分数的总排名


下页原理讲解


总共30多个命令方块,一起来看看。
算法计分板:
1.Count (其中的假名Count用于处理同分)
2.Score (储存需要排序的分数)
3.Order (将重新排序后的分数计入这个计分板)

核心命令:
  1. /scoreboard players operation @e[name=Holder,type=ArmorStand] Score > @e[tag=Compare2,c=1] Score
复制代码
有必要强调一下这个命令的用法:
scoreboard players operation <targetName> <targetObjective> <operation> <selector> <objective>
">" 取较大值: 如果selector的分数比 targetName的分数大,则把targetName的分数设为 selector的分数。
------Minecraft Wiki

简而言之 A>B的意思就是:若B>A,则令B=A
我们可以利用这个做出排出一系列分数的第一名,方法就是刷出一个Marker来和所有分数使用一遍“>”运算,这样,全部比对完以后Marker的分数就是探测范围内的最大分数了,然后将Marker的值与所有分数相减,分数为0的那个(些)就是第一名了。你可以这样理解:一次“>”运算是一个点的运动(一组分数的比对),那么将所有点纵向运动起来(将每组分数比对过去)就构成了一条“线”(一次第一名的探测),也就是所谓的“点动成线”

那么,如何“线动成面”呢?
我们可以这样做:将第一次选出的第一名剔除在外,然后在剩余的分数中利用之前的方法选出现在的第一名。那第二次选出的第一名就是第二名了,依次类推,直到每个分数都当过一次第一名之后就意味着每个分数都有自己的“位置”(或者说顺序)了。
当然,“点动成线,线动成面”意味着我们需要有一个两层的控制系统,告诉电脑接下来该怎么排序。
主要的思路就是上面这些,我们看看在游戏中的对应关系。
最开始只执行一次的部分:
  1. icb:/blockdata ~ ~ ~ {auto:0b}
  2. /scoreboard players tag @e[type=ArmorStand,name=Test] add Compare1
  3. /blockdata ~-1 ~ ~ {auto:1b}
复制代码
然后就是一层控制(探测是否所有的分数都进行过排序,tag=Compare1就是还没有排序后分数的分数)

  1. /blockdata ~ ~ ~ {auto:0b}
  2. /blockdata ~-4 ~ ~ {auto:1b}
  3. /testfor @e[type=ArmorStand,tag=Compare1]
  4. cond:/blockdata ~-2 ~ ~ {auto:0b}
  5. cond:/blockdata ~-2 ~ ~ {auto:1b}
  6. /blockdata ~-24 ~ ~ {auto:1b}
复制代码
如果没有全部都经过排序,就执行下一层,即“第一名”的选择

这些是在二层中只执行一次的:
  1. /blockdata ~ ~ ~ {auto:0b}
  2. /summon ArmorStand ~ ~ ~ {Marker:1b,CustomName:Holder,NoGravity:1b,Invisible:1b}
  3. /scoreboard players tag @e[type=ArmorStand,name=Test,tag=Compare1] add Compare2
  4. /blockdata ~-1 ~ ~ {auto:1b}
复制代码
下面是二层控制(探测此轮“第一名”是否已经探测完成,即Marker是否对每个待选分数进行过“>”运算,tag=Compare2指的是未运算过的分数):

  1. /blockdata ~-4 ~ ~ {auto:1b}
  2. /testfor @e[type=ArmorStand,tag=Compare2]
  3. cond:/blockdata ~-2 ~ ~ {auto:0b}
  4. cond:/blockdata ~-11 ~ ~ {auto:1b}
复制代码
如果2级运算也没有
完成,系统会执行以下命令:
  1. /blockdata ~ ~ ~ {auto:0b}
  2. /scoreboard players operation @e[name=Holder,type=ArmorStand] Score > @e[tag=Compare2,c=1] Score
  3. /scoreboard players tag @e[tag=Compare2,c=1] remove Compare2
  4. /blockdata ~18 ~ ~ {auto:1b}
复制代码
如果完成了,就执行这些(顺序对号入座,当然,理所当然的,加了重分的处理):

  1. /blockdata ~ ~ ~ {auto:0b}
  2. /scoreboard players operation @e[type=ArmorStand,name=Test] Score -= @e[type=ArmorStand,name=Holder] Score
  3. /scoreboard players add Count Count 1
  4. /scoreboard players operation @e[type=ArmorStand,name=Test,score_Score_min=0,score_Score=0] Order = Count Count
  5. /scoreboard players tag @e[type=ArmorStand,name=Test,score_Score_min=0,score_Score=0] remove Compare1
  6. /execute @e[type=ArmorStand,name=Test,score_Score_min=0,score_Score=0] ~ ~ ~ /scoreboard players add Count Count 1
  7. /scoreboard players remove Count Count 1
  8. /scoreboard players operation @e[type=ArmorStand,name=Test] Score += @e[type=ArmorStand,name=Holder] Score
  9. /kill @e[type=ArmorStand,name=Holder]
  10. /blockdata ~24 ~ ~ {auto:1b}
复制代码
现在,让我们回到一级控制处,如果第一层探测不到未排序的分数,那么就算大工告成,每个分数都有自己对应的顺序了,收尾即可:

  1. /blockdata ~ ~ ~ {auto:0b}
  2. /scoreboard players reset Count Count
  3. say ok
复制代码

至此,分数排序全部完成。

下页闲聊+存档


看到BBS是没有特别系统的排序算法(可能是用得少吧),就特地写了一个稍微集成点的,希望能帮助到想要提高水平的命令新人2333,排序其实在做系统的时候也是会用到的,当然,方法仅供参考,仅是抛砖引玉罢了,大触们见笑了。
特别感谢 @玄素 给我提供了脑洞

存档下载(本人制作采用的是1.9.3pre2)
[TML-乾坤]分数智能排序算法




来自群组:The Minecraft Lover