前言

“算命”,是一种迷信,我父亲那一辈却执迷不悟,有时深陷其中,有时为求一“上上签”,甚至不惜重金,向“天神”保佑。我曾看到过有些算命网站,可以根据人的生辰八字,来求得这个人一生的财运、桃花运,如果第一卦算得不好,还可以向“天神”“请愿”(充钱),再算一卦,直到达到好运为止。

作为一个深信唯物辩证法的人来说,这些东西当然是不信。

但仔细琢磨,发现这些东西其中需要有些科学道理。我可以将算命总结为以下“三要素”:

  1. 一致性

    “命中注定”,因此“算”出来的东西,不管早算还是晚算,什么时候算,结果应该都一样。

  2. 无规律性

    “天机不可泄露”,因此输入相近的姓名等参数,输出应该相差较远。“每个人的命运各不相同”,比如狗二和狗三,相差只有一个字,但他们的命运并不一定会几乎一样。算法应该也考虑这一点。

  3. 个性化

    输入参数应该尽量个性化,不要像十二生肖/十二星座那样,和性别做排列组合,只有12x2=24种结果。否则撞车的人太多,容易露馅?。因此输入参数必须个性化,最好是姓名、性别再加上生辰八字(出生时间)。

  4. 可操作性

    孜孜不倦的求卦者,可能会“诚心诚意”想求个“上上签”,因此在一致性的基础上,必须要加一点点“可操作性”。这个可以当作一个单独的输入参数来表示。

如果将算命当作一个函数,那它的输入无疑是姓名、其它个人信息和诚心,输出就是一个分数(0-100),可以用下图的代码表示:

int destinyScore = f(name, otherPersonalInformation, faith);

下面,我将用.NET实现这个功能。

最简单的“算命”程序

最初想法

如果只以姓名作为输入,那么这个函数可以简化为:

int destinyScore = f(name);

这可能就好办多了,如.NET中的.GetHashCode(),即可快速获取一个字符串的哈希值,这个哈希值应该是固定的(吗?),该值的取值范围是int.MinValue-int.MaxValue。因此最简单的办法,可以先可以通过对100求模,此时的取值范围是-99~99;然后再取绝对值+1即可,代码如下:

int GetForturn(string name)
{   return Math.Abs(name.GetHashCode() % 100) + 1;
}

在.NET Framework 4.8中运行,可以算出我(周杰)的得分固定为15分。

最简单算法的缺点-.NET Core的不一致

在.NET Core中,这个算法每次重新运行,算出的结果都不同,因为.NET Core为了确保安全性,在应用程序启动时,会随机生成一个字符串哈希值种子,因此每次exe运行,哈希值都会变,文档是这么说的:

哈希代码本身不一定是稳定的。 对于单个版本的 .NET, 相同字符串的哈希代码可能跨 .net 实现、跨 .NET 版本和跨 .NET 平台 (如32位和64位) 不同。 在某些情况下, 它们甚至不同于应用程序域。 这意味着, 同一程序的两次后续运行可能返回不同的哈希代码。(源自:https://docs.microsoft.com/zh-cn/dotnet/api/system.string.gethashcode?view=netframework-4.8 )

很显然,这不符合“一致性”,看来想简单地通过GetHashCode()快速“算命”的想法落空了,只能使用标准的哈希算法。

当然,使用如此简单的算法,客户知道了,可能也不太情愿消费更多的“诚意金”了。

哈希算法

哈希算法可以给任意长度的字符转换为一串二进制数组,也就是哈希值。.NET内置了许多不同的哈希算法可供选择:

1. 有单纯的哈希,如MD5、SHA1之类;

2. 有“加盐”的哈希,如HMACSHA、HMACSHA256等;

3. 有可指定生成长度、可多次迭代、综合性“加盐”的哈希,如Rfc2898DeriveBytes。

我们要指定一点点“天机”(加盐),但“天机不可泄露”,因此简单地MD5等单纯哈希算法排除;

我们要转化为一个整数,最大的整数类型,long/Int64,为64位,而最小的内置哈希算法,MD5,就已达128位。因此也要排除HMACSHA等“加盐”哈希。当然这些哈希值也可以手动截取部分长度,但安全性是个问号(也受强迫症影响)。

搞过ASP.NET Identity登录的都知道里面用到了Rfc2898DeriveBytes,它默认为ASP.NET Core做了10000次迭代,用多次迭代的方式(而不是引入一个新哈希算法的方式),确保了安全性。搞对称加密的时候,有时也用这个类将客户的密码转换为加密算法的密钥(key),非常有用。

所以最终我们选择了Rfc2898DeriveBytes,该算法可以生成任意指定长度的哈希值。这个类的构造函数要求输入一个盐值和迭代次数,在这个示例中我们取一个别人不知道的值(代码中写死了,你们假装不知道,你们想用这个代码时可以改改?)。可以写出如下代码:

int GetForturn(string name)
{   using (var h = new Rfc2898DeriveBytes(name,    salt: new byte[8] { 44, 2, 3, 4, 5, 6, 7, 8},   iterations: 10086)) {   return (int)(BitConverter.ToUInt64(h.GetBytes(8), 0) % 100) + 1;   };
}

我从网上自动生成了888个姓名,然后调用该函数,发现得分超过90分“上上签”标准的,只有83个,相同于十分之一,符合分布特点(详情见Github上的代码)。可见算出一卦80分以上的“上签”,已经非常不容易了。

通过以下代码,可以算出“狗二”是48分,“狗三”是96分,可见一字之差相差甚远:

GetForturn("狗二").Dump(); // 48
GetForturn("狗三").Dump(); // 96

完整算法

最后,依葫芦画瓢,加上个人信息参数(生日)和“诚意金次数”,完成最后的算法:

int GetForturn(string name, DateTime birthDay, int faithCount)
{   using (var h = new Rfc2898DeriveBytes(name + birthDay + faithCount,  salt: new byte[8] { 44, 2, 3, 4, 5, 6, 7, 8 },  iterations: 10086)) {   return (int)(BitConverter.ToUInt64(h.GetBytes(8), 0) % 100) + 1;   };
}

然后又是“狗二”和“狗三”,加上他们的生日参数后,默认他们的得分是95分和3分:

GetForturn("狗二", new DateTime(1994, 5, 17), 0).Dump(); // 95
GetForturn("狗三", new DateTime(1996, 11, 3), 0).Dump(); // 3

但狗三经过1次“诚意金”后,也求得了高达99分以上的“上上签”:

GetForturn("狗二", new DateTime(1994, 5, 17), 0).Dump(); // 98
GetForturn("狗三", new DateTime(1996, 11, 3), ).Dump(); // 99

最后的话

Rfc2898DeriveBytes非常有用,本文说了Rfc2898DeriveBytes的一种使用场景,相信各位在工作当时也经常会有机会去接触它。

我将上述功能做了一个页面,愿博君一笑:https://destiny.starworks.cc/

出处:微信公众号【DotNet骚操作微信可能无法留言,可点击“阅读原文”转到博客园留言。原文链接:https://www.cnblogs.com/sdflysha/p/20190905-fortune-with-dotnet.html

觉得好看,请点这里↓↓↓

用.NET写“算命”程序相关推荐

  1. 用python语言写了一套在线算命程序 ,精准度怎么样?可以来试试

    用python语言写了一套在线付费算命程序,分网页版和小程序版 包括八字精批 合婚 八字解名 婚姻 终身运势五大项.算法精准,回头客较多.有相关网站流量资源的可以坐等收益.python anli网zh ...

  2. 在线算命程序 源码 用python语言写的 算命的网络化发展趋势 你怎么理解的?

    欢迎使用Markdown编辑器写博客 用python语言写了一套在线付费算命程序,分网页版和小程序版 包括八字精批 合婚 八字解名 婚姻 终身运势五大项.另外有完善的分销系统,有相关流量资源的适合做. ...

  3. 新版付费测算源码 星座运势 塔罗牌 牛年运程 宝宝起名 月老姻缘 起名算命程序第三版支持易支付

    新版付费测算源码 星座运势 塔罗牌 牛年运程 宝宝起名 月老姻缘 起名算命程序第三版支持对接易支付,这是一款很不错的测算源码小白已经测试过了是能正常运营的,首页有三套模板原版的有点BUG我已经修复好了 ...

  4. 算命程序的网络化发展 实现占卜程序网络化 在线算命程序python编写 根据周易五行算法编写

    用python语言编写开发出一套在线算命程序,属于占卜程序类,根据周易五行,实现出一套算法,这一套算命程序分为网页版和微信小程序版两种,每个版本包括5大版块,分别是八字精批.八字合婚.婚姻测算.起名解 ...

  5. 算命程序源码 实现一对多的网络算命发展趋势 python编写的,测算的精准度 页面的布局 欢迎业内人士指导改进

    欢迎使用Markdown编辑器写博客 在线算命程序源码,python语言编写.有网页版本和小程序版本,包括八字精批 婚姻 八字解名 合婚 终身运势 .可以实现在线付款后 自动跳转测算页面.程序运行稳定 ...

  6. 自己写的程序密码功能 ------数字功能

    自己写的程序密码功能  ------数字功能 class LockedViewController: UIViewController { var dataBase:FMDatabase? var i ...

  7. 【python编程导论】我想和你探讨下如何去写好程序

    1. 题目来源 麻省理工的编程导论: Introduction to Computer Science and Programming Using Python 第一周课程的第三个编程题 Week 1 ...

  8. ACMNO.30 C语言-宏交换 定义一个带参的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参。输出已交换后的两个值。

    题目描述 定义一个带参的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参.输出已交换后的两个值. 输入 两个数,空格隔开 输出 交换后的两个数,空格隔开 样例输入 1 2 样例输出 2 ...

  9. /* * 编程题第五题(20分): 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印 ***** *** * *** ***** 所谓“

    题目: 编程题第五题(20分): 本题要求你写个程序把给定的符号打印成沙漏的形状.例如给定17个"*",要求按下列格式打印 *****************    所谓" ...

最新文章

  1. 全凭“脚感”,这个不看路的机器人就能稳稳爬楼梯,一脚踩空也不怕 | RSS 2021...
  2. CSS公共清除浏览器默认样式
  3. Python为什么这么厉害? 不想成为专业码农? 来学习Python吧!
  4. 二分法求方程的根_快速求解方程的根——二分法与牛顿迭代法
  5. matlab ode45 二阶微分,matlab关于ode45解二阶微分方程的困惑
  6. ORA-01841: (完整) 年份值必须介于 -4713 和 +9999 之间, 且不为 0情况解决
  7. mysql服务器失败1396_MYSQL ERROR 1396 (HY000) 错误的解决办法
  8. spring boot: 组合注解与元注解
  9. 《Web应用基础》课程结业报告
  10. 成功解决TypeError: Encoders require their input to be uniformly strings or numbers.
  11. Hybrid接口、MSTP协议
  12. 网络安全——攻防对抗
  13. No enclosing instance of type FormDetailBean is accessible. Must qualify the allocation with an encl
  14. 十只老鼠在1000瓶药水中找一瓶有毒的
  15. 戴尔服务器显示屏报警PDR1101 fault detected on drive 3. Check drive
  16. 教你修改网卡物理地址(MAC)
  17. Flutter之Toast
  18. 5.0 DataView使用说明
  19. 字符集、标识符、常量与变量
  20. 大型会议的礼仪(2)

热门文章

  1. β射线与哪些物质可产生较高的韧致辐射_辐射无所不在,香蕉土豆里都有?我们还能愉快生活吗?...
  2. opencv---颜色空间转化并实现物体跟踪
  3. 为何Windows版QuickTime突然寿终正寝?
  4. iOS开发之手势识别
  5. 你一写长文章就焦虑拖延?
  6. 系统集成相关岗位理解
  7. 一个不成功人士的“成功之道”
  8. 无符号数、有符号数、补码在汇编中的运用及相关注意事项
  9. 500w 的引用类型和值类型到底有多大差异?
  10. .NET Core剪裁器升级瘦身引擎,并支持剪裁计划的录制和回放