Assignment - More Randomness

hey @thecil, thanks a lot.
Yeah… I didn’t heed that one. But still, why this isn’t a problem with earlier compilers.
I just made a little change to make it work.

for(uint i = 1 ; i <= 128 ; i = i*2){
       if(random & i != 0){
         geneArray[index] = mumDNA % 100;
       }
       else{
         geneArray[index] = dadDNA % 100;

       }
       mumDNA = mumDNA / 100;
       dadDNA = dadDNA / 100;
       
       if(i != 128){index = index-1;}
       
      }
1 Like

Hey @tanu_g, I was having the same problem. How did you come up with that?
Also, when I transact again with the same deployment in Remix, the results keeps getting longer after the first time, like this: 112033448060779922304002607080
It should not grow - does this happen on yours?

1 Like

I was having the same problem as @tanu_g, Remix v 0.8.0 resulting in error, "needs to be a payable transaction…
I tried Tanu’s fix and that worked.
I tried yours @thecil, setting it 64 instead of 128 and that worked as well !

1 Like

hey @bjamRez, as in the last for loop we’re using the condition something like below, where we don’t want to append 00 in the last iteration

if(i != 7){newGene = newGene * 100;} 

I got the idea from this one as we don’t want i to become negative in the last iteration.

Nope…It’s didn’t happen on my machine.

1 Like

Here is my code. I added what I think is some more randomization.

 uint256 newGene;
    
    function mixDnaMoreRand(uint256 _dadDna, uint256 _mumDna) public returns(uint256) {
        
      uint256 [8] memory geneArray;
      uint256 index = 7;
      uint8 random = uint8(block.timestamp % 255);
      uint256 i = 0;
      
      // dad 1020304050607080  
      // mum 1122334455667788
      
      for(i = 1; i <= 128; i=i*2){

          if(random & i != 0){
              geneArray[index] = uint8(_mumDna % 100);
          } else {
              geneArray[index] = uint8(_dadDna % 100);
          }
          _mumDna /= 100;
          _dadDna /= 100;

        if(i != 128){index = index-1;}
      }
      
//extra random treatment

       uint8 newPairIndex = 4; // index

      for (i = 1; i <= 64; i=i*2 ) {
        
        geneArray[newPairIndex] = random % 99;

      }
      

      for (i = 0 ; i < 8; i++ ){
        newGene += geneArray[i];
        if(i != 7){
            newGene *= 100;
        }
        
      }
      
      return newGene;
    }

I’m finally almost up to date with the front-end, so I got back into this DNA mixing thing. I’ve added a 15% chance to get a complete random mutation for each gene. Working nicely and without bug on remix, so pretty happy!
Here is my code:

// Mix DNA from both parents with an extra 15% chance mutation per gene
    function _mixDna(uint256 _dadDna, uint256 _mumDna)
        private
        view
        returns (uint256)
    {
        uint8 random = uint8(block.timestamp % 255); // binary between 00000000-11111111
        uint8 index = 7;
        uint16 i;
        uint256[8] memory geneArray;
        uint256 newGene;

        for (i = 1; i <= 128; i = i * 2) {
            uint256 randomMutation = randomPercent();

            // 15% mutation chances
            if (randomMutation < 85) {
                if (random & i != 0) {
                    geneArray[index] = uint8(_mumDna % 100);
                } else {
                    geneArray[index] = uint8(_dadDna % 100);
                }
            } else {
                if (index == 5 || index == 7) {
                    geneArray[index] = uint8(randomCattribute());
                } else {
                    geneArray[index] = uint8(color10to98(randomPercent()));
                }
            }

            _mumDna = _mumDna / 100;
            _dadDna = _dadDna / 100;

            if (i != 128) {
                index--;
            }
        }

        for (i = 0; i < 8; i++) {
            newGene += geneArray[i];
            if (i != 7) {
                newGene *= 100;
            }
        }

        return newGene;
    }

    // Random number between 00 and 98 = percent %
    function randomPercent() private view returns (uint256) {
        uint256 percent = uint256(
            keccak256(abi.encodePacked(block.timestamp, msg.sender, gasleft()))
        ) % 98;
        return percent;
    }

    // return a random number between 10 and 98 for the random color
    function color10to98(uint256 _percent) private view returns (uint256) {
        uint256 result = _percent;
        while (result < 10) {
            result = randomPercent();
        }
        return result;
    }

    // Return a random double digits number [from 1 to 6 , from 1 to 5] to match cattributes
    function randomCattribute() private view returns (uint256 result) {
        uint256 randomCattribute1 = color1to6(randomPercent());
        uint256 randomCattribute2 = color1to5(randomPercent());

        return randomCattribute1 * 10 + randomCattribute2;
    }

    function color1to6(uint256 _percent) private view returns (uint256) {
        uint256 result = _percent % 10;
        while (result == 0 || result > 6) {
            result = randomPercent() % 10;
        }
        return result;
    }

    function color1to5(uint256 _percent) private view returns (uint256) {
        uint256 result = _percent % 10;
        while (result == 0 || result > 5) {
            result = randomPercent() % 10;
        }
        return result;
    }
2 Likes

I’ve never used HTML or CSS until I started this course, so the front-end component of this project is really challenging for me. Can anyone recommend a favorite (free) resource for learning the basics? Just need enough to make it look decent

hey @Attiss
Here is a good page for learn HTML,CSS and other languages
https://www.w3schools.com/html/default.asp

I followed Filip’s advanced DNA mixing strategy, and added a condition before if for a bit more randomness.

Before entering the if/else statement in the first for loop, I added a modulo condition where the random number modulo over i should be less than 5 to enter into the prior if/else where it adopts exactly the DNA set from either the mother of father.

But if the modulo was 5 or greater, it would adopt the 2 digits which sit as the average between the mother and father DNA.
So, it goes ((_mumDna + dadDna) / 2) % 100 and the kid takes that spliced DNA.

So my full _mixDna function is now:

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

        uint[8] memory geneArray;

        uint8 random = uint8(block.timestamp % 255); // Result is between 0 - 255, or 00000000 - 11111111 e.g. 11001011 => 0 we take genes from dad and 1 we take gene from mum

        uint i = 1; // Lets Say that random = 11001011
        uint index = 7;

        for (i = 1; i <= 128; i*=2) {
            if(random % i < 5) {
                if(random & i != 0) {
                    geneArray[index] = uint8(_mumDna % 100); // Gets the last 2 digits
                } else {
                    geneArray[index] = uint8(_dadDna % 100);
                }
            } else {
                geneArray[index] = uint8(((_mumDna + _dadDna) / 2) % 100);
            }

            // And Then remove the last two digits from the dna
            _mumDna /= 100;
            _dadDna /= 100;
            index -= 1;            
        }

        uint newGene;

        for (i = 0; i < 8; i++) {
            // e.g. [11, 22, 33, 44, 55, 66, 77, 88]
            newGene += geneArray[i];
            // 11
            if (i != 7) {
                newGene *= 100;
                // 1100 => such that when you enter the loop next time, you ADD the next 2 numbers, so => 1122
            }

        }
        return newGene;
    }

I removed most of the comments from the function explaining what’s going on because it looks supremely gross.
All about the aesthetiqs :sunglasses:

1 Like

Adding a variation for the simple algorithm, alternating mixing of the DNA between the mom and dad:

    function _mixDna(uint _momDna, uint _dadDna) internal pure returns(uint newDna) {
        uint newDna1stQuarter = _momDna / 1000000000000;
        uint newDna2ndQuarter = (_dadDna / 100000000) % 10000;
        uint newDna3rdQuarter = (_momDna % 100000000) / 10000;
        uint newDna4thQuarter = _dadDna % 10000;

        newDna = (newDna1stQuarter * 1000000000000) + (newDna2ndQuarter * 100000000) + (newDna3rdQuarter * 10000) + newDna4thQuarter;
    }
1 Like

Using math rather than storing DNA in an array to generate new DNA string. Not sure if that’s a good move, but it works. In testing I eventually got a duplicate cat, so considering if it’s worth it to add logic to make sure every cat’s dna is actually unique.

  function mixDna(uint256 matronDna, uint256 sireDna) internal view returns(uint256){
    uint256 newGenes;
    uint256 placeMaker = 1;
    uint256 rando1 = uint256(keccak256(abi.encodePacked(matronDna, block.timestamp)));
    uint256 rando2 = uint256(keccak256(abi.encodePacked(sireDna, block.timestamp)));
    uint256 rando3 = uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp)));
    for(uint256 i = 0; i < 10; i++){
      if(i == 0 || i == 1 || i == 4 || i == 5){
        if(rando1 % 2 == 0){
          newGenes = newGenes + ((matronDna % 10) * placeMaker);
        }
        else if(rando1 % 2 != 0){
          newGenes = newGenes + ((sireDna % 10) * placeMaker);
        }
        else if(rando3 % 10 == 7) {
          newGenes = newGenes + ((matronDna + sireDna % 10) * placeMaker);
        }
        matronDna /= 10;
        sireDna /= 10;
        placeMaker *= 10;
      }
      else {
        if(rando2 % 2 == 0){
          newGenes = newGenes + ((sireDna % 100) * placeMaker);
        }
        else if(rando2 % 2 != 0){
          newGenes = newGenes + ((matronDna % 100) * placeMaker);
        }
        else if(rando3 % 10 == 9) {
          newGenes = newGenes + ((matronDna + sireDna % 100) * placeMaker);
        }
        matronDna /= 100;
        sireDna /= 100;
      placeMaker *= 100;
      }
      rando1 /= 10;
      rando2 /= 10;
      rando3 /= 10;
    }
    return newGenes;
  }

Hi, this is my solution for the advanced mix DNA function.

I add 2 more lines of code to randomly choose a pair of numbers and change it to another pair of random numbers which is irrelevant to the parents’ genes:

uint256 _randomIndex = uint256(block.timestamp % 8); // i = [0, 7]

_DNA[_randomIndex] = uint256(block.timestamp % 90) + 10; // _DNA[_randomIndex] = [10, 99]
function _advancedMixDNA(uint256 mumDNA_, uint256 dadDNA_)
        private
        view
        returns (uint256)
    {
        uint256 _randomNumber = uint8(block.timestamp % 255);
        uint256[8] memory _DNA;
        uint256 _dnaIndex = 8;

        for (uint256 i = 1; i <= 128; i = i * 2) {
            _dnaIndex = _dnaIndex - 1;
            if (_randomNumber & i != 0) {
                _DNA[_dnaIndex] = mumDNA_ % 100;
            } else {
                _DNA[_dnaIndex] = dadDNA_ % 100;
            }

            mumDNA_ = mumDNA_ / 100;
            dadDNA_ = dadDNA_ / 100;
        }

        uint256 _randomIndex = uint256(block.timestamp % 8); // i = [0, 7]

       _DNA[_randomIndex] = uint256(block.timestamp % 90) + 10; // _DNA[_randomIndex] = [10, 99]

        uint256 _result;

        for (uint256 i = 0; i < 8; i++) {
            _result = _result + _DNA[i];
            if (i != 7) {
                _result = _result * 100;
            }
        }
        return _result;
    }

My variation is to randomly choos between easy and advanced mixDna functions in the breed function:

    // decide pseudo random which mixDna method to use..
    uint256 newDna = ( now % 2 == 0 ) ? _mixDna1(dadDna, mumDna) : _mixDna2(dadDna, mumDna);

Both functions:

  function _mixDna1(uint256 _dadDna, uint256 _mumDna) internal pure returns (uint256) {
    uint256 leftHalfDad = _dadDna /  100000000;
    uint256 rightHalfMum = _mumDna % 100000000;
    return leftHalfDad * 100000000 + rightHalfMum;
  }

  function _mixDna2(uint256 _dadDna, uint256 _mumDna) internal view returns (uint256) {
    // mamDna, dadDna are 2x 15digits gene => 2x 8-pairs
    // generate 8bit random number -> 0 bit = take pair from dadDna, else from mumDna => new Kitten 16digits gene
    uint256[8] memory geneArray;
    //uint8 random = uint8( now % 255); // bin between 0-11111111 ex. 11001011
    uint8 random = uint8(uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty))) % 255);
    uint8 i = 1;
    uint8 bitIndex = 7; // 7..0
    for(i=1; i<=128; i*=2) { // 1 2 4 8 16 32 64 128
      geneArray[bitIndex] = (random & i == 0) ? uint8( _dadDna % 100 ) : uint8( _mumDna % 100 );
      _dadDna /= 100;
      _mumDna /= 100;
      bitIndex--;
    }

    // convert array to string of 8pair digits
    uint256 newGene = 0;
    for(i=0; i<7; i++) {
      newGene = (newGene + geneArray[i]) * 100;
    }
    newGene += geneArray[7];

    return newGene;
  }

Hello!

I chose to randomize each DNA field, using a similar mechanism. My code could probably be a bit more efficient, but for now it seems to work (only pasting the part of the contract relevant to DNA mixing):

function breedKitty(uint256 _cat1, uint256 _cat2) public {
    require(kittyIndexToOwner[_cat1] == msg.sender && kittyIndexToOwner[_cat2] == msg.sender);
    require(_cat1 != _cat2);
    uint256 dadGenes = kitties[_cat1].genes;
    uint256 momGenes = kitties[_cat2].genes;
    
    return _generateDigits(dadGenes, momGenes, _cat1, _cat2);
}

function _generateDigits(uint256 _dad, uint256 _mom, uint256 dadId, uint256 momId) internal {
        delete digitsMom;
        delete digitsDad;
        delete finalD;
        uint256 numberMom = _mom;
        uint256 numberDad = _dad;
        
        while (digitsDad.length < 6) {
            uint256 digitM = uint256(numberMom % 10);
            uint256 digitD = uint256(numberDad % 10);
            numberMom = numberMom / 10;
            numberDad = numberDad / 10;
            digitsMom.push(digitM);
            digitsDad.push(digitD);
        }
        while (digitsDad.length < 13) {
            uint256 digitM = uint256(numberMom % 100);
            uint256 digitD = uint256(numberDad % 100);
            numberMom = numberMom / 100;
            numberDad = numberDad / 100;
            digitsMom.push(digitM);
            digitsDad.push(digitD);
        }
        
        _mixDNA(dadId, momId);
        
    }

    function _mixDNA(uint256 dadId, uint256 momId) internal returns (uint256) {
        
        uint256 random = uint256(block.timestamp % 255);
        uint256 i;
        uint256 index = 12;
        
        for (i = 1; i <= 2048; i = i*2) {
            if (random & i != 0) {
                finalD.push(digitsMom[index]);
            } else {
                finalD.push(digitsDad[index]);
            }
            index = index - 1;
            
        }
        if (finalD[0] == digitsMom[digitsMom.length - 1]){
            finalD.push(digitsDad[0]);
        } else {
            finalD.push(digitsMom[0]);
        }
            uint256 newGene;
            uint256 newGeneration;
        
                for (i = 0; i < 12; i++){
                    if (i < 6){
                        newGene = newGene + finalD[i];
                        newGene = newGene * 100;
                    } if (i >= 6){
                        newGene = newGene + finalD[i];
                        newGene = newGene * 10;
                    }
                    
                }

                if (kitties[dadId].generation > kitties[momId].generation){
                    newGeneration = kitties[dadId].generation + 1;
                } else if  (kitties[dadId].generation < kitties[momId].generation){
                    newGeneration = kitties[momId].generation + 1;
                } else {
                    newGeneration = kitties[momId].generation + 1;
                }

                return _createKitty(momId, dadId, newGeneration, newGene, msg.sender);
                
        }
    

1 Like

Hello😃 I am still trying to understand the advanced DNA coding, but yikes😬 is going to take a bit longer for me, here what I have so far.

function _mixDna(uint256 _dadDna, uint256 _mumDna) public view returns (uint256) {
        uint[8] memory geneArray;

        uint8 random = uint8( block.timestamp % 255 ) ; 
        uint256 i = 1;
        uint256 index = 7;

        //MUM DNA 11 22 33 44 55 66 77 88
        //DAD DNA 88 77 66 55 44 33 22 11

        for (i = 1; i <= 128; i=i*2) {
            if(random & i != 0) {
                geneArray[index] = uint8( _mumDna % 100);
            }
            else {
                geneArray[index] = uint8(_dadDna % 100);
            }
            _mumDna = _mumDna/ 100;
            _dadDna =  _dadDna/ 100;

            if(i != 128) {index = index - 1;} 
        }
        uint256 newGene;

        for (i = 0; i <8; i++) {
            newGene = newGene + geneArray[i];
            if (i != 7) {
                   newGene = newGene * 100;
            }
            
        }
            return newGene;

    }
        
}
1 Like

_mixDna function:

function _mixDna(uint _dadDna, uint _momDna) internal view returns(uint) {
        uint[8] memory geneArray;
        uint8 random = uint8(block.timestamp % 255); //
        uint256 i = 1;
        uint256 index = 7;
        for (i = 1; i <= 128; i=i*2) {
            if(random & i !=0){
                geneArray[index] = uint8(_momDna % 100);
            }
            else{
                geneArray[index] = uint8(_momDna % 100);
            }
            _momDna = _momDna / 100;
            _dadDna = _dadDna / 100;
            index = index - 1;
        }
        
        uint256 newGene;
        for (i = 0; i < 8; i++) {
            newGene = newGene + geneArray[i];
            if(i != 7){
                newGene = newGene * 100;
            }
            
        }
        return newGene;
    }
1 Like

I chose to set up my _mixDNA function to make the third position a random number.

function _mixDNA(uint256 _dadDNA, uint256 _momDNA) internal view returns (uint256){
        uint256[8] memory geneArray;
        uint8 random = uint8(block.timestamp % 255); //0-255 binary between 00000000-11111111
        uint256 i = 1;
        uint256 index = 7;

        for(i = 1; i <= 122; i = i*2){
            if(random & i != 0){
                geneArray[index] = uint8(_momDNA % 100);}
            else{
                geneArray[index] = uint8(_dadDNA % 100);}

            _momDNA = _momDNA/100;
            _dadDNA = _dadDNA/100;
            index = index - 1;
            }
        
        uint256 newGene;

        for(i = 0; i < 8; i++){
            if(i == 2){
            newGene = newGene + randomNum();    
            }
            else{          
            newGene = newGene + geneArray[i];
            }
            }
            if(i != 7){
                newGene = newGene * 100;
            }
        return newGene;

        }

        function randomNum() internal view returns(uint256){
        uint256 randNumber = block.timestamp % 100;
        return randNumber; 
        }

Hi Devs,

Vid: Advanced DNA Coding
time: 18.16

When I try to test Filip’s code on remix, it reverts the transaction.

Is there something that I am missing in my code?

test.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

contract test {
    function _mixDna(uint256 _dadDna, uint256 _mumDna) public view returns (uint256) {
        uint256[8] memory geneArray;

        uint8 random = uint8(block.timestamp % 255); //
        uint256 i = 1;
        uint256 index = 7;

        for(i = 1; i <= 128 ; i = i * 2){
            if(random & i !=0){
                geneArray[index] = uint8(_mumDna % 100);
            }
            else{
                geneArray[index] = uint8(_dadDna % 100);
            }
            _mumDna = _mumDna / 100;
            _dadDna = _dadDna / 100;
            
            index = index - 1;
        }
        uint256 newGene;
        
        for (i = 0; i < 8; i++) {
            newGene = newGene + geneArray[i];
            if(i != 7) {
                newGene = newGene * 100;
            }

        }

        return newGene;
    }
}

thanks
Dave

Thanks for this solution!
I was having the same problem.
I tried the 64 instead of 128 which seemed to work but, it actually returned 7 pairs instead of the inputted 8 pairs.

2 Likes

You’re very welcome, @DaveRad.
All of us are learning as we go along. :slightly_smiling_face:

1 Like