Kalkulator łańcuchów produkcyjnych.

0

Witajcie, mam taki oto problem, z którym chciałbym sobie od strony programistycznej jak najoptymalniej poradzić.

Mianowicie postanowiłem sobie napisać prosty kalkulator produkcji (łańcuchów produkcyjnych) do gierki online, w którą grywam. Kalkulator ma mieć prostą (prawie jak cep) budowę: na wejściu ma przyjmować nazwę przedmiotu, który chcemy wyprodukować oraz jego ilość; na wyjściu zaś mamy dostawać listę produktów, które są potrzebne do zrobienia tego podanego przez nas wraz z ich ilościami.
Próbowałem rozwiązanie to zaimplementować w Excelu, ale się tam zamotałem, więc chcę to napisać w C++.

Gdzie wg mnie tkwi problem? Ano w tym, iż niektóre produkty występują w wielu łańcuchach produkcyjnych jako substraty do wyprodukowania innych rzeczy, inne zaś są produktami podstawowymi, których nie robi się z czegoś innego. I ni w ząb nie wiem, jak to ugryźć w sensowny sposób.

Najpierw myślałem o tym, żeby zrobić całą masę zmiennych, które miałyby przechowywać ilości danych produktów, ale to by było chyba najmniej optymalne rozwiązanie, jakie sobie można wyobrazić (ze względu na mnogość zasobów w tej grze). Poza tym byłoby to pójście na łatwiznę i brak możliwości nauczenia się (lub potrenowania) dobrego zaprojektowania programu obiektowego.
Wpadłem więc na pomysł, aby zrobić klasę, która będzie symulować produkt podstawowy - i w niej pola o nazwach takich jak te produkty, które byłyby inkrementowane poprzez wywołanie metody klasowej z podanym odpowiednim argumentem. Z drugiej znów strony nie wiem, czy to ma sens, czy może każdy produkt podstawowy powinien być osobnym obiektem... podejrzewam też, że powinien być tam dla ułatwienia zostać zastosowany jakiś typ wyliczeniowy :( pogubiłem się już w tym zupełnie - o ile jestem w stanie jakoś poskładać w całość mechanizm obliczeń, o tyle zaprojektowanie tego z sensem znowu sprawia mi problem pomimo tego, iż programuję już od kilku ładnych lat.... :x

Czytałem ostatnio książkę z serii Head First o projektowaniu obiektowym i niby coś tam zaczęło świtać, ale w praktyce nadal nie wiem jak sobie z tym poradzić. Dlatego będę wdzięczny za wszelkie sugestie, w jaki sposób to zaprojektować i na co w pierwszej kolejności zwrócić uwagę. :)

Pozdrawiam
Łukasz

0

z opisu nie moge wylapac zaleznosci tych produktow. Mozesz opisac to jasniej? W sensie relacje miedzy produktem, gra a produktym podstawowym i rozszerzonym?

3

Chodziło o takie coś?

Nawet ciekawie się pisało to masz gotowca (:

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <memory>
#include <sstream>

struct Product;

struct Component
{
    size_t amount;
    Product &product;
};

struct Product
{
    typedef std::map<std::string, size_t> NeededProducts;

    std::string name;
    std::vector<Component> components;

    bool isBasicProduct() const
    {
        return components.size() == 0;
    }

    static void insertProducts( size_t amount, 
                                const NeededProducts &productsToInsert, 
                                NeededProducts &insertTo )
    {
        for( const auto &productPair : productsToInsert )
        {
            auto &productName = productPair.first;
            auto &productAmount = productPair.second;

            insertTo[productName] += amount * productAmount;
        }
    }

    NeededProducts getNeededProducts( size_t myselfAmount ) const
    {
        NeededProducts neededProducts;

        for( const auto &component : components )
        {
            const size_t amount = myselfAmount * component.amount;

            neededProducts[component.product.name] += amount;

            auto componentNeededProducts = component.product.getNeededProducts( component.amount );

            insertProducts( amount,
                            componentNeededProducts,
                            neededProducts );
        }

        return neededProducts;
    }

    NeededProducts getBasicProducts( size_t myselfAmount ) const
    {
        NeededProducts neededProducts;

        for( const auto &component : components )
        {
            const size_t amount = myselfAmount * component.amount;

            if( component.product.isBasicProduct() )
                neededProducts[component.product.name] += amount;
            else
            {

                auto componentNeededProducts = component.product.getBasicProducts( component.amount );

                insertProducts( amount,
                                componentNeededProducts,
                                neededProducts );
            }
        }

        return neededProducts;
    }
};



std::map<std::string, std::shared_ptr<Product>> loadProducts( std::istream &in )
{
    std::string name;
    std::map<std::string, std::shared_ptr<Product>> products;

    while( in >> name )
    {
        std::shared_ptr<Product> product( new Product );
        size_t componentAmount;

        product->components.clear();
        product->name = name;

        while( in >> componentAmount && componentAmount != 0 )
        {
            std::string componentName;

            in >> componentName;

            product->components.push_back( { componentAmount, *products[componentName] } );
        }

        products[name] = product;
    }

    return products;
}

int main()
{
    std::istringstream iss( "zboze 0\n\
                            jajko 0\n\
                            woda 0\n\
                            jablko 0\n\
                            burakCukrowy 0\n\
                            cukier 10 burakCukrowy 0\n\
                            dzem 20 jablko 1 cukier 0\n\
                            maka 20 zboze 0\n\
                            paczek 1 maka 2 jajko 1 dzem 0\n\
                            chleb 1 maka 1 woda 0" );

    auto products = loadProducts( iss );

    auto neededProducts = products["paczek"]->getNeededProducts(2);

    std::cout << "Na dwa paczki trza:\n";

    for( const auto &productPair : neededProducts )
        std::cout << productPair.second << "x " << productPair.first << "\n";

    neededProducts = products["paczek"]->getBasicProducts( 2 );
    std::cout << "\n\nNa dwa paczki samych bazowych produktow potrzebujesz:\n";

    for( const auto &productPair : neededProducts )
        std::cout << productPair.second << "x " << productPair.first << "\n";

    return 0;
}

out:

Na dwa paczki trza:
20x burakCukrowy
2x cukier
2x dzem
40x jablko
4x jajko
2x maka
40x zboze


Na dwa paczki samych bazowych produktow potrzebujesz:
20x burakCukrowy
40x jablko
4x jajko
40x zboze
0

Jestem pod wrażeniem! Nigdy bym nie wpadł na to, że można w ten sposób napisać takowy program. W 10 próbach na 10 prób poszedłbym w stronę zrobienia kilku klas symulujących towar podstawowy/pochodny/główny, ewentualnie jakieś typy wyliczeniowe, żeby zastosować obiektówkę od podstaw. Ale w taki sposób jak wyżej nigdy bym chyba do problemu nie podszedł. No ale cóż - człowiek się uczy ciągle nowych rozwiązań... Muszę trochę posiedzieć nad tym kodem, żeby rozkminić co która funkcja w jaki sposób robi... Bo niektóre biblioteki pierwszy raz na oczy widzę :x

Edit:
user image
Widzę, że mój kompilator nie przepuścił całości kodu - czy to może być wina nieaktualnego środowiska, czy jakaś inna przyczyna?

0

A da się w jakiś sposób przesłać do zmiennej typu istringstream dane tak, aby wczytywanie nie zajmowało około 100 linii kodu? Można jakoś zaincludować zewnętrzny plik .cpp z samymi danymi? Ewentualnie jako wczytany zewn. plik tekstowy?

0

oczywiscie ze tak. Uzyj www.google.com wpisz tam
reading file istringstream

(tym razem zrobilem za Ciebie, ale takie pytania latwiej Ci sprawdzic w 10 sekund niz czekac na odpowiedz)

http://stackoverflow.com/questions/132358/how-to-read-file-content-into-istringstream

0

@lukusm
Eee.. a czemu nie przekazać samego ifstream?

1 użytkowników online, w tym zalogowanych: 0, gości: 1