#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <set>
#include <variant>
#include <vector>

class Ammunition {
public:
    Ammunition(size_t amount)
        : _amount(amount) {}
    virtual ~Ammunition() = default;

    size_t amount() const { return _amount; }

private:
    size_t _amount = 0;
};

class RoundShot final : public Ammunition {
public:
    using Ammunition::Ammunition;
};

class ChainShot final : public Ammunition {
public:
    using Ammunition::Ammunition;
};

class GrapeShot final : public Ammunition {
public:
    using Ammunition::Ammunition;
};

class DamageVisitor {
public:
    void operator()(const RoundShot& shot) const {
        std::cout << "Round shot make 20 damages\n";
    }
    void operator()(const ChainShot& shot) const {
        std::cout << "Chain shot make 30 damages\n";
    }
    void operator()(const GrapeShot& shot) const {
        std::cout << "Grape shot make 40 damages\n";
    }
};

class SoundVisitor {
public:
    void operator()(const RoundShot& shot) const {
        std::cout << "Fiuuuuuuuu Bam!\n";
    }
    void operator()(const ChainShot& shot) const {
        std::cout << "Fiuuuuuuuuuuu Bam bam!\n";
    }
    void operator()(const GrapeShot& shot) const {
        std::cout << "Fiuuuuuuuuuuu Bam bam bam bam bam!\n";
    }
};

int main() {
    using Shot = std::variant<RoundShot, ChainShot, GrapeShot>;

    Shot shot = GrapeShot(100);
    SoundVisitor soundVisitor;
    DamageVisitor damageVisitor;
    std::visit(damageVisitor, shot);
    std::visit(soundVisitor, shot);
}
