Assignment - DNA Mixing

    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

My solution…

  function breed(uint256 _dadId, uint256 _mumId) public returns (uint256) {
    require(_owns(msg.sender, _dadId), "Dad Id is not owned by you");
    require(_owns(msg.sender, _mumId), "Mum Id is not owned by you");

    (uint256 dadDna,,,,uint256 dadGeneration) = getKitty(_dadId); // only necessary values retrieved
    (uint256 mumDna,,,,uint256 mumGeneration) = getKitty(_mumId); // => Dna and generation

    uint256 newDna = _mixDna(dadDna, mumDna);

    // new generation: highest one + 1
    uint256 kittyGen = (dadGeneration < mumGeneration) ? mumGeneration + 1 : dadGeneration + 1;

    _createKitty(_mumId, _dadId, kittyGen, newDna, msg.sender);
  }

 function _mixDna(uint256 _dadDna, uint256 _mumDna) internal pure returns (uint256) {
    uint256 leftHalfDad = _dadDna /  100000000;
    uint256 rightHalfMum = _mumDna % 100000000;
    return leftHalfDad * 100000000 + rightHalfMum;
  }
2 Likes
function breed(uint256 _dadId, uint256 _momId) public returns (uint256) {
        //Check ownership
        require(_owns(msg.sender,_dadId) && _owns(msg.sender,_momId), "Both cats have to be owned by you to enable breeding");
        //Figure out the calculation for the new cat Generation (now that we have the DNA).
        ( uint256 _dadDNA,,,, uint256 dadGeneration ) = getKitty(_dadId);
        ( uint256 _momDNA,,,, uint256 momGeneration ) = getKitty(_momId);

        uint256 newCatDna = _mixDna(_dadDNA, _momDNA);

        //Create new cat w/ new properties & give it to msg.sender
        uint256 kidGeneration = 0;
        if (dadGeneration < momGeneration) {
            kidGeneration = momGeneration + 1;
            kidGeneration / 2;
        }
        else if (dadGeneration > momGeneration) {
            kidGeneration = dadGeneration + 1;
            kidGeneration / 2;
        }
        else {kidGeneration = momGeneration + 1;
        }

        return _createKitty(_momId, _dadId, kidGeneration, newCatDna, msg.sender); 
        
    }
function _mixDna(uint256 _dadDna, uint256 _momDna) internal returns (uint256) {
        uint256 firstHalf = _dadDna / 100000000;
        uint256 secondHalf = _momDna % 100000000;

        uint256 newDNA = firstHalf * 100000000;
        newDNA = newDNA + secondHalf;

        return newDNA;
    }
1 Like

**mix dna **

function _mixDna(uint256 _dadDna, uint256 _mumDna)
        internal
        pure
        returns (uint256)
    {
        //dadDna: 11 22 33 44 55 66 77 88
        //mumDna: 88 77 66 55 44 33 22 11
        uint256 dadSide = _dadDna / 100000000;
        uint256 mumSide = _mumDna % 100000000;
        uint256 newDna = (dadSide * 100000000) + mumSide;
        return newDna;
    }

breed

function breed(uint256 _dadId, uint256 _mumId) public returns (uint256) {
        //check ownership
        //check you got the dna
        //figure out the generation
        //create a new cat with new properties, give it to msg.sender
        require(
            _owns(msg.sender, _dadId) && _owns(msg.sender, _mumId),
            "You must own both cats in order to breed"
        );
        uint256 newDna = _mixDna(_dadId, _mumId);
        uint256 kidGen = 0;
        uint256 mumGen = kitties[_mumId].generation;
        uint256 dadGen = kitties[_dadId].generation;
        if (dadGen < mumGen) {
            kidGen = mumGen + 1;
            kidGen /= 2;
        } else if (dadGen > mumGen) {
            kidGen = dadGen + 1;
            kidGen /= 2;
        } else {
            kidGen = mumGen = 1;
        }
        _createKitty(newDna, _mumId, _dadId, kidGen, msg.sender);
        return newDna;
    }
    }```
1 Like

Breed

function breed(uint256 _dadId, uint256 _mumId) public returns (uint256){
        //check ownership
        //You got the DNA
        //figure out the Generation 
        //Creat a new cat with the new properties, give it to the msg.sender
        require(_owns(msg.sender, _dadId), "The user doesn't own the token");
        require(_owns(msg.sender, _mumId), "The user doesn't own the token");

        ( uint256 dadDna,,,,uint256 DadGeneration ) = getKitty(_dadId);
        ( uint256 mumDna,,,,uint256 MumGeneration ) = getKitty(_mumId);
        
        uint256 newDna = _mixDna(dadDna, mumDna);

        uint256 kidGen = 0;
        if(DadGeneration < MumGeneration){
            kidGen = MumGeneration + 1;
            kidGen /=2
        
        }else if (DadGeneration > MumGeneration) {
            kidGen = DadGeneration + 1;
            KidGen /= 2;
        }else{
            KidGen = MumGeneration + 1;
        }

        _createKitty(_mumId, _dadId, kidGen, newDna, msg.sender);
    }

Mix DNA

function _mixDna(uint256 _dadDna, uint256 _mumDna) internal returns (uint256) {
        //dadDna: 11 22 33 44 55 66 77 88
        //mumDna: 88 77 66 55 44 33 22 11 

        uint256 firstHalf = _dadDna / 100000000; // 11223344
        uint256 secondHalf = _mumDna % 100000000; // 44332211 

        uint256 newDna = firstHalf * 100000000;
        newDna = newDna + secondHalf; // 1122334444332211 

        return newDna;
        

    }
2 Likes

breed function:

 function breed(uint _dadId, uint _momId) external returns(uint) {
        require(_owns(msg.sender, _dadId) && _owns(msg.sender, _momId),"You dont own these cats");
        
        uint dadGeneration = kitties[_dadId].generation;
        uint momGeneration = kitties[_momId].generation;
        uint newGeneration;
        if(dadGeneration > momGeneration) {
            newGeneration = dadGeneration++;
        }
        else {
            newGeneration = momGeneration++;
        }
        
        uint dadDna = kitties[_dadId].genes;
        uint momDna = kitties[_momId].genes;
        uint newDna = _mixDna(dadDna, momDna);
        
        _createKitty(newDna, _momId, _dadId, newGeneration, msg.sender);

        return newDna;
    }

_mixDna function:

 function _mixDna(uint _dadDna, uint _momDna) internal pure returns(uint) {
        uint firstHalf= _dadDna / 100000000;
        uint secondHalf= _momDna % 100000000;
        uint newDna = (firstHalf * 100000000) + secondHalf;
        return newDna;
    }
2 Likes
function breed(uint256 _dadId, uint256 _momId) public returns(uint256){
    require(_owns(msg.sender,_dadId));
    require(_owns(msg.sender,_momId));

    {uint256 dadDNA,,,, uint256 dadGen} = getKitty(_dadId);
    {uint256 momDNA,,,, uint256 momGen} = getKitty(_momId);

    uint256 newDNA = _mixDNA(dadDNA,momDNA);
    uint256 childGen = 0;

    if(dadGen < momGen){
       childGen = momGen++;
    }else if(dadGen > momGen){
       childGen = dadGen++;
    }else{ 
       childGen = momGen++;
    }
    
    _createKitty(_momId, _dadId, childGen, newDNA, msg.sender);

}
2 Likes
    //breeding new Bears
    function breed(uint256 dadId, uint256 mumId) public returns (uint256) {
        //check ownership
        require(_owns(msg.sender, dadId) || getApproved(dadId) == msg.sender, "msg.sender is not the token owner of the father!");
        require(_owns(msg.sender, mumId) || getApproved(mumId) == msg.sender, "msg.sender is not the token owner of the mother!");

        //new generation is determined
        uint256 dadGen = bears[dadId].generation;
        uint256 mumGen = bears[mumId].generation;
        uint256 newGen;

        if(dadGen > mumGen) {
            newGen = dadGen++;
        }
        else {
            newGen = mumGen++;
        }

        //DNA String is made
        uint256 dadDna = bears[dadId].genes;
        uint256 mumDna = bears[mumId].genes;

        uint256 newDna = _mixDna(dadDna, mumDna);

        //create new bear
        _createBear(newDna, mumId, dadId, newGen, msg.sender);
    }

    //Dna of parent bears gets mixed
    function _mixDna(uint256 _dadDna, uint256 _mumDna) internal returns (uint256) {
        uint256 firstDnaHalf = _dadDna / 100000000;
        uint256 secondDnaHalf = _mumDna % 100000000;

        uint256 newDna = firstDnaHalf * 100000000;
        newDna = newDna + secondDnaHalf;
        return newDna;
    }

Hi All, :snowman:

This is the breed function:

    function breed(uint32 _mumId, uint32 _dadId) external {
        _validateToken(_mumId);
        _validateToken(_dadId);

        // Check ownership
        require(tokenowners[_mumId] == msg.sender, "Caller does not own mum id");
        require(tokenowners[_dadId] == msg.sender, "Caller does not own dad id");
        
        // Calculate the new dna
        Kitty storage mum = kitties[_mumId];
        Kitty storage dad = kitties[_dadId];

        uint256 newGenes = _mixGenes(mum.genes, dad.genes);

        // mint the new kitty
        _createKitty(_mumId, _dadId, mum.generation+1, newGenes, msg.sender);

    }

and a very basic _mixGenes function:

    function _mixGenes(uint256 mumDna, uint256 dadDna) private pure returns (uint256 childDna){

        childDna = (mumDna / 1000000)*1000000 + dadDna % 1000000;
    }

Unit tests:

4_breed_test.js
const Kitty = artifacts.require('Kittycontract');
const truffleAssert = require('truffle-assertions');


contract("Test breed function", accounts =>{

    let kitty
    let mumId
    let dadId
    let childId

    beforeEach(async()=>{
        kitty = await Kitty.new()

        let mum = await kitty.createKittyGen0(10203040123501)
        truffleAssert.eventEmitted(mum, 'Birth', event=>{
            mumId = event.tokenId
            return true
        })


        let dad = await kitty.createKittyGen0(50708090234602)
        truffleAssert.eventEmitted(dad, 'Birth', event=>{
            dadId = event.tokenId
            return true
        })        


        let child = await kitty.breed(mumId, dadId)
        truffleAssert.eventEmitted(child, 'Birth', event=>{
            childId = event.tokenId
            return true
        })


    })

    afterEach(async()=>{
        kitty = 0
        mumId = 0
        dadId = 0
        childId = 0
    })

    it("caller should own a new cat with higher generation", async()=>{

        var childOwner = await kitty.ownerOf(childId)
        assert(childOwner == accounts[0], "Account 0 should own the new cat")

        var childKitty = await kitty.getKitty(childId)

        assert(childKitty.generation == 1, "Wrong generation")
        assert(childKitty.mumId == mumId.toNumber(), "wrong mum")
        assert(childKitty.dadId == dadId.toNumber(), "wrong dad")
    })


    it("new cat genes should be properly mixed", async()=>{

        var childKitty = await kitty.getKitty(childId)

        assert(childKitty.genes == 10203040234602, "Wrong mixed genes")        
    })


    it("should fail if caller does not own any of the cats", async()=>{
        
        // Does not own any
        await truffleAssert.reverts(
            kitty.breed(mumId, dadId, {from: accounts[1]})
        )

        
    })

    it("should fail if caller owns 1 cat out of 2", async()=>{
        await kitty.transfer(accounts[1], mumId)

        // Owns one
        await truffleAssert.reverts(
            kitty.breed(mumId, dadId, {from: accounts[1]})
        )
    })

    it("should pass if caller owns both cats", async()=>{
        await kitty.transfer(accounts[1], mumId)
        await kitty.transfer(accounts[1], dadId)

        // Owns one
        await truffleAssert.passes(
            kitty.breed(mumId, dadId, {from: accounts[1]})
        )

    })

    
}
)


Github:
https://github.com/CodingInLondon/moralisacademy-nftmarketplace/tree/b9220275cfe762edebdb277819cd50a7d34dd4fc

Kittycontract

	uint256 private constant secondsPerGeneration = 1000000;
	uint256[] public cooldowns = [
		1 minutes, // for generation 0 cats
		2 minutes, // for generation 1 cats
		3 minutes, // for generation 2 cats
		4 minutes  // for generation 3+ cats
	];

	function breed(uint256 _dadId, uint256 _mumId) public returns(uint256) {
		// Check ownership of both parents
		require(_owns(payable(msg.sender), _dadId), "Caller does not own the father");
		require(_owns(payable(msg.sender), _mumId), "Caller does not own the mother");

		// Get parent DNA
		(uint256 dadGenes, , , , uint16 dadGeneration) = getKitty(uint32(_dadId));
		(uint256 mumGenes, , , , uint16 mumGeneration) = getKitty(uint32(_mumId));
		// Generation 
		uint16 newGeneration = dadGeneration > mumGeneration ? dadGeneration : mumGeneration;

		// create and return new cat  to msg.sender
		uint256 newDna = _mixDna(dadGenes, mumGenes);
		return newDna;
	}
	function _canBreed(uint256 _kittyId) internal view returns (bool) {
		Kitty storage kitty = kitties[_kittyId];
		uint256 secondsSinceBirth = uint256(block.timestamp).sub(kitty.birthTime);
		uint256 cooldown = secondsPerGeneration.mul(kitty.generation.add(1));

		return secondsSinceBirth >= cooldown && kitty.cooldownEndBlock <= uint64(block.number);
	}
	function _mixDna(uint256 _dadDna, uint256 _mumDna) internal returns(uint256) {
		// dadDna = 11 22 33 44 55 66 77 88
		// mumDna = 88 77 66 55 44 33 22 11
		uint256 multiplicator = 100000000; 	// 100 000 000
		uint256 firstHalf = _dadDna / multiplicator;	// 11 22 33 44
		uint256 secondHalf = _mumDna % multiplicator;	// 44 33 22 11

		uint256 newDna = firstHalf * multiplicator;		// 11 22 33 44 00 000 000
		newDna = newDna + secondHalf;					// 11 22 33 44 44 33 22 11

		return newDna;
	}
function createKitty(
		uint256 _mumId,
		uint256 _dadId,
		uint256 _generation,
		uint256 _genes,
		address _owner
	) private returns (uint256) {
		uint256 cooldownEndBlock = 0; // set initial cooldown end block to 0
		if (_generation == 0) {
			cooldownEndBlock = block.number + (1 days / cooldowns[0]);
		} else {
			uint256 lastGenCooldownEndBlock = kitties[kitties.length - 1].cooldownEndBlock;
			cooldownEndBlock = lastGenCooldownEndBlock + (1 days / cooldowns[_generation]);
		}

		Kitty memory _kitty = Kitty({
			genes: _genes,
			birthTime: uint64(block.timestamp),
			mumId: uint32(_mumId),
			dadId: uint32(_dadId),
			generation: uint16(_generation),
        	cooldownEndBlock: uint64(cooldownEndBlock)
		});

		kitties.push(_kitty);
		uint256 newKittenId = kitties.length - 1;
		emit Birth(_owner, newKittenId, _mumId, _dadId, _genes);
		_transfer(address(0), _owner, newKittenId);

		return newKittenId;
	}