Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >dotnet 世界猜测 随机数的小测试

dotnet 世界猜测 随机数的小测试

作者头像
林德熙
发布于 2023-04-07 00:32:17
发布于 2023-04-07 00:32:17
38000
代码可运行
举报
文章被收录于专栏:林德熙的博客林德熙的博客
运行总次数:0
代码可运行

这是一个半技术向的博客,主题来源于我读过的某本书的片段,这是一个稍稍有些前置知识的故事,主题的大概内容就是假定世界存在某个规则序列,通过一代代的探索,可以获取到此序列的内容。本文将模拟此情形,写一个随机数的小测试应用,来不严谨的证明,或者准确来说是用代码讲述这个故事

天有五贼,见之者昌。 传说,在一个由某逗写的代码世界里面,世界里藏着一段取值范围为 0 到 100 且长度为 10 的序列。某逗将此序列称为世界序列。在此世界里面,还生活着一群名为 Element 的小人儿。这些 Element 小人儿,都在探索和追求着世界序列。因为呀,每当此世界经过一代的时候,嗯,约等于某个大循环执行一遍的时候,将会根据此世界序列的内容,再加上某逗规定的算法,决定哪些 Element 小人儿需要被淘汰掉。已知的是,如果 Element 小人儿越了解准确世界序列,那 Element 小人儿就越能生存下来

此世界每经过一代,将会淘汰一批 Element 小人儿。而存活下来的 Element 小人儿将会迎来新的一轮生娃过程。可以由存活下来的 Element 小人儿创建出更多的下一代的 Element 小人儿

在经过此世界的很多代之后,咱来看看存活下来的 Element 小人儿是否都掌握了正确的世界序列

接下来就是写代码的内容了,命题确定了,其实通过简单的大学数学的知识,是能够计算出结果的,只不过咱是计算机系的,肯定要写点代码啦

按照本文的题注,天有五贼,见之者昌,先用代码写天有五贼。我的文学修养还不够,不能达意的解释天有五贼,见之者昌这句话。只能用代码的方式,以一个片面的方式来解释。在某逗写的代码世界里面,此世界的世界序列就是对应着天有五贼的意思。这片天地有五贼,五贼大概就是金木水火土五行的意思,也等于说世界的规则或者说世界的本源。本文的世界序列,就大概属于某逗写的代码世界里面的本源。而见之者昌可以认为是,如果有人可以知晓五贼,约等于说如果有人可以知道世界的规则或者说世界的本源,那他将会昌盛。对应某逗写的代码世界里面的 Element 小人儿,如果 Element 小人儿能够知晓世界序列,那他更能在此代码世界的一代代循环里面存活,而且 Element 小人儿也就能生产更多的下一代的 Element 小人儿,不断昌盛

某逗写的代码世界里的世界序列,序列里面的每个项,都可以用一个 Key 的只读结构体来表示。之所以不直接使用 int 等来表示,那是为了给一个单位,这属于程序员的修养。如以下代码定义了 Key 这个只读结构体,本文代码基于 dotnet 7 版本编写,本文代码都在 GitHub 上开源

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
readonly record struct Key(int N)
{
    public const int MaxKeyValue = 100;
}

世界序列也就是一个 List<Key> 类型。当然,有了代码世界,为了代码世界能够好好工作,还需要一个世界管理者,也就是以下代码定义的 Manager 类型,在 Manager 里面就存放了世界序列,代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public List<Key> KeyList { get; }
    ... // 忽略其他代码
}

生活在代码世界里面的是一群 Element 小人儿,使用的是 Element 类型,每个 Element 小人儿都有自己的一段序列。这就是 Element 小人儿最重要的,也是不断探索的内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public List<Key> KeyList { get; } = new List<Key>();
    ... // 忽略其他代码
}

在代码世界刚开始的时候,也就是 Manager 被创建出来的时候,将会立刻初始化世界序列

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public Manager()
    {
        KeyList = new List<Key>();
        for (int i = 0; i < 10; i++)
        {
            var key = Random.Shared.Next(Key.MaxKeyValue);
            KeyList.Add(new Key(key));
        }
    }

世界开始的时候,将会进入 Manager 的 Start 方法,在初始化世界时,将会创建出首批的 Element 小人儿,如以下代码,由于怕电脑被玩坏,这里约束了 Element 小人儿的数量大概只有 10000 个

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        for (int i = 0; i < 10000; i++)
        {
            var element = CreateElement();
            ElementList.Add(element);
        }
    }

    public List<Element> ElementList { get; } = new List<Element>();

    ... // 忽略其他代码
}

以上的 CreateElement 方法是一个用来辅助创建 Element 小人儿对象的方法,在实现他之前,还请先看看 Element 类型的构造函数吧

在 Element 类型里面,不仅包含了 KeyList 属性,还包括了两个辅助代码运行的属性,分别是 Random 随机数属性和 FinishBuildKey 属性,还请让我卖个关子,在本文后续部分再来揭晓 FinishBuildKey 属性的作用。在 Element 类型的构造函数里面,将要求传入 Random 属性,以让 Element 在每一代里面,拥有猜测世界序列的能力,且多个 Element 之间有奇妙的关系

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public Element(Random random)
    {
        Random = random;
    }

    public Random Random { get; }

    private bool FinishBuildKey { get; set; }

    public List<Key> KeyList { get; } = new List<Key>();

    ... // 忽略其他代码
}

在了解到 Element 的构造函数之后,相信大家也能猜到 CreateElement 方法的实现了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private Element CreateElement()
    {
        Element element = new Element(new Random(Random.Shared.Next()));
        return element;
    }

在完成了代码世界的首批 Element 小人儿创建之后,就要进入激烈的世界迭代了。先创建一个大循环,大概是 10000 次。表示这个世界将会开始迭代 10000 次

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        for (int i = 0; i < 10000; i++)
        {
            ... // 忽略其他代码
        }

在每一代的开始时,都会让每个 Element 小人儿进行一轮思考,让 Element 决定是否在自己的 KeyList 里面,加上新的 Key 值。当然,每个 Element 小人儿的思考方式,现在就是通过 Random 随机数生成的哈

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        for (int i = 0; i < 10000; i++)
        {
            foreach (var element in ElementList)
            {
                element.BuildKey();
            }
            ... // 忽略其他代码
        }

以上的 BuildKey 函数就是放在 Element 里的函数,用于让 Element 小人儿思考新的 Key 值是什么,大概的实现如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public bool BuildKey()
    {
        var key = Random.Next(Key.MaxKeyValue);
        KeyList.Add(new Key(key));

        return true;
    }
    ... // 忽略其他代码
}

当然了,有些 Element 小人儿决定放弃思考,也就是 Element 可以不再生成新的 Key 值。这也就是上文卖关子的 FinishBuildKey 属性的作用,此属性用来判断是否此 Element 已不再生成新的 Key 值了,约等于此 Element 认为自己已猜出了世界序列

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public bool BuildKey()
    {
        if (KeyList.Count > 0 && (FinishBuildKey || Random.Shared.Next(10) == 1))
        {
            FinishBuildKey = true;
            return false;
        }

        var key = Random.Next(Key.MaxKeyValue);
        KeyList.Add(new Key(key));

        return true;
    }
    ... // 忽略其他代码
}

等待各个 Element 思考完成之后,此代码世界的考验就要开始了。在此世界的天道规则是从当前的世界序列里面通过当前世界的代数,也就是世界大循环的 i 变量的值,决定出世界序列中的一个 Key 值。对于每个 Element 来说,也要根据当前世界的代数返回一个 Key 值。一旦 Element 的返回的 Key 和此世界的 Key 值不相同,那么此 Element 将会被淘汰

说起来简单,先来看看代码如何实现

先实现从当前的世界序列里面通过当前世界的代数,也就是世界大循环的 i 变量的值,决定出世界序列中的一个 Key 值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        for (int i = 0; i < 10000; i++)
        {
            ... // 忽略其他代码
            var key = GetKey(i);
            ... // 忽略其他代码
        }
    }

    public Key GetKey(int n)
    {
        var index = n % KeyList.Count;
        return KeyList[index];
    }

    ... // 忽略其他代码
}

每个 Element 也实现 GetKey 方法,也是通过传入的序号返回一个 Key 值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public Key GetKey(int n)
    {
        var index = n % KeyList.Count;
        return KeyList[index];
    }
    ... // 忽略其他代码
}

判断 Element 返回的 Key 是否和世界的相同,如果不相同,将会淘汰。代码只需要一句话就可以完成实现,那就是返回 Key 不相同的,从 Manager 的 ElementList 列表里面移除

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        for (int i = 0; i < 10000; i++)
        {
            ... // 忽略其他代码
            var key = GetKey(i);
            ElementList.RemoveAll(element => element.GetKey(i).N != key.N);
            ... // 忽略其他代码
        }
    }

    ... // 忽略其他代码
}

对于从 ElementList 被移除的 Element 来说,等待这些 Element 就是凌驾于此世界之上的 dotnet 的 GC 回收机制将其当初垃圾清理掉

经过了世界的一次考验,最后剩下的 Element 不多。此世界显得十分空旷,就给了这些存活的 Element 创建子 Element 的机会,在 Element 里实现 Create 方法,用来通过当前的 Element 创建新的 Element 对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public Element Create()
    {
        Element element = new Element(Random);
        foreach (var key in KeyList)
        {
            element.KeyList.Add(key);
        }
        return element;
    }
    ... // 忽略其他代码
}

通过以上代码可以看到,新创建的 Element 不仅继承了用来思考的 Random 随机数,还继承了前辈对世界序列的思考,也就是 KeyList 元素。接下来新的 Element 可以继续在前辈的基础上,对世界序列进行思考

在 Manager 完成考验,将调用 Element 的 Create 方法,让此世界继续被填充

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        for (int i = 0; i < 10000; i++)
        {
            ... // 忽略其他代码
            var currentCount = ElementList.Count;
            while (ElementList.Count < 10000)
            {
                for (int index = 0; index < currentCount; index++)
                {
                    var element = ElementList[index];
                    ElementList.Add(element.Create());
                }
            }
            ... // 忽略其他代码
        }
    }

    ... // 忽略其他代码
}

如果当前的世界考验,干掉了绝大部分的 Element 对象,那么剩下的 Element 就有更多的机会创建出新的 Element 对象

为了防止灭世,也就是某次考验干掉了此世界上所有 Element 小人儿,在每次迭代的时候,如果世界太过空旷,将会额外加上从空白里创建的新 Element 对象

和世界的首批 Element 一样从石头蹦出来的,每次迭代,都会尝试加上一些从石头里面蹦出来的新 Element 对象,更改后的代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        for (int i = 0; i < 10000; i++)
        {
            ... // 忽略其他代码
            bool addElement = false;
            var currentCount = ElementList.Count;
            while (ElementList.Count < 10000)
            {
                for (int index = 0; index < currentCount; index++)
                {
                    var element = ElementList[index];
                    ElementList.Add(element.Create());
                }

                if (addElement)
                {
                    continue;
                }

                addElement = true;
                var addCount = 10000 - ElementList.Count;
                addCount = Math.Min(addCount, 100);
                for (int index = 0; index < addCount; index++)
                {
                    var element = CreateElement();
                    ElementList.Add(element);
                }
            }
            ... // 忽略其他代码
        }
    }

    ... // 忽略其他代码
}

如此的进行迭代,在完成了世界的大循环,也就是 10000 次之后,将会开始最后的审判。判断剩下的 Element 是否了解了世界序列,以及了解了多少次

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        for (int i = 0; i < 10000; i++)
        {
            ... // 忽略其他代码
        }

        for (var i = 0; i < KeyList.Count; i++)
        {
            var key = GetKey(i);
            ElementList.RemoveAll(element => element.GetKey(i).N != key.N);
        }
    }

    ... // 忽略其他代码
}

最后剩下的,都是明了世界序列,也就是明了此世界本质的 Element 小人儿

完成代码编写之后,放入 Main 函数用来启动世界

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
internal class Program
{
    static void Main(string[] args)
    {
        Manager manager = new Manager();
        manager.Start();
    }
}

此代码版本,放在 GitHub 上,可以从 https://github.com/lindexi/lindexi_gd/commit/49878e97df5c75c22d40294b6970aaf46b11c218 获取全部代码

运行代码的结果是,最后剩下的 Element 小人儿,都明了世界序列。其实这也是因为继承了前辈们的知识,从前辈那里拿到了 KeyList 才让越后创建的 Element 有越高的生存率

以上是一个简单的版本,世界序列是非常裸的参与计算,或者说没有参与计算,就根据序列进行返回。接下来对这个世界的游戏规则加上更多的难度,应用上加法规则。加法规则就是取随机的数值,例如 3 个数值,作为序号,再根据序号一一取出 Key 值,接着将 Key 值取和,返回一个数值。此规则同时也对每个 Element 执行,一旦发现 Element 计算出来的最终数值和世界计算出来的不匹配,那就将此 Element 淘汰

新的这个游戏规则其实对 Element 来说,更有挑战性,也同时带来了新的数学上的计算方法,那就是如果 Element 猜测的世界序列和此世界的世界序列不匹配,也有可能在取出的数值里面,通过加法返回相同的值。换句话说,每个 Element 在一轮迭代里面,如果没有被淘汰,那也是无法知道当前猜测的世界序列是否正确。对比之前的规则,之前的规则,一旦猜测错误,自然就会被淘汰

改造一下代码,让 Element 和 Manager 都继承 IKeyManager 接口,方便同时应用上相同的加法规则。这个 IKeyManager 接口定义如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IKeyManager
{
    Key GetKey(int n);
}

加法计算规则的代码实现如下,根据传入参数的序列,获取的 Key 值,取 Key 值的总和

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    private int BuildByKey(IKeyManager keyManager, IList<int> indexList)
    {
        var n = 0;
        foreach (var index in indexList)
        {
            var key = keyManager.GetKey(index);
            n += key.N;
        }

        return n;
    }

    ... // 忽略其他代码
}

看到这里,也许机智的大家也就猜到了。世界序列对应着世界的本源数据,而加法规则对应的通过世界本源数据进行的一套规则。有世界本源数据加上世界的本源规则,即可展现出有趣的世界。有世界的本源规则的存在,也就是此代码世界的加法规则的存在,将会让 Element 小人儿更加难以知道自己所了解的世界规则是对是错

按照以上的加法规则,只要几个 Key 相加的和相等即可,而从数学上,这是无法反算唯一解的。举个例子,假定 indexList 里面有三个序号,分别是 1 2 3 三个序号。而 keyManager 里面根据 1 2 3 返回的 Key 分别是 10 20 30 三个 Key 值,计算出的结果是 60 的值。那反过来,已知返回值是 60 且传入序号是 1 2 3 三个序号。请问 keyManager 存放的 KeyList 里面的第 1 和 第 2 和 第 3 的 Key 应该是多少? 抽象出来的数学题就是,已知三个数加起来的总和是 60 求这三个数。读过小学数学的大家,自然就知道,这三个数没有唯一解

如此加法规则,一开始就要求取序列里面的几个 Key 值,这就要求 Element 小人儿需要一开始就初始化一段 Key 列表。否则就不好玩了。经过实际的测试结果,我发现如果不告诉 Element 小人儿 世界序列的长度 的话,那 Element 小人儿 几乎不能在世界大循环结束之前,明了世界序列。降低游戏的难度,我将告诉 Element 小人儿 世界序列 的长度是 10 个 Key 值。同时也更改了 Element 的 BuildKey 方法,让此方法可以在一开始就生成了序列

在之前的代码基础上,修改 Element 的 BuildKey 方法,本来是 BuildKey 方法每次世界迭代都会调用,现在修改为只有 Element 被创建时才调用,修改过之后的代码如下,以下的代码还不是最终的版本,在下文将会告诉大家最终的版本代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public void BuildKey()
    {
        const int count = 10;
        while (KeyList.Count < count)
        {
            var key = Random.Next(Key.MaxKeyValue);
            KeyList.Add(new Key(key));
        }
    }
    ... // 忽略其他代码
}

以上的代码可以让 Element 创建出来一段序列,序列长度和世界序列长度相同

接着从世界循环里面,删掉每次迭代都调用 BuildKey 方法的代码,也就是这段代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
            foreach (var element in ElementList)
            {
                element.BuildKey();
            }

将调用 BuildKey 方法的代码放入到 CreateElement 方法里,修改之后的方法代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    private Element CreateElement()
    {
        Element element = new Element(new Random(Random.Shared.Next()));
        element.BuildKey();
        return element;
    }
    ... // 忽略其他代码
}

每次世界迭代都会取出随机三个数值,将这三个随机数值传入到 BuildByKey 方法里,通过加法规则算出总和。将此方式分别应用在世界序列和每个 Element 上,将计算结果和世界序列计算出来的不相同的 Element 淘汰掉

实现的代码如下,每次迭代随机三个数值,可以先放入到一个数组里面

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        var indexList = new int[3];
        for (int i = 0; i < 10000; i++)
        {
            ... // 忽略其他代码
        }
    }

    ... // 忽略其他代码
}

每次调用 UpdateRandomIndexList 方法,将 indexList 加上三个随机数值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        var indexList = new int[3];
        for (int i = 0; i < 10000; i++)
        {
            UpdateRandomIndexList(indexList);
            ... // 忽略其他代码
        }
    }

    private void UpdateRandomIndexList(int[] indexList)
    {
        for (var i = 0; i < indexList.Length; i++)
        {
            indexList[i] = Random.Shared.Next();
        }
    }

    ... // 忽略其他代码
}

先计算世界序列经过 BuildByKey 的值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        var indexList = new int[3];
        for (int i = 0; i < 10000; i++)
        {
            UpdateRandomIndexList(indexList);

            var key = BuildByKey(this, indexList);

            ... // 忽略其他代码
        }
    }
    ... // 忽略其他代码
}

接着依然是一句代码,将 ElementList 里面,计算结果不等于 key 值的 Element 淘汰

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Manager
{
    public void Start()
    {
        ... // 忽略其他代码
        var indexList = new int[3];
        for (int i = 0; i < 10000; i++)
        {
            UpdateRandomIndexList(indexList);

            var key = BuildByKey(this, indexList);

            ElementList.RemoveAll(element => BuildByKey(element, indexList) != key);

            ... // 忽略其他代码
        }
    }
    ... // 忽略其他代码
}

淘汰之后,依然就到了根据剩下存活的 Element 构建出来新的 Element 的步骤了。由于这次的 BuildKey 只有在元素创建的时候才被调用,这就意味着需要改造 Create 方法,让 Element 的在创建时调用 BuildKey 方法,修改之后的代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public Element Create()
    {
        Element element = new Element(Random);
        foreach (var key in KeyList)
        {
            element.KeyList.Add(key);
        }

        element.BuildKey();

        return element;
    }
    ... // 忽略其他代码
}

而根据以上的 BuildKey 方法的代码,只是将 KeyList 序列生成到 10 个,显然不符合当前的需求。毕竟现在在创建的时候,就设置了 KeyList 内容了,这会让 BuildKey 方法啥都没有做。 继续优化 BuildKey 方法,让此方法可以将 KeyList 进行更改

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public void BuildKey()
    {
        const int count = 10;
        while (KeyList.Count < count)
        {
            var key = Random.Next(Key.MaxKeyValue);
            KeyList.Add(new Key(key));
        }

        KeyList[Random.Next(count)] = new Key(Random.Next(Key.MaxKeyValue));
    }
    ... // 忽略其他代码
}

以上代码就是优化完成之后的 BuildKey 方法。大概映射的含义就是,子 Element 可以从前辈继承到 KeyList 知识,只是子 Element 要做出变化,变化就是修改 KeyList 中的数据。当前的变化只是修改一项而已

更改完成之后,即可开始跑代码。当前的代码的含义总的来说就是,在此世界里面,有一段世界序列,世界规则将根据世界序列计算出一个值,同样的世界规则也使用相同的算法应用在每个 Element 小人儿上,一旦发现两者计算结果不相同,那么 Element 小人儿将被淘汰。存活下来的 Element 小人儿将可以创建出下一代 Element 小人儿出来,创建的时候,可以将自己的知识传授给下一代。而下一代 Element 小人儿也不是全盘接受的,而是会经过自己的思考,优化从前辈继承到 KeyList 知识

只不过呢,在此世界里面,世界规则只是一个加法规则。而下一代 Element 小人儿的思考也只是一段随机数

尝试运行程序,可以看到这一次灭世的情况发生的次数比一开始的代码的多。灭世的情况就是在世界的某一代中,存活下来的 Element 小人儿的数量是 0 个。可以看到当前代码的规则让 Element 小人儿更加难以应对。但也同时发现了这样的规律,一旦开始有某个 Element 小人儿掌握了一定数量的正确的世界序列的值时,此 Element 小人儿将可以创建出更多更好存活的下一代 Element 小人儿

举个例子来说明运行的情况

假定世界序列就是从 0 到 9 的 10 个 Key 数值。某个 Element 掌握的序列就是 1020120120 序列。刚好一开始的 indexList 就是取前三个,这就让 Element 存活起来了。于是接下来 Element 将创建出下一代的 Element 出来。下一代的 Element 刚好修改的第 3 个(从0开始)序号为 4 的值,修改之后的是 1024120120 序列。下一轮世界取的 indexList 是 1 2 3 三个序号,世界序列计算结果是 1+2+3=6 的值。而原先的 Element 计算出来的是 0+2+0=2 被淘汰,而下一代的 Element 计算出来的是 0+2+4=6 存活。可以看到,尽管下一代的 Element 没有思考出正确的世界序列,然而在世界规则的处理下,依然还是可以存活的,只不过在偏离世界序列的情况下,可以存活的代数自然是有限的

这也能说明能存活下来的 Element 前辈掌握的世界序列是有一定的正确性的,但是下一代的 Element 是不知道前辈有哪些序列是正确的,甚至前辈的 KeyList 都是偏离世界序列的,只是刚好满足当前的世界规则而存活

在经过了世界大循环之后,可以再来看看存活下来的 Element 小人儿掌握世界序列的情况。这次的结果是绝大部分的 Element 小人儿掌握了正确的世界序列,之后少部分的 Element 小人儿掌握了错误的世界序列。这些少部分的掌握错误的世界序列的 Element 小人儿都是在最后几代世界循环里面创建的。也就是说活的足够久的 Element 小人儿都是掌握了正确的世界序列的

这也能映射到现实世界的一部分,能够存活下来的生物,或者人,都是掌握了一定的世界序列,也就是世界本源或者说世界的知识,或者说是符合世界规则。掌握的越多,或者说行为越靠近世界规则,就越能存活

此代码版本,放在 GitHub 上,可以从 https://github.com/lindexi/lindexi_gd/commit/5f7d17b206b904db424d17fed6cef48eb0965496 获取全部代码

这个代码游戏到这里还没有结束,可以玩的还有很多。例如修改下一代的 Element 的思考逻辑,让下一代的 Element 更加有想法,想要更改更多的知识。在修改之后的代码世界,下一代的 Element 更加质疑前辈的知识,会更多的思考世界序列,而不是和之前的代码一样,只是修改世界序列里面的一项

修改之后的代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Element
{
    public void BuildKey()
    {
        const int count = 10;
        while (KeyList.Count<count)
        {
            var key = Random.Next(Key.MaxKeyValue);
            KeyList.Add(new Key(key));
        }

        var updateCount = Random.Next(1, count);
        for (int i = 0; i < updateCount; i++)
        {
            KeyList[Random.Next(count)] = new Key(Random.Next(Key.MaxKeyValue));
        }
    }
    ... // 忽略其他代码
}

运行一下代码,可以看到此时运行的情况是,在很多代的世界大循环里面,即世界代数里,大量存在灭世的情况。因为下一代的 Element 小人儿思考越多,代表着继承到的前辈的知识越少。继承的知识越少,越难以存活。这也能说明前辈们的知识是有用的

此代码版本,放在 GitHub 上,可以从 https://github.com/lindexi/lindexi_gd/commit/9bb128484abfa9fe6f5ba3ff66a91505fb3105b5 获取全部代码

好了,今天的小测试就到这里。通过这个代码故事可以告诉咱,在这个代码世界里面,是符合天有五贼,见之者昌的道理,越接近世界序列的 Element 小人儿将越能存活。这个和当前的现实世界也差不多

在这个代码世界里面,前辈的知识是有用的,学习前辈的知识可以更好帮助存活,符合书籍是人类进步的阶梯这句话的道理。通过让前辈的知识传授给下一代,可以逐渐让整个世界在一代一代的循环里面存活的 Element 小人儿的数量越多

在此代码世界里面,前辈传授给下一代的知识也不一定是完全正确的,下一代需要进行质疑,因为前辈说不定活不过世界的下次迭代,前辈的知识只是刚好在当前的世界规则下是正确的,不代表着在下一次迭代的世界规则还是正确的。映射到现实世界,那就是需要质疑前辈的知识,前辈的知识放在前辈的时代是正确的,不代表在当前也是正确的。但是将前辈们的知识全抛掉,那自然也是不对的

现实世界里面也许存在世界序列和世界规则,然而现实世界里面可不会告诉大家,有多少个世界序列列表,世界序列的每个项的取值范围是多少,世界序列有多长等。试试在代码世界里面,让代码世界的世界序列的取值范围更大,或者是世界序列更长,试试看修改之后的灭世次数。同样现实世界不会告诉大家世界规则是什么,有多少个规则。现实世界的世界序列和世界规则更加复杂,这就让在现实世界进行探索世界的本质更加难。但是有一点是正确的,那就是学习前辈们的知识同时进行自己的思考,在一代代的努力下,可以不断靠近世界的本质

这个代码世界还有很多可以玩的,例如可以修改更有趣的世界规则,也就是 BuildByKey 方法。修改 Element 的思考方式等

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C# Random 生成不重复随机数
伪随机数是以相同的概率从一组有限的数字中选取的。所选数字并不具有完全的随机性,因为它们是用一种确定的数学算法选择的,但是从实用的角度而言,其随机程度已足够了。
用户8671053
2021/09/26
1.6K0
多线程环境下生成随机数
Java里有伪随机型和安全型两种随机数生成器。伪随机生成器根据特定公式将seed转换成新的伪随机数据的一部分。安全随机生成器在底层依赖到操作系统提供的随机事件来生成数据。
马士兵的朋友圈
2020/09/08
1.2K0
如何用遗传算法进化出一只聪明的小鹦鹉
现在有一些样本数据,如下表所示。你是否能找到其中的规律,然后计算出新样本的output是多少?
Stanley Sun
2019/09/23
5100
如何用遗传算法进化出一只聪明的小鹦鹉
产生随机数算法[通俗易懂]
两个办法帮你解决如何在Java中产生随机数   随机数在日常的应用和开发中经常会见到,比如说某些系统会为用户生成一个最初的初始化密码,这就是一个随机数。如何生成这个随机数,不同的开发工具的方法也不一样。在应用中,Java是应用最为广泛的开发工具之一,如何在Java中产生随机数,也是很多开发者在初学随机数时的一个必修课,在此为读者贡献两个办法帮你解决如何在Java中产生随机数。
全栈程序员站长
2022/09/17
2.1K0
遗传算法(1)
与其说遗传算法是一个算法,不如说是一种处理问题的思想方式更为恰当,因为遗传算法整个体系说来说去都是在说对于一种问题处理的思路和原则,而不是一个具体的代码编写过程。 遗传算法(Genetic Algorithm)是一类借鉴生物界的进化规律(适者生存,优胜劣汰遗传机制)演化而来的随机化搜索方法。它是由美国的J.Holland教授1975年首先提出的,不过它借鉴的可是进化论的理论依据。在这个体系里,思维方式远比编写代码重要,所以我们先用一点时间来缅怀一下遗传算法真正的鼻祖,著名的英国生物学家查尔斯·罗伯特·达尔
刀刀老高
2018/04/11
1.7K0
遗传算法(1)
Redis应用—8.相关的缓存框架
整体上看,Ehcache的使用是相对简单便捷的,提供了完整的各类API接口。需要注意,虽然Ehcache支持磁盘的持久化,但是由于存在两级缓存介质,在一级内存中的缓存如果没有主动刷入磁盘持久化,则在应用异常宕机时,依然会出现缓存数据丢失,为此可以根据需要将缓存刷到磁盘。将缓存条目刷到磁盘的操作可以通过cache.flush()方法来执行。需要注意:将对象写入磁盘前,要先将对象进行序列化。
东阳马生架构
2025/03/07
1040
有关遗传算法的一个简单入门的例子(java语言实现)
摘要:本报告提出了一个能体现遗传算法原理的例子,并侧重于java语言的编程实现,结果较好地完成了算法的要求。基因遗传算法是一种灵感源于达尔文自然进化理论的启发式搜索算法。算法反映了自然选择的过程,即最适者被选定繁殖,并产生下一代。
Reborn Lee
2020/06/29
1.4K0
C# dotnet 一个还看的过去的 B 树实现
我尝试找到一个 B 树的实现,尽管这个东西十分简单,但是依然网上有很多不同的版本。我在 justcoding121 的版本上魔改了一下,就是本文可以用来给大家的版本
林德熙
2022/08/12
2260
【小家java】Java中Random ThreadLocalRandom 设置随机种子获取随机数精讲
我们都知道,随机数在太多的地方使用了,比如加密、混淆数据等,我们使用随机数是期望获得一个唯一的、不可仿造的数字,以避免产生相同的业务数据造成混乱。 在Java项目中通常是通过Math.random方法和Random类来获得随机数的。那么本文针对于这两种产生随机数的方法进行源码级别的精度,让你以后不再犯错。
YourBatman
2019/09/03
1.9K0
【优化算法】遗传算法(Genetic Algorithm) (附代码及注释)
遗传算法(Genetic Algorithm, GA)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
短短的路走走停停
2019/05/14
27.5K2
【优化算法】遗传算法(Genetic Algorithm) (附代码及注释)
LINQ常用扩展方法、委托、Lambda、yield
 每一项数据都会经过predicate的测试,如果针对一个元素,predicate执行的返回值为true,那么这个元素就会放到返回值中。 Where参数是一个lambda表达式格式的匿名方法,方法的参数e表示当前判断的元素对象。参数的名字不一定非要叫e,不过一般lambda表达式中的变量名长度都不长。
鱼找水需要时间
2024/03/23
1250
我们应该从JAVA集合中学到什么
本文不讲解各种集合间的区别,适用场景是什么,增删改查的时间复杂度和时间复杂度是多少,是否线程安全,是否有序,是否支持随机访问,是否是快速失败的,也不关心底层结构是数组、哈希表、链表、红黑树的哪一个。如果你阅读过我blog(www.liangsonghua.me)大部分文章就会发现基本上是总结性、技巧性、细节性的,送一句话与你共勉:看懂然后模仿再创造,加油!!
公众号_松华说
2019/07/16
2810
我们应该从JAVA集合中学到什么
Python
概念:保留字是Python语言中已经被赋予特定意义的一些单词,开发程序时,不可以作为变量、函数、类、模块和其他对象的名称来使用。
青灯古酒
2023/10/16
1650
Python
python基础题目大全,测试你的水平,巩固知识(含答案)
(1)、python代码,简介,明确,优雅,简单易懂 (2)、开发效率高 (3)、可扩展性强
一墨编程学习
2018/12/26
9430
遗传算法解决TSP问题实现以及与最小生成树的对比
本实验采用遗传算法实现了旅行商问题的模拟求解,并在同等规模问题上用最小生成树算法做了一定的对比工作。遗传算法在计算时间和占用内存上,都远远优于最小生成树算法。
流川疯
2022/11/29
7500
遗传算法解决TSP问题实现以及与最小生成树的对比
TensorFlow官方教程翻译:导入数据
需要注意的是,如下教程的tf.data的模块需要将tensorflow升级到1.4的版本,才可以支持,低于1.4的版本的导入数据教程,见之前的翻译教程,戳这里(https://www.jianshu.com/p/64bd6a49a94a) Dataset的API让你能从简单,可重用的模块中构建复杂的输入管道。例如一个图片模型的输入管道,可能要从分布式的文件系统中获得数据,对每张图片做随机扰动,以及将随机选取的图片合并到一个批次中用作训练。文本模型的输入管道可能涉及到从原始文本数据中提取符号,然后将其转换到查
用户1332428
2018/03/09
2.4K0
【整理】待毕业.Net码农就业求职储备
声明:本文题目来源于互联网,仅供即将从学校毕业的.Net码农(当然,我本人也是菜逼一个)学习之用。当然,学习了这些题目不一定会拿到offer,但是针对就业求职做些针对性的准备也是不错的。此外,除了技术上的准备外,要想得到提升,还得深入内部原理,阅读一些经典书籍(例如Jeffrey Richter的《CLR via C#》)以及借助Reflector或ILSpy反编译查看源码实现,知其然也知其所以然,方能得到感性认识到理性认识的飞跃!另外,本来想将本文标题取为就业求职宝典,但一想这名字太LOW了,而且太过浮华了,本文也根本达不到那个目标,于是将其改为储备,简洁明了。
Edison Zhou
2018/08/20
6931
【整理】待毕业.Net码农就业求职储备
Swift 3到5.1新特性整理
Swift 5.0 最重要的自然是ABI Stability, 对此可以看这篇 Swift ABI 稳定对我们到底意味着什么 。
小刀c
2022/08/16
4.8K0
Swift 3到5.1新特性整理
无梯度强化学习:使用Numpy进行神经进化
如果我告诉你训练神经网络不需要计算梯度,只需要前项传播你会怎么样?这就是神经进化的魔力!同时,我要展示的是,所有这一切只用Numpy都可以很容易地做到!学习统计学你会学到很多关于基于梯度的方法,但是不久前我读了Uber AI的人写的一篇非常有趣的文章,他表明在解决Atari游戏时,简单的遗传算法与最复杂的基于梯度的RL方法是挺有竞争力的。我链接了下面的来源,如果你对强化学习感兴趣,我强烈建议你读一读。
磐创AI
2020/07/01
5450
无梯度强化学习:使用Numpy进行神经进化
玩转EhCache之最简单的缓存框架
Ehcache是一个用Java实现的使用简单,高速,实现线程安全的缓存管理类库,ehcache提供了用内存,磁盘文件存储,以及分布式存储方式等多种灵活的cache管理方案。同时ehcache作为开放源代码项目,采用限制比较宽松的Apache License V2.0作为授权方式,被广泛地用于Hibernate, Spring,Cocoon等其他开源系统。Ehcache 从 Hibernate 发展而来,逐渐涵盖了 Cahce 界的全部功能,是目前发展势头最好的一个项目。具有快速,简单,低消耗,依赖性小,扩展性强,支持对象或序列化缓存,支持缓存或元素的失效,提供 LRU、LFU 和 FIFO 缓存策略,支持内存缓存和磁盘缓存,分布式缓存机制等等特点。
小程故事多
2018/08/22
2.8K0
玩转EhCache之最简单的缓存框架
相关推荐
C# Random 生成不重复随机数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档