Assignment - DNA Mixing

hey @walter_w ! Check out this answer where I explain how to render multiple cats.

hi guys,

heres my code for function breed

function breed(uint dadId, uint mumId) public returns(uint256){
        //check ownership
        require(_owes(msg.sender, dadId));
        require(_owes(msg.sender, mumId));
        
        Doggie memory _dadId = doggies[dadId];
        uint dadDna = _dadId.genes;
        Doggie memory _mumId = doggies[mumId];
        uint mumDna = _mumId.genes;
        uint newDna = _mixDna(dadDna, mumDna);
        //figure out generation
        uint16 _generation = _dadId.generation + 1;
            
        //create new Dog with new properties and give it to the msg.sender
         _createDoggie(mumId, dadId, _generation, newDna, msg.sender);
    }
2 Likes
breed function
function breed(uint256 dadId, uint256 mumId) public returns (uint256) {
        Kitty storage dad = kitties[dadId];
        Kitty storage mum = kitties[mumId];

        require(
            kittyIndexToOwner[dadId] == msg.sender &&
            kittyIndexToOwner[mumId] == msg.sender,
             "Owner must own tokens");

        require(
            dad.generation == mum.generation,
            "Only cats from same generation can procreate");


        uint256 dadDna = dad.genes;
        uint256 mumDna = mum.genes;
        uint256 newDna = _mixDna(dadDna, mumDna);

        uint16 newGeneration = dad.generation + 1;

        return _createKitty(mumId, dadId, newGeneration, newDna, msg.sender);
    }```

1 Like
    function breed(uint256 _dadId, uint256 _mumId) public returns (uint256 newKittenId){
        //Check ownership
        require(_owns(msg.sender, _dadId));
        require(_owns(msg.sender, _mumId)); 
        //You got the DNA
        uint256 newDna = _mixDna(_dadId, _mumId);
        //Figure out the Generation
        uint256 _generation;

        if(kitties[_mumId].generation == kitties[_dadId].generation){
            _generation = kitties[_mumId].generation++;
        }
        else if (kitties[_mumId].generation < kitties[_dadId].generation)
        {
            _generation = kitties[_mumId].generation++;
        }
        else{
            _generation = (kitties[_mumId].generation + kitties[_dadId].generation) / 2 + 1;
        }

        //Create a new cat with the new properties, give it to the msg.sender
        return newKittenId = _createKitty(_mumId, _dadId, _generation, newDna, msg.sender);
    }
1 Like

Did you ever get help with this? Struggling to have the array of owned nft’s appear when loading a catalogue page. Way too much time wasted.

Yeah, the catalogue is a tricky part. You can’t use the same code that what we used for the factory (not without adjustments at least).
You can try to check a few completed projects from Assignment - Marketplace Frontend to try to understand how it works. That’s what I’ve done.

My code is slightly different. Does it work? I had to take out “returns(uint)” because the function doesn’t return anything and I got an warning while compiling.

    function breed(uint _mumId, uint _dadId) public {
        //Check ownership of mum and dad
        require(ownership[_mumId] == msg.sender, "Mum cat does not belong to msg.sender");
        require(ownership[_dadId] == msg.sender, "Dad cat does not belong to msg.sender");

        //You got the DNA
        uint _mumDNA = allTokens[_mumId].genes;
        uint _dadDNA = allTokens[_dadId].genes;
        uint newDNA = _mixDNA(_mumDNA, _dadDNA);

        //Figure out the generation of new cat
        //I took the average of the parents and added one
        uint newKittyGen = ((allTokens[_mumId].generation + allTokens[_dadId].generation) / 2) + 1;

        //Create a new cat with the new properties, transfer it to the msg.sender
        _createKitty(_mumId, _dadId, newKittyGen, newDNA, msg.sender);
     
    }

hey @Emerald_Coast did you try to run this function?

Here it is with some pseudo-randomness (DNA mixing functions are at the bottom of the contract).

There’s something about this contract that’s been bothering me, maybe someone can explain. Why isn’t the ‘kittenId’ stored in the actual Kitty struct? I know it’s not entirely necessary, but wouldn’t it be pretty helpful for users to be able to easily find the Id of each token?

pragma solidity 0.8.0;

// import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./Ownable.sol";

contract Kittycontract is Ownable {

    string public constant tickerName = "ThePowerOfMeow";
    string public constant tickerSymbol = "MEOW";
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
    uint256 totalTokenCount;

    bytes4 internal constant MAGIC_ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    uint256 public gen0Counter = 0;

    event Birth(
      address owner,
      uint256 kittenId,
      uint256 matronId,
      uint256 sireId,
      uint256 genes
    );

    struct Kitty {
        uint256 genes;
        uint64 birthTime;
        uint32 matronId;
        uint32 sireId;
        uint16 generation;
    }

    Kitty[] kitties;

    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    mapping(address => uint256) private ownershipTokenCount;
    mapping(uint256 => address) public ownedBy;

    mapping(uint256 => address) public kittyIndexToApproved;
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    function supportsInterface(bytes4 _interfaceId) external pure returns(bool){
        return(_interfaceId == _INTERFACE_ID_ERC721 || _interfaceId == _INTERFACE_ID_ERC165);
    }

    function _createKitty(
      uint256 _matronId,
      uint256 _sireId,
      uint256 _generation,
      uint256 _genes,
      address _owner
    ) private returns(uint256) {
        Kitty memory _kitty = Kitty({
            genes: _genes,
            birthTime: uint64(block.timestamp),
            matronId:uint32(_matronId),
            sireId: uint32(_sireId),
            generation: uint16(_generation)
        });
        kitties.push(_kitty);
        uint256 newKittenId = kitties.length - 1;
        emit Birth(_owner, newKittenId, _matronId, _sireId, _genes);
        _transfer(address(0), _owner, newKittenId);
        return newKittenId;
    }

    function createKittyGen0(uint256 _genes) public onlyOwner returns(uint256 id){
        require(gen0Counter < CREATION_LIMIT_GEN0, "Maximum Gen0 limit reached");
        gen0Counter++;
        return _createKitty(0, 0, 0, _genes, msg.sender);
    }

    function breed(uint256 matronId, uint256 sireId) public {
        //check ownership
        require(ownedBy[matronId] == msg.sender && ownedBy[sireId] == msg.sender);
        //New DNA function
        uint256 newGenes = mixDna(kitties[matronId].genes, kitties[sireId].genes);
        //figure out the generation
        uint256 newGeneration;
        if(kitties[matronId].generation > kitties[sireId].generation) {
            newGeneration = kitties[matronId].generation + 1;
        } else {
            newGeneration = kitties[sireId].generation + 1;
        }
        //create new cat, give it to msg.sender
        _createKitty(matronId, sireId, newGeneration, newGenes, msg.sender);
    }



    function getKitty(uint kittenId) public view returns(Kitty memory) {
        return kitties[kittenId];
    }

    function balanceOf(address owner) external view returns(uint256 balance) {
        return ownershipTokenCount[owner];
    }

    function totalSupply() external view returns (uint256 total) {
        return kitties.length;
    }

    function name() external pure returns (string memory tokenName) {
        return tickerName;
    }

    function symbol() external pure returns (string memory tokenSymbol) {
        return tickerSymbol;
    }

    function ownerOf(uint256 tokenId) external view returns (address owner) {
        address tokenOwner = ownedBy[tokenId];
        require(tokenId < kitties.length, "Token does not exist");
        return tokenOwner;
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external {
        require(validateOperator(msg.sender, tokenId) || kittyIndexToApproved[tokenId] == msg.sender, "Unauthorized operator");
        require(to != address(0), "Invalid recipient, cannot transfer to zero addres");
        _safeTransfer(from, to, tokenId, data);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId) external {
      require(validateOperator(msg.sender, tokenId) || kittyIndexToApproved[tokenId] == msg.sender, "Unauthorized operator");
      require(to != address(0), "Invalid recipient, cannot transfer to zero addres");
      _safeTransfer(from, to, tokenId, "");
    }

    function _safeTransfer(address _from, address _to, uint256 _tokenId, bytes memory _data) internal {
        _transfer(_from, _to, _tokenId);
        require(_checkIERC721Support(_from, _to, _tokenId, _data));
    }

    function transfer(address to, uint256 tokenId) external {
        require(to != address(0), "Invalid recipient, cannot transfer to zero addres");
        require(to != address(this), "Invalid recipient, cannot transfer to this contract");
        require(to != msg.sender, "Invalid recipient, you cannot transfer to yourself");
        require(ownedBy[tokenId] == msg.sender, "Transfer function is only for token owner, operator should use transferFrom");
        _transfer(msg.sender, to, tokenId);
    }

    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        ownershipTokenCount[_to]++;
        if(_from != address(0)){
            ownershipTokenCount[_from]--;
            delete kittyIndexToApproved[_tokenId];
        }
        ownedBy[_tokenId] = _to;
        emit Transfer(_from, _to, _tokenId);
    }

    function approve(address approved, uint256 tokenId) external {
        require(ownedBy[tokenId] != address(0));
        require(validateOperator(msg.sender, tokenId), "Only token owner or authorized operator can approve");
        _approve(ownedBy[tokenId], approved, tokenId);
    }

    function _approve(address _owner, address _approved, uint256 _tokenId) internal {
        kittyIndexToApproved[_tokenId] = _approved;
        emit Approval(_owner, _approved, _tokenId);
    }

    function setApprovalForAll(address operator, bool approved) external {
        require(operator != msg.sender, "Operator must be a third party");
        _setApprovalForAll(operator, approved);
    }

    function _setApprovalForAll(address _operator, bool _approved) internal {
        _operatorApprovals[msg.sender][_operator] = _approved;
        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    function getApproved(uint256 tokenId) public view returns (address) {
        require(tokenId < kitties.length, "Token does not exist");
        return kittyIndexToApproved[tokenId];
    }

    function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
        return _operatorApprovals[_owner][_operator];
    }

    function transferFrom(address from, address to, uint256 tokenId) external {
        require(validateOperator(msg.sender, tokenId) || kittyIndexToApproved[tokenId] == msg.sender, "Unauthorized operator");
        require(from == ownedBy[tokenId], "Can only transfer from token owner");
        require(to != address(0), "Token has no owner");
        require(tokenId < kitties.length, "Token does not exist");
        _transfer(from, to, tokenId);
    }

    function validateOperator(address _operator, uint _tokenId) internal view returns(bool) {
        bool validOperator = false;
        address tokenOwner = ownedBy[_tokenId];
        if(tokenOwner == _operator){
            validOperator = true;
        }
        else if(_operatorApprovals[tokenOwner][_operator] == true){
            validOperator = true;
        }
        return validOperator;
    }

    function _checkIERC721Support(address _from, address _to, uint256 _tokenId, bytes memory _data) internal returns(bool) {
        if(!_isContract(_to)){ // if _to is NOT a contract, that means it's a wallet and all is well
            return true;
        }
        bytes4 returnData = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
        return returnData == MAGIC_ERC721_RECEIVED;
    }

    function _isContract(address _to) internal view returns(bool) {
        //check if address _to code size is > 0, which means it's a contract rather than a wallet
        uint32 size;
        assembly{
            size := extcodesize(_to)
        }
        return size > 0;
    }

    function mixDna(uint256 matronDna, uint256 sireDna) internal returns(uint256) {
        return mixDnaColors(matronDna, sireDna) + mixDnaCattributes(matronDna, sireDna);
    }

    function mixDnaColors(uint256 matronDna, uint256 sireDna) internal view returns(uint256){

        uint256 dnaBodyColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -1))) % 2 == 0){
            dnaBodyColor = matronDna / 100000000000000;
        } else {
            dnaBodyColor = sireDna / 100000000000000;
        }
        uint256 dnaEyeColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -2))) % 2 ==0) {
            dnaEyeColor = (matronDna/1000000000000) % 100;
        } else {
            dnaEyeColor = (sireDna/1000000000000) % 100;
        }
        uint256 dnaPawsColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -3))) % 2 ==0) {
            dnaPawsColor = (matronDna/10000000000) % 100;
        } else {
            dnaPawsColor = (sireDna/10000000000) % 100;
        }
        uint256 dnaStripesColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -4))) % 2 ==0) {
            dnaStripesColor = (matronDna/100000000) % 100;
        } else {
            dnaStripesColor = (sireDna/100000000) % 100;
        }
        return( (dnaBodyColor * 100000000000000) + (dnaEyeColor * 1000000000000) + (dnaPawsColor * 10000000000) + (dnaStripesColor * 100000000));
    }

    function mixDnaCattributes(uint256 matronDna, uint256 sireDna) internal view returns(uint256){

        uint256 dnaEyeStyle;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -5))) % 2 ==0) {
            dnaEyeStyle = (matronDna/10000000) % 10;
        } else {
            dnaEyeStyle = (sireDna/10000000) % 10;
        }
        uint256 dnaStripesPattern;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -6))) % 2 ==0) {
            dnaStripesPattern = (matronDna/1000000) % 10;
        } else {
            dnaStripesPattern = (sireDna/1000000) % 10;
        }
        uint256 dnaBellyColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -7))) % 2 ==0) {
            dnaBellyColor = (matronDna/10000) % 100;
        } else {
            dnaBellyColor = (sireDna/10000) % 100;
        }
        uint256 dnaJowlsColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -8))) % 2 ==0) {
            dnaJowlsColor = (matronDna/100) % 100;
        } else {
            dnaJowlsColor = (sireDna/100) % 100;
        }
        uint256 dnaAnimation;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -9))) % 2 ==0) {
            dnaAnimation = (matronDna/10) % 10;
        } else {
            dnaAnimation = (sireDna/10) % 10;
        }
        return((dnaEyeStyle * 10000000) + (dnaStripesPattern * 1000000) + (dnaBellyColor * 10000) + (dnaJowlsColor * 100) + (dnaAnimation * 10));
    }

}

Hey @Attiss ! We use the index as token Id, for user find their dragons you can use different getter functions like

getSingleDragon(uint DragonId) 
getAllDragons(uint[] DragonIds)

Here are the mixing functions added for the breeding.

    function breed(uint _dadId, uint _mumId) public returns (uint) {
        // Check Ownership
        require (ownerOf(_dadId) == msg.sender, "The Sender Does Not Own The Dad");
        require (ownerOf(_mumId) == msg.sender, "The Sender Does Not Own The Mum");

        // Figure out Generation
        Kitty memory dad = kitties[_dadId];
        Kitty memory mum = kitties[_mumId];

        uint16 dadGeneration = dad.generation;
        uint16 mumGeneration = mum.generation;

        uint newGeneration = _mixGeneration(uint256(dadGeneration), uint256(mumGeneration));

        uint16 dadDna = dad.genes;
        uint16 mumDna = mum.genes;

        uint newDna = _mixDna(dadDna, mumDna);

        uint mintedCat = _createKitty(_mumId, _dadId, newGeneration, newDna, msg.sender);
        return mintedCat;
    }

    function _mixGeneration(uint _dadGeneration, uint _mumGeneration) internal pure returns (uint) {
        uint mixedGeneration = (_dadGeneration + _mumGeneration) / 2;
        require (mixedGeneration > 0);
        return mixedGeneration;
    }

    function _mixDna(uint _dadDna, uint _mumDna) internal pure returns (uint) {

        // daddna: 11 22 33 44 55 66 77 88
        // mumdna: 88 77 66 55 44 33 22 11

        uint firstHalf = _dadDna / 100000000; // 11 22 33 44
        uint secondHalf = _mumDna % 100000000; // 44 33 22 11

        uint extendedDna = firstHalf * 100000000; // 11 22 33 44 00 00 00 00

        uint finalDna = extendedDna + secondHalf; // 11 22 33 44 44 33 22 11
        return finalDna;
    }

And the full code for the contract for now:

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./Ownable.sol";
import "./IERC721Receiver.sol";

contract Kittycontract is IERC721, Ownable {

    string private tokenName = "KittyToken";
    string private tokenSymbol = "KITTY";
    uint constant MAXGENZEROCATS = 2000;
    uint currentGenZeroCats;
    bytes4 internal constant MAGIC_ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    event Birth(address _owner, uint _kittenId, uint _mumId, uint _dadId, uint _genes);

    struct Kitty {
        uint16 genes;
        uint64 birthTime;
        uint32 mumId;
        uint32 dadId;
        uint16 generation;
    }

    function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
        return _interfaceId == _INTERFACE_ID_ERC721 || _interfaceId == _INTERFACE_ID_ERC165;
    }

    function createKittyGenZero(uint _genes) external returns (uint kittyId) {

        require(currentGenZeroCats < MAXGENZEROCATS);
        currentGenZeroCats += 1;

        return _createKitty(0, 0, 0, _genes, msg.sender);

    }

    function _createKitty(uint _mumId, uint _dadId, uint _generation, uint _genes, address _owner) private returns (uint kittyId) {
        Kitty memory _kitty = Kitty({genes: uint16(_genes), birthTime: uint64(block.timestamp), mumId: uint32(_mumId), dadId: uint32(_dadId), generation: uint16(_generation)});
        kitties.push(_kitty);
        uint newKittenId = kitties.length - 1;
        _transfer(address(0), _owner, newKittenId);
        emit Birth(_owner, newKittenId, _mumId, _dadId, _genes);
        return newKittenId;
    }

    function getKitty(uint256 _kittyId) public view returns (uint _genes, uint _birthTime, uint _mumId, uint _dadId, uint _generation, address _owner) {
        require(_kittyId < kitties.length);

        Kitty storage kitty = kitties[_kittyId];

        _genes = uint256(kitty.genes);
        _birthTime = uint256(kitty.birthTime);
        _mumId = uint256(kitty.mumId);
        _dadId = uint256(kitty.dadId);
        _generation = uint256(kitty.generation);
        _owner = ownerOf(_kittyId);

    }

    Kitty[] kitties;

    mapping(uint => address) public kittyIndexToOwner;
    mapping (address => uint) ownershipTokenCount;
    mapping(uint => address) kittyIndexToApproved;
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    function balanceOf(address owner) external override view returns (uint256 balance) {
        return ownershipTokenCount[owner];
    }

    function totalSupply() external override view returns (uint256 total) {
        return kitties.length;
    }

    function name() public view virtual override returns (string memory) {
        return tokenName;
    }

    function symbol() public view virtual override returns (string memory) {
        return tokenSymbol;
    }

    function ownerOf(uint256 tokenId) public override view returns (address owner) {
        require(tokenId <= kitties.length, "Token Does Not Exist");
        return kittyIndexToOwner[tokenId];
    }

    function transfer(address to, uint256 tokenId) external override {
        require(to != address(0));
        require(to != address(this));
        require(kittyIndexToOwner[tokenId] == msg.sender);
        _transfer(msg.sender, to, tokenId);
    }

    function _transfer(address from, address to, uint256 tokenId) internal {

        if(from != address(0)) {
            ownershipTokenCount[msg.sender] -= 1;
            delete kittyIndexToApproved[tokenId];
        }

        ownershipTokenCount[to] += 1;
        kittyIndexToOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }


    function approve(address _to, uint256 _tokenId) external override {
        require(kittyIndexToOwner[_tokenId] == msg.sender);
        _approve(_to, _tokenId);
        emit Approval(msg.sender, _to, _tokenId);
    }

    function _approve(address _to, uint256 _tokenId) internal {
        kittyIndexToApproved[_tokenId] = _to;
    }

    function setApprovalForAll(address _operator, bool _approved) external override {
        require (_operator != msg.sender);
        _setApprovalForAll(_operator, _approved);
        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    function _setApprovalForAll(address _operator, bool _approved) internal {
        _operatorApprovals[msg.sender][_operator] = _approved;
    }

    function getApproved(uint256 _tokenId) external override view returns (address) {
        require (_tokenId < kitties.length); // Token Must Exist
        return kittyIndexToApproved[_tokenId];
    }

    function isApprovedForAll(address _owner, address _operator) public override view returns (bool) {
        return _operatorApprovals[_owner][_operator];
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) public override {
        if(_from != msg.sender && ownerOf(_tokenId) != msg.sender) {
            require(_approvedFor(msg.sender, _tokenId) || isApprovedForAll(_from, msg.sender) == true);
        }
        require(_tokenId < kitties.length);
        require(_to != address(0));
        _transfer(_from, _to, _tokenId);
    }

    function _approvedFor(address _claimant, uint _tokenId) internal view returns (bool) {
        return kittyIndexToApproved[_tokenId] == _claimant;
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external override {
        transferFrom(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, _data));
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external override {
        transferFrom(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, ""));
    }

    function _safeTransfer(address _from, address _to, uint _tokenId, bytes memory _data) internal {
        _transfer(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, _data));
    }

    function _checkERC721Support(address _from, address _to, uint _tokenId, bytes memory _data) internal returns (bool) {
        if(!_isContract(_to)) {
            return true;
        }
        
        // Call onERC721Received in the _to contract
        bytes4 returnData = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);

        // Check return Value
        return returnData == MAGIC_ERC721_RECEIVED;
    }

    function _isContract(address _to) view internal returns (bool) {
        uint32 size;
        assembly{
            size := extcodesize(_to)
        }
        return size > 0;
    }

    function breed(uint _dadId, uint _mumId) public returns (uint) {
        // Check Ownership
        require (ownerOf(_dadId) == msg.sender, "The Sender Does Not Own The Dad");
        require (ownerOf(_mumId) == msg.sender, "The Sender Does Not Own The Mum");

        // Figure out Generation
        Kitty memory dad = kitties[_dadId];
        Kitty memory mum = kitties[_mumId];

        uint16 dadGeneration = dad.generation;
        uint16 mumGeneration = mum.generation;

        uint newGeneration = _mixGeneration(uint256(dadGeneration), uint256(mumGeneration));

        uint16 dadDna = dad.genes;
        uint16 mumDna = mum.genes;

        uint newDna = _mixDna(dadDna, mumDna);

        uint mintedCat = _createKitty(_mumId, _dadId, newGeneration, newDna, msg.sender);
        return mintedCat;
    }

    function _mixGeneration(uint _dadGeneration, uint _mumGeneration) internal pure returns (uint) {
        uint mixedGeneration = (_dadGeneration + _mumGeneration) / 2;
        require (mixedGeneration > 0);
        return mixedGeneration;
    }

    function _mixDna(uint _dadDna, uint _mumDna) internal pure returns (uint) {

        // daddna: 11 22 33 44 55 66 77 88
        // mumdna: 88 77 66 55 44 33 22 11

        uint firstHalf = _dadDna / 100000000; // 11 22 33 44
        uint secondHalf = _mumDna % 100000000; // 44 33 22 11

        uint extendedDna = firstHalf * 100000000; // 11 22 33 44 00 00 00 00

        uint finalDna = extendedDna + secondHalf; // 11 22 33 44 44 33 22 11
        return finalDna;
    }
}
1 Like

Very good @jak I notice that you learn and develop so fast! Good job!

1 Like

Hey, thanks for the kind words!

I’m more comfortable with react so doing this project in jquery has been ace.

And have been using hardhat instead of truffle so it’s been harder to cheat there, but I’m struggling with lots of errors to do with the RPC filter in where it says things like:

Errors encountered in param 0: Invalid value "0x0c" supplied to : RpcFilterRequest/fromBlock: (QUANTITY | "earliest" | "latest" | "pending") | undefined/0: QUANTITY, Invalid value "0x0c" supplied to : RpcFilterRequest/fromBlock: (QUANTITY | "earliest" | "latest" | "pending") | undefined/1: "earliest" | "latest" | "pending"

Which I manage to fix, and then when I come back to it, it broken again gaagghh :face_with_symbols_over_mouth:

But this has been a fun project!!
Was hoping to finish it within a week but I’m pushing on Sunday now and still a fair bit to get done.

    function breed(uint _momId, uint _dadId) public returns(uint newKittyId) {
        require(tokenOwner[_momId] == msg.sender && tokenOwner[_dadId] == msg.sender, "Should own both kitties before breeding.");

        uint newDna = _mixDna(kitties[_momId].dna, kitties[_dadId].dna);
        uint newGen = _calcGen(kitties[_momId].generation, kitties[_dadId].generation);
        
        newKittyId = _createKitty(_momId, _dadId, newGen, newDna, msg.sender);
    }

    function _mixDna(uint _momDna, uint _dadDna) internal pure returns(uint newDna) {
        uint newDnaFirstHalf = _momDna / 100000000;
        uint newDnaSecondHalf = _dadDna % 100000000;

        newDna = newDnaFirstHalf * 100000000;
        newDna = newDna + newDnaSecondHalf;
    }

    function _calcGen(uint _momGen, uint _dadGen) internal pure returns(uint newGen) {
        if (_momGen <= _dadGen) {
            newGen = _dadGen + 1;
        }          
        else {
            newGen = _momGen + 1;
        }
    }
1 Like
breed function
    function breed(uint256 _dadId, uint256 _momId) public returns (uint256) {
        
        //check ownership
        //figure out the generation of the fish
        //create a new fish with new dna, give it to msg.sender
        require(msg.sender == ownerToken[_dadId] && msg.sender == ownerToken[_momId],
        "You must own both the sire and mother to breed");

        uint256 _dadGen = fishies[_dadId].generation;
        uint256 _momGen = fishies[_momId].generation;
        uint256 _childGen = 0;

        if(_dadGen == _momGen && _dadGen < 1) {
            _childGen = 1;
        }
        else {
            if(_dadGen > _momGen) {
                _childGen = _dadGen + 1;
            }
            else {
                _childGen = _momGen + 1;
            }
        }

        uint256 _dadGenes = fishies[_dadId].genes;
        uint256 _momGenes = fishies[_momId].genes;
        uint256 newDna = _mixDna(_dadGenes, _momGenes);

        return _createFishy(_momId, _dadId, _childGen, newDna, msg.sender);
    }
_mixDna function
    function _mixDna(uint256 _dadDna, uint256 _momDna) internal pure returns (uint256) {
        //dadDna: 11 22 33 44 55 66 77 88
        //momDna: 88 77 66 55 44 33 22 11
        uint256 _firstDadHalf = (_dadDna / 100000000);  //11223344
        uint256 _secondMomHalf = (_momDna % 100000000); //44332211
        uint256 _babyDna = ((_firstDadHalf * 100000000) + _secondMomHalf); 

        return _babyDna;

        /* NOTE - An advanced mixing option would have the ability to evaluate 
        each 2-digit section, and determine which parent to utilize for that
        section of child dna */
        //Have a loop that iterates to pull each section
        //Use a 'random' function to do a "coin-flip" and pick a parent dna section
        //With each section assigned, run another loop which brings all the sections together
    }

Regarding the generation of the Kitty. I added an additional constraint that only same generation of kitty can breed.
Code:

function breedKitty(uint256 _dadId, uint256 _momId) public returns (uint256) {
    require(_exists[_dadId] && _exists[_momId], "NFT does not exists!");
    require(owners[_dadId] == msg.sender && owners[_momId] == msg.sender, "NFT does not belong to the address!");
    require(kitties[_dadId].generation == kitties[_momId].generation, "Generation must match to breed!");
    uint256 newDna = _mixDna(kitties[_dadId].dna, kitties[_momDna].dna);
    uint256 gen = kitties[_dadId].generation.add(1);
    return _createKitty(newDna, _momId, _dadId, gen, msg.sender);
}

function _mixDna(uint256 _dadDna, uint256 _momDna) public return (uint256) {
    uint256 dadPart = _dadDna/10**8;
    uint256 momPart = _momDna % 10**8;

    uint256 newDna = dadPart * 10**8;
    newDna = newDna + momPart;
    return newDna;
}
2 Likes

Hi, this is my solution:

function breed(uint256 mumId_, uint256 dadId_)
        external
        returns (uint256 _newKittenId)
    {
        (, , , , uint256 _dadGeneration, uint256 _dadDNA, ) = getKitty(dadId_);
        (, , , , uint256 _mumGeneration, uint256 _mumDNA, ) = getKitty(mumId_);
        require(
            (_owns(msg.sender, dadId_) && _owns(msg.sender, mumId_)),
            "Kitties: Only owner of both parent kitties can use this function to breed new kitties"
        );
        uint256 _newKittyGene = _mixDNA(_dadDNA, _mumDNA);
        uint256 _generation = _dadGeneration < _mumGeneration
            ? _mumGeneration
            : _dadGeneration;
        _newKittenId = _createKitty(
            mumId_,
            dadId_,
            _generation,
            _newKittyGene,
            msg.sender
        );
    }
function _mixDNA(uint256 dadDNA_, uint256 mumDNA_)
        internal
        pure
        returns (uint256 _newDNA)
    {
        uint256 _newDNAPartOne = dadDNA_ / (10 ^ 8);
        uint256 _newDNAPartTwo = mumDNA_ % (10 ^ 8);
        _newDNA = _newDNAPartOne * (10 ^ 8) + _newDNAPartTwo;
    }
1 Like

Here is my solution: :slight_smile:

    function breed(uint256 _dadId, uint256 _mumId) external returns(uint256) {
        require(kittyToOwner[_dadId] == msg.sender, "Both paretns must be yours!");
        require(kittyToOwner[_mumId] == msg.sender, "Both paretns must be yours!");
        
        ( uint256 mumGenes,,,,uint256 mumGeneration, ) = getKitty(_mumId);
        ( uint256 dadGenes,,,,uint256 dadGeneration, ) = getKitty(_dadId);

        uint256 newDna = _mixDna(dadGenes, mumGenes);
        // calculate genereation (takes the heighest gen + 1 --> dad gen: 1, mum gen: 4, kid gen: 5):
        uint256 gen = mumGeneration >= dadGeneration ? mumGeneration+1 : dadGeneration+1;

        return _createKitty(_mumId, _dadId, gen, newDna, msg.sender);
    }
1 Like

DNA Mixing Assignment

breed
function breed(uint256 _dadId, uint256 _momId) public onlyOwner returns (uint256) {    
        //check ownership
        //figure out the generation of the fish
        //create a new fish with new dna, give it to msg.sender
        require(msg.sender == ownerToken[_dadId] && msg.sender == ownerToken[_momId],
        "You must own both parents to breed");

        uint256 _dadGen = fishies[_dadId].generation;
        uint256 _momGen = fishies[_momId].generation;
        uint256 _childGen = 0;

        if(_dadGen == _momGen && _dadGen < 1) {
            _childGen = 1;
        }
        else {
            if(_dadGen > _momGen) {
                _childGen = _dadGen + 1;
            }
            else {
                _childGen = _momGen + 1;
            }
        }

        uint256 _dadGenes = fishies[_dadId].genes;
        uint256 _momGenes = fishies[_momId].genes;
        uint256 newDna = _mixDna(_dadGenes, _momGenes);

        return _createFishy(_momId, _dadId, _childGen, newDna, msg.sender);
    }
_mixDna
   function _mixDna(uint256 _dadDna, uint256 _momDna) internal pure returns (uint256) {
        //dadDna: 11 22 33 44 55 66 77 88
        //momDna: 88 77 66 55 44 33 22 11
        uint256 _firstDadHalf = (_dadDna / 100000000);  //11223344
        uint256 _secondMomHalf = (_momDna % 100000000); //44332211
        uint256 _babyDna = ((_firstDadHalf * 100000000) + _secondMomHalf); 

        return _babyDna;

        /* NOTE - An advanced mixing option would have the ability to evaluate 
        each section, and determine which parent to utilize for that
        section of child dna */
        //Have a loop that iterates to pull each section
        //Use a 'random' function to do a "coin-flip" and pick a parent dna section
        //With each section assigned, run another loop which brings all the sections together
    }
1 Like

Ive made it all in a single function. I decided that the generation will be mums generation +1

 function Breed(uint32 mumId, uint32 dadId)public returns(uint256){
        require(_isApprovedOrOwner(_msgSender(), mumId), "ERC721: transfer caller is not owner nor approved");
        require(_isApprovedOrOwner(_msgSender(), dadId), "ERC721: transfer caller is not owner nor approved");
        uint dadGenes = kitties[dadId].genes;
        uint mumGenes = kitties[mumId].genes;

        uint16 kittyGeneration =kitties[mumId].generation+1;
        uint _fromDad = dadGenes/100000000;
        uint fromDad = _fromDad*100000000;
        uint fromMum = mumGenes % 100000000;
        uint kittyGenes = fromDad+fromMum;
        return kittyGenes;
        return _createNewKitty(kittyGenes, mumId, dadId, kittyGeneration, msg.sender);
    }
2 Likes