diff --git a/src/game/genetics/allele.hpp b/src/game/genetics/allele.hpp index e39ed80..ef8f2ef 100644 --- a/src/game/genetics/allele.hpp +++ b/src/game/genetics/allele.hpp @@ -20,17 +20,19 @@ #ifndef ANTKEEPER_ALLELE_HPP #define ANTKEEPER_ALLELE_HPP +#include + namespace dna { /// Enumerates allele types. -enum class allele: bool +enum allele: std::uint8_t { /// Indicates an allele is recessive. - recessive = false, + recessive = 0, /// Indicates an allele is dominant. - dominant = true + dominant = 1 }; } // namespace dna diff --git a/src/game/genetics/gene.hpp b/src/game/genetics/gene.hpp index 0de648e..324939f 100644 --- a/src/game/genetics/gene.hpp +++ b/src/game/genetics/gene.hpp @@ -20,13 +20,13 @@ #ifndef ANTKEEPER_GENE_HPP #define ANTKEEPER_GENE_HPP -#include "allele.hpp" +#include namespace dna { -/// A gene with two alleles. -typedef std::array gene; +/// A 2-bit gene with two alleles. +typedef std::uint8_t gene; } // namespace dna diff --git a/src/game/genetics/genetic-operators.hpp b/src/game/genetics/genetic-operators.hpp new file mode 100644 index 0000000..574e5de --- /dev/null +++ b/src/game/genetics/genetic-operators.hpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_GENETIC_OPERATORS_HPP +#define ANTKEEPER_GENETIC_OPERATORS_HPP + +#include +#include + +namespace dna +{ + +/** + * Performs a genetic crossover on a range of interleaved allele blocks defined by `[first1, last1)`. + * + * @param[in] first1,last1 First range of interleaved allele blocks to crossover. + * @param[in] first2 Beginning of the the second range of interleaved allele blocks to crossover. + * @param[out] d_first Beginning of the destination range. + * @param[in,out] g A uniform random bit generator. + * @return Output iterator to the block past the last block crossed over. + */ +template +OutputIt crossover(InputIt1 first1, InputIt1 last1, InputIt2 first2, OutputIt d_first, URBG&& g) +{ + typedef typename std::iterator_traits::value_type block_t; + static constexpr std::size_t bits_per_block = sizeof(block_t) << 3; + + while (first1 != last1) + { + block_t block = 0; + + for (std::size_t i = 0; i < bits_per_block;) + { + block_t allele1 = ((*first1) >> (i + (g() % 2))) & 1; + block_t allele2 = ((*first2) >> (i + (g() % 2))) & 1; + + block |= allele1 << i++; + block |= allele2 << i++; + } + + *d_first++ = block; + ++first1; + ++first2; + } + + return d_first; +} + +/** + * Performs a genetic mutation by flipping the bit of a single allele in a range of interleaved allele blocks defined by `[first1, last1)`. + * + * @param[in,out] first,last Range of interleaved allele blocks to mutate. + * @param[in,out] g A uniform random bit generator. + * @return Locus of the mutated allele. + */ +template +typename std::iterator_traits::difference_type mutate(RandomIt first, RandomIt last, URBG&& g) +{ + typedef typename std::iterator_traits::value_type block_t; + typedef typename std::iterator_traits::difference_type diff_t; + static constexpr diff_t bits_per_block = sizeof(block_t) << 3; + + diff_t i = g() % ((last - first) * bits_per_block); + first[i / bits_per_block] ^= block_t(1) << (i % bits_per_block); + + return i; +} + +} // namespace dna + +#endif // ANTKEEPER_GENETIC_OPERATORS_HPP diff --git a/src/game/genetics/zygosity.hpp b/src/game/genetics/zygosity.hpp index 549edca..b67bcce 100644 --- a/src/game/genetics/zygosity.hpp +++ b/src/game/genetics/zygosity.hpp @@ -26,39 +26,39 @@ namespace dna { /// A homozygous recessive gene. -static constexpr gene homozygous_recessive = {allele::recessive, allele::recessive}; +static constexpr gene homozygous_recessive = 0b00; /// A homozygous dominant gene. -static constexpr gene homozygous_dominant = {allele::recessive, allele::recessive}; +static constexpr gene homozygous_dominant = 0b11; /// Returns `true` if gene @p x is heterozygous, `false` otherwise. -bool is_heterozygous(const gene& x); +bool is_heterozygous(gene x); /// Returns `true` if gene @p x is homozygous, `false` otherwise. -bool is_homozygous(const gene& x); +bool is_homozygous(gene x); /// Returns `true` if gene @p x is homozygous recessive, `false` otherwise. -bool is_homozygous_recessive(const gene& x); +bool is_homozygous_recessive(gene x); /// Returns `true` if gene @p x is homozygous dominant, `false` otherwise. -bool is_homozygous_dominant(const gene& x); +bool is_homozygous_dominant(gene x); -inline bool is_heterozygous(const gene& x) +inline bool is_heterozygous(gene x) { - return x[0] != x[1]; + return x - 1 < 2; } -inline bool is_homozygous(const gene& x) +inline bool is_homozygous(gene x) { - return x[0] == x[1]; + return (x & 1) == (x >> 1); } -inline bool is_homozygous_recessive(const gene& x) +inline bool is_homozygous_recessive(gene x) { return x == homozygous_recessive; } -inline bool is_homozygous_dominant(const gene& x) +inline bool is_homozygous_dominant(gene x) { return x == homozygous_dominant; }