Solidity实现智能合约——宠物进食系统(二)

Solidity实现智能合约——宠物进食系统(二)

在上一节当中我们实现了创建宠物的功能,接下来将继续完善功能,让我们的宠物可以进食。

为了存储宠物的所有权,我们会使用到两个映射:一个记录宠物拥有者的地址,另一个记录某地址所拥有宠物的数量。

创建一个叫做 AnimalToOwner 的映射。其键是一个uint(我们将根据它的 id 存储和查找宠物),值为 address。映射属性为public。
创建一个名为 ownerAnimalCount的映射,其中键是 address,值是 uint。

 mapping (uint => address) public AnimalToOwner;
 mapping (address => uint) ownerAnimalCount;

修改上一节当中的 _createAnimal方法,将宠物分配给函数调用者
在得到新的宠物 id 后,更新 AnimalToOwner 映射,在 id 下面存入 msg.sender。然后,我们为这个 msg.sender 名下的 ownerAnimalCount 加 1。

 
    function _createAnimal(string _name,uint _dna) internal{
        uint animalId = animals.push(Animal(_name,_dna))-1;   
         //  将当前地址对应此时的id 
        AnimalToOwner[animalId] = msg.sender;
        //  这个地址下的宠物数量加一 
        ownerAnimalCount[msg.sender]++;
        NewAnimal(animalId, _name, _dna);
    }

我们不希望用户通过反复调用 createRandomAnimal 来创建无限多个宠物 ,我们可以使用了 require 来确保这个函数只有在每个用户第一次调用它的时候执行,用以创建初始宠物。在 createRandomAnimal 的前面放置 require 语句。 使得函数先检查 ownerAnimalCount[msg.sender]的值为 0 ,不然就抛出一个错误。

 function createRandomAnimal(string _name) public {
        //  用户只能创建一次初始宠物  
        require(ownerAnimalCount[msg.sender] == 0);
        uint randDna = _generateRandomDna(_name);
        _createAnimal(_name, randDna);
    }

接下来为了不让代码过于冗余,我们在AnimalFeeding.sol当中新建一个合约 AnimalFeeding并让它继承上一节当中的AnimalFactory合约

pragma solidity ^0.4.19;

contract  AnimalFeeding is AnimalFactory {

}

.将 AnimalFactory.sol 导入到我们的新文件AnimalFeeding.sol 中。

pragma solidity ^0.4.19;

import "./AnimalFactory.sol";

contract  AnimalFeeding is AnimalFactory{

 

}

这时候我们就可以给宠物增加“猎食”和“繁殖”功能了!当一个宠物进食时,它自身的DNA将与食物的DNA结合在一起,形成一个新的宠物DNA。

创建一个名为feedAndGrow 的函数。 使用两个参数: _AnimalId( uint类型 )和_targetDna (也是 uint 类型)。 设置属性为 public 的。

我们不希望别人用我们的宠物去进食。 首先,我们确保对自己宠物的所有权。 通过添加一个require 语句来确保 msg.sender 只能是这个宠物的主人(类似于我们在 createRandomAnimal 函数中做过的那样)。

为了获取这个宠物的DNA,我们的函数需要声明一个名为 myAnimal 数据类型为Animal的本地变量(这是一个 storage 型的指针)。 将其值设定为在animals 数组中索引为_AnimalId所指向的值。

 function feedAndGrow(uint _AnimalId,uint _targetDna)public {
        // 确保当前的宠物是自己的  
        require(msg.sender == AnimalToOwner[_AnimalId]);
        //  获取这个宠物的DNA
        Animal storage myAnimal = animals[_AnimalId];
    }

当获取食物的DNA时,我们就可以让宠物进食,让宠物DNA和食物DNA结合生成新的宠物DNA,另外我们也可以给新宠物起名。这里只是将宠物DNA和食物DNA算了平均值并把最后两位数字替换成了99,最后宠物的新名字为"No-one"。

  //  实现进食功能    宠物   食物DNA 
    function feedAndGrow(uint _AnimalId,uint _targetDna)public {
        // 确保当前的宠物是自己的  
        require(msg.sender == AnimalToOwner[_AnimalId]);
        //  获取这个宠物的DNA
        Animal storage myAnimal = animals[_AnimalId];
        
         _targetDna = _targetDna % dnaLength;
         uint newDna = (myAnimal.dna + _targetDna) / 2;
         newDna = newDna - newDna % 100 + 99;
         _createAnimal("No-one", newDna);
    }

上面的feedAndGrow函数需要传入的参数为宠物ID和食物DNA,宠物ID我们可以拿到,那么食物DNA我们该如何获取呢,接下来就要创建一个生成食物DNA的函数。这个函数的功能很简单,调用这个函数传入uint值,通过一个hash函数将这个uint生成一个hash值,而我们最后只会取这个hash值的后16位作为食物的DNA

 function _catchFood(uint _name) internal pure returns (uint){
        uint rand = uint(keccak256(_name));
        return rand;
    }

最后就是通过一个feedOnFood函数来调用上面的俩个部件来实现我们想要的功能:宠物进食可以生成新的宠物名和新的DNA(末尾俩位数字为99),而且我们初始只能创建一个宠物。

最后贴上我们的完整代码

pragma solidity ^0.4.19;
import "./AnimalFactory.sol";

contract  AnimalFeeding is AnimalFactory{
    
     //  实现进食功能    宠物   食物DNA 
    function feedAndGrow(uint _AnimalId,uint _targetDna)public {
        // 确保当前的宠物是自己的  
        require(msg.sender == AnimalToOwner[_AnimalId]);
        //  获取这个宠物的DNA
        Animal storage myAnimal = animals[_AnimalId];
        
         _targetDna = _targetDna % dnaLength;
         uint newDna = (myAnimal.dna + _targetDna) / 2;
         newDna = newDna - newDna % 100 + 99;
         _createAnimal("No-one", newDna);
    }
    
    function _catchFood(uint _name) internal pure returns (uint){
        uint rand = uint(keccak256(_name));
        return rand;
    }
    
    function feedOnFood(uint _AnimalId,uint _FoodId) public{
        uint foodDna = _catchFood(_FoodId);
        feedAndGrow(_AnimalId,foodDna);
    }
    
}

接下来给大家演示一下代码的功能
在这里插入图片描述
在这里插入图片描述
部署成功之后我们可以先创建我们的宠物drogon
在这里插入图片描述
此时我们还可以继续尝试初始创建第二个宠物cat,这时候你就会发现初始化失败,说明我们定义的初始化一个宠物的功能实现了。
在这里插入图片描述
接下来给我们的宠物进食。发现喂食成功,此时我们可以来查看我们的数组当中的宠物
在这里插入图片描述
我们的第一个初始化宠物drogon
在这里插入图片描述
drogon进食后进化成的第二个宠物No-one,而且我们可以发现新宠物的DNA最后俩位成功变成了99
在这里插入图片描述
到这里我们的功能就都实现了,大家也可以去尝试玩一玩。
下一节我们进一步对这个合约进行功能优化:链接: Solidity实现智能合约——Solidity高级理论(三)

Guess you like

Origin blog.csdn.net/qq_43537319/article/details/121172401