Ejemplo n.º 1
0
int main()
{
    std::string name = "BrickyBot";
    std::string source = ":BrickyBot!~BrickyBot@BrickHouse";
    std::string server = "irc.p2p-network.net";
    std::string port = "6667";
    std::string channel = "#MyLittleAlcoholic";
    bool auto_reconnect = false;
    
    // Load and parse the options file for configurability
    std::vector<std::pair<std::string, std::string> > options = get_pairs_from_file("data/options");
    for (std::vector<std::pair<std::string, std::string> >::iterator options_it = options.begin(); options_it != options.end(); options_it++)
    {
        if ((*options_it).first == "name") name = (*options_it).second;
        else if ((*options_it).first == "source") source = (*options_it).second;
        else if ((*options_it).first == "server") server = (*options_it).second;
        else if ((*options_it).first == "port") port = (*options_it).second;
        else if ((*options_it).first == "channel") channel = (*options_it).second;
        else if ((*options_it).first == "auto_reconnect" && (*options_it).second == "true") auto_reconnect = true;
        else if ((*options_it).first == "debug" && (*options_it).second == "true") debug = true;
    }

    // initialize vectors    
    std::vector<std::string> operators = get_vector_from_file("data/operators");
    std::vector<std::string> episodes = get_vector_from_file("data/pony_episodes");
    std::vector<boost::tuple<std::string, uint16_t, time_t> > drinks = get_counts_from_tuples(get_tuples_from_file("data/drinkcount"));
    std::vector<std::pair<std::string, std::string> > responses = get_pairs_from_file("data/responses");
    std::vector<boost::tuple<std::string, uint16_t, time_t> > hits = get_counts_from_tuples(get_tuples_from_file("data/hitcount"));
    
    // set up signal handlers
    signal(SIGABRT, handleSignal);
    signal(SIGINT, handleSignal);
    signal(SIGTERM, handleSignal);
    
    try
    {
        // networking shit
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::resolver resolver(io_service);
        boost::asio::ip::tcp::resolver::query query(server, port);
        boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
        boost::asio::ip::tcp::socket socket(io_service);
        boost::asio::connect(socket, endpoint_iterator);

        boost::system::error_code ignored_error;
        uint64_t num_in = 0;
        bool first_ping = false;
        bool in_channel = false;
        
        while (running)
        {
            // Get a message from the server
            boost::array<char, 1024> buf;
            boost::system::error_code error;
            size_t len = socket.read_some(boost::asio::buffer(buf), error);

            // Check for an error or a closed connection
            if (error == boost::asio::error::eof)
            {
                // Connection closed cleanly by peer
                running = false;
            }
            else if (error)
            {
                // Some other dipshit error
                throw boost::system::system_error(error);
            }
            else
            {
                // No error. Parse the message.
                // First form a string from the char array
                std::string message_str(buf.begin(), buf.begin() + len);

                // Tokenize the string for multiple messages
                boost::char_separator<char> msg_sep("\r\n");
                boost::tokenizer<boost::char_separator<char> > msg_tok(message_str, msg_sep);

                // Place all the tokens into a vector
                std::vector<std::string> message_strings;
                for (boost::tokenizer<boost::char_separator<char> >::iterator it = msg_tok.begin(); it != msg_tok.end(); ++it)
                    message_strings.push_back(*it);

                // Process each message
                for (uint16_t i = 0; i < message_strings.size(); ++i)
                {
                    dbgPrint("incoming: %s\n", message_strings[i].c_str());

                    // Tokenize the message
                    boost::char_separator<char> sep(" ");
                    boost::tokenizer<boost::char_separator<char> > tok(message_strings[i], sep);
                    std::vector<std::string> tokens;
                    for (boost::tokenizer<boost::char_separator<char> >::iterator it = tok.begin(); it != tok.end(); ++it)
                        tokens.push_back(*it);

                    // Now process the message.
                    if (tokens[0] == "PING")
                    {
                        // Build a new string consisting of PONG followed by everything else
                        std::string send_str = "PONG";

                        for (uint16_t j = 1; j < tokens.size(); ++j)
                            send_str += " " + tokens[j];

                        // Add the carriage return and newline, as per IRC protocol
                        send_str += "\r\n";

                        // Send it to the server
                        boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);

                        first_ping = true;
                    }

                    num_in++;

                    
                    // Stupid IRC bullshit. Send some info after getting three messages.
                    if (num_in == 3)
                    {
                        // Send the USER/NICK message pair after 3 receives
                        // (What a w***e; receieves three times before telling its name...)
                        std::string nick_msg_str = "NICK " + name + "\r\n";
                        std::string user_msg_str = "USER " + name + " 0 * :" + name + "\r\n";
                        boost::asio::write(socket, boost::asio::buffer(nick_msg_str), ignored_error);
                        boost::asio::write(socket, boost::asio::buffer(user_msg_str), ignored_error);
                    }

                    // Join the channel when appropriate
                    if (first_ping && !in_channel)
                    {
                        // Connect after being pinged
                        std::string send_str = source + " JOIN :" + channel + "\r\n";
                        boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);

                        // wait a bit...
                        //boost::this_thread::sleep(boost::posix_time::milliseconds(1000));

                        in_channel = true;
                    }

                    // Bot is in the channel. The interesting shit is here
                    if (in_channel)
                    {
                        // Used to send messages
                        std::string send_str;

                        if (tokens[1] == "PRIVMSG") // gettin a message
                        {
                            // Get the name of the sending user
                            boost::char_separator<char> user_tok_sep(":!");
                            boost::tokenizer<boost::char_separator<char> > user_tok(tokens[0], user_tok_sep);
                            std::string sending_user = *(user_tok.begin());
                            
                            // Check whether the sending user is an operator
                            bool user_is_operator = (std::find(operators.begin(), operators.end(), sending_user) != operators.end());
                            
                            // Find the start of the text
                            uint16_t chat_start_index = 2;
                            while (tokens[chat_start_index][0] != ':') ++chat_start_index;
                            
                            // Add the first token (the start of the message) and remove the leading colon
                            std::string chat_text = tokens[chat_start_index];
                            chat_text.erase(0, 1);
                            
                            for (uint16_t chat_text_index = chat_start_index + 1; chat_text_index < tokens.size(); ++chat_text_index)
                            {
                                chat_text += " " + tokens[chat_text_index];
                            }

                            boost::char_separator<char> chat_sep(" ");
                            boost::tokenizer<boost::char_separator<char> > chat_tok(chat_text, chat_sep);
                            std::string chat_command = chat_text;
                            
                            int16_t chat_arg = -1;
                            
                            if (std::distance(chat_tok.begin(), chat_tok.end()) > 0)
                            {
                                chat_command =  *(chat_tok.begin());
                                
                                boost::tokenizer<boost::char_separator<char> >::iterator chat_tok_it = chat_tok.begin();
                                if (++chat_tok_it != chat_tok.end())
                                {
                                    try
                                    {
                                        chat_arg = boost::lexical_cast<int16_t>(*chat_tok_it);
                                    }
                                    catch (boost::bad_lexical_cast &)
                                    {
                                        BB
                                    }
                                }
                                
                                if (chat_arg < -1) chat_arg = -1;
                            }
                                
                            /*
                             *    This is where the bot actually does interesting things.
                             *    ---AT THIS INDENTATION, MOTHERFUCKERS.---
                             */
                            
                            // quit if an operator tells it to
                            if (boost::iequals(chat_text, name + ": quit") && user_is_operator)
                            {
                                send_str = source + " QUIT " + channel + " :quitting\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                                running = false;
                            }
                            
                            // reload operators file when ordered to by an operator
                            if (boost::iequals(chat_text, name + ": reload ops") && user_is_operator)
                            {
                                operators =  get_vector_from_file("data/operators");
                                send_str = source + " PRIVMSG " + channel + " :Reloaded operators.\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }

                            // .poni
                            if (boost::iequals(chat_command, ".poni"))
                            {
                                // pick a random episode
                                int episode = rand() % episodes.size();
                                send_str = source + " PRIVMSG " + channel + " :" + episodes[episode] + "\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                                
                            }
                            
                            // reload mlp episode list when ordered to by an operator
                            if (boost::iequals(chat_text, name + ": reload poni") && user_is_operator)
                            {
                                episodes =  get_vector_from_file("data/pony_episodes");
                                send_str = source + " PRIVMSG " + channel + " :Reloaded poni.\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            if (boost::iequals(chat_command, ".shot") || boost::iequals(chat_command, ".drink"))
                            {
                                // Find the user in the vector
                                int32_t user_index = get_user_index_in_counts(sending_user, drinks);
                                uint16_t current_drink_count;
                                
                                // If the user is already in the vector, increment the count and update the time.
                                // Otherwise, add the user and initialize them.
                                if (user_index != -1)
                                {
                                    time_t rawtime;
                                    time (&rawtime);
                                    
                                    drinks[user_index].get<1>() += chat_arg == -1? 1: chat_arg; 
                                    current_drink_count = boost::get<1>(drinks[user_index]);
                                    drinks[user_index].get<2>() = rawtime;
                                    // drinks[user_index].second += chat_arg == -1? 1: chat_arg;
                                    // current_drink_count = drinks[user_index].second;
                                }
                                else
                                {  ///////// Found a bug: if the user isn't in the array and adds more than one, it will only count as one, but
                                   ///////// it will say that it added however many it said it would. or so I think. I'm pretty drunk right now.
                                   time_t rawtime;
                                   time (&rawtime);
                                
                                   drinks.push_back(boost::make_tuple(sending_user, 1, rawtime));
                                    //drinks.push_back(std::make_pair(sending_user, 1));
                                    current_drink_count = chat_arg == -1? 1 : chat_arg;
                                }
                                
                                
                                // Write the changes to disk
                                write_counts(drinks, "data/drinkcount");
                                
                                // Convert the number of drinks into a string
                                std::ostringstream num_to_str;
                                num_to_str << current_drink_count;
                                std::string drink_count_str = num_to_str.str();
                                
                                // send the current number of drinks
                                send_str = source + " PRIVMSG " + channel + " :" + sending_user + ": you are now at " +
                                        drink_count_str + " drink(s).\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            if (boost::iequals(chat_command, ".weed") || boost::iequals(chat_command, ".hit") || boost::iequals(chat_command, ".toke"))
                            {
                                // Find the user in the vector
                                int32_t user_index = get_user_index_in_counts(sending_user, hits);
                                uint16_t current_hit_count;
                                
                                // If the user is already in the vector, increment the count.
                                // Otherwise, add the user and initialize them with one drink.
                                if (user_index != -1)
                                {
                                    time_t rawtime;
                                    time (&rawtime);  
                                    
                                    hits[user_index].get<1>() += chat_arg == -1? 1: chat_arg;
                                    current_hit_count = boost::get<1>(hits[user_index]);
                                    hits[user_index].get<2>() = rawtime;
                                    //hits[user_index].second += chat_arg == -1? 1: chat_arg;
                                    //current_hit_count = hits[user_index].second;
                                }
                                else
                                {  ///////// Found a bug: if the user isn't in the array and adds more than one, it will only count as one, but
                                   ///////// it will say that it added however many it said it would. or so I think. I'm pretty drunk right now.
                                   time_t rawtime;
                                   time (&rawtime);  
                                   
                                    hits.push_back(boost::make_tuple(sending_user, 1, rawtime));
                                    //hits.push_back(std::make_pair(sending_user, 1));
                                    current_hit_count = chat_arg == -1? 1: chat_arg;
                                }

                                
                                // Write the changes to disk
                                 write_counts(hits, "data/hitcount");
                                
                                // Convert the number of drinks into a string
                                std::ostringstream num_to_str;
                                num_to_str << current_hit_count;
                                std::string hit_count_str = num_to_str.str();
                                
                                // send the current number of drinks
                                send_str = source + " PRIVMSG " + channel + " :" + sending_user + ": you are now at " +
                                        hit_count_str + " hit(s).\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);                                
                            }
                            
                            if (boost::iequals(chat_command, ".reset"))
                            {
                                ////////////////// Reset Drink Count
                                
                                // Find the user in the vector
                                int32_t user_index = get_user_index_in_counts(sending_user, drinks);
                                
                                // set that user's shot/drink count to zero
                                if (user_index != -1)
                                {
                                    //drinks[user_index].second = 0;
                                    drinks[user_index].get<1>() = 0;
                                }
                                else
                                {
                                    time_t rawtime;
                                    time(&rawtime);
                                    //drinks.push_back(std::make_pair(sending_user, 0));
                                    drinks.push_back(boost::make_tuple(sending_user, 0, rawtime)); 
                                }
                                
                                // write changes to disk
                                write_counts(drinks, "data/drinkcount");
                                
                                ////////////////// Reset Hit Count
                                
                                // Find the user in the vector
                                user_index = get_user_index_in_counts(sending_user, hits);
                                
                                // set that user's hit count to zero
                                if (user_index != -1)
                                {
                                    //hits[user_index].second = 0;
                                    hits[user_index].get<1>() = 0;
                                }
                                else
                                {
                                    time_t rawtime;
                                    time(&rawtime);
                                    //hits.push_back(std::make_pair(sending_user, 0));
                                    hits.push_back(boost::make_tuple(sending_user, 0, rawtime));
                                }
                                
                                // write changes to disk
                                write_counts(hits, "data/hitcount");
                                
                                // send acknowledgement
                                send_str = source + " PRIVMSG " + channel + " :" + sending_user + ": you are now at 0 drinks and 0 hits.\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            
                            
                            // Print user's counts
                            if (boost::iequals(chat_command, ".count"))
                            {
                                // Find the user in the vector
                                int32_t user_index = get_user_index_in_counts(sending_user, drinks);
                                
                                send_str = source + " PRIVMSG " + channel + " :" + sending_user + ": you are now at ";
                                
                                if (user_index != -1)
                                {
                                    std::ostringstream num_to_str;
                                    //num_to_str << drinks[user_index].second;
                                    num_to_str << drinks[user_index].get<1>();
                                    send_str += num_to_str.str();
                                }
                                else
                                {
                                    send_str += "0";
                                }

                                send_str += " drinks and ";
                                
                                user_index = get_user_index_in_counts(sending_user, hits);
                                
                                if (user_index != -1)
                                {
                                    std::ostringstream num_to_str;
                                    //num_to_str << hits[user_index].second;
                                    num_to_str << hits[user_index].get<1>();
                                    send_str += num_to_str.str();
                                }
                                else
                                {
                                    send_str += "0";
                                }
                                
                                send_str += " hits.\r\n";

                                
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            // Print the time of the user's last count update
                            if (boost::iequals(chat_command, ".lastdrink"))
                            {
                                int32_t user_index = get_user_index_in_counts(sending_user, drinks);
                                
                                send_str = source + " PRIVMSG " + channel + " :" + sending_user + ": ";
                                
                                if (user_index != -1)
                                {
                                    if (boost::get<1>(drinks[user_index]) > 0)
                                    {
                                        send_str += "Last counted drink was at " + std::string(ctime(&(boost::get<2>(drinks[user_index])))) + ".\r\n";
                                    }
                                    else
                                    {
                                        send_str += "You have no counted drinks.\r\n";
                                    }
                                }
                                else
                                {
                                    send_str += "You have no counted drinks.\r\n";
                                }
                                
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                                
                            }
                            if (boost::iequals(chat_command, ".lasthit"))
                            {
                                int32_t user_index = get_user_index_in_counts(sending_user, drinks);
                                
                                send_str = source + " PRIVMSG " + channel + " :" + sending_user + ": ";
                                
                                if (user_index != -1)
                                {
                                    if (boost::get<1>(hits[user_index]) > 0)
                                    {
                                        send_str += "Last counted hit was at " + std::string(ctime(&(boost::get<2>(hits[user_index])))) + ".\r\n";
                                    }
                                    else
                                    {
                                        send_str += "You have no counted hits.\r\n";
                                    }
                                }
                                else
                                {
                                    send_str += "You have no counted hits.\r\n";
                                }
                                
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            
                            // Print the channel's total number of recorded drinks
                            if (boost::iequals(chat_command, ".chtotal"))
                            {
                                uint32_t total = 0;
                                //for (std::vector<std::pair<std::string, uint16_t> >::iterator drinks_it = drinks.begin(); drinks_it != drinks.end(); drinks_it++)
                                for (std::vector<boost::tuple<std::string, uint16_t, time_t> >::iterator drinks_it = drinks.begin(); drinks_it != drinks.end(); drinks_it++)
                                {
                                    //total += (*drinks_it).second;
                                    total += boost::get<1>(*drinks_it);
                                }
                                
                                std::ostringstream num_to_str;
                                num_to_str << total;
                                send_str = source + " PRIVMSG " + channel + " :Total drinks: " + num_to_str.str() + "; ";
                                
                                total = 0;
                                //for (std::vector<std::pair<std::string, uint16_t> >::iterator hits_it = hits.begin(); hits_it != hits.end(); hits_it++)
                                for (std::vector<boost::tuple<std::string, uint16_t, time_t> >::iterator hits_it = hits.begin(); hits_it != hits.end(); hits_it++)
                                {
                                    //total += (*hits_it).second;
                                    total += boost::get<1>(*hits_it);
                                }
                                
                                std::ostringstream num_to_str2;
                                num_to_str2 << total;
                                send_str += "Total hits: " + num_to_str2.str() + "\r\n";
                                
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            // Send all the drink info
                            if (boost::iequals(chat_command, ".chdrinks"))
                            {
                                send_str = source + " PRIVMSG " + channel + " :Channel Drinks: ";
                                
                                for (uint16_t i = 0; i < drinks.size(); i++)
                                {
                                    //if (drinks[i].second > 0)
                                    if (drinks[i].get<1>() > 0)
                                    {
                                        std::ostringstream num_to_str;
                                        //num_to_str << drinks[i].second;
                                        num_to_str <<  boost::get<1>(drinks[i]);
                                        //send_str += drinks[i].first + ": " + num_to_str.str() + ". ";
                                        send_str += boost::get<0>(drinks[i]) + ": " + num_to_str.str() + ". ";
                                    }
                                }
                                
                                send_str += "\r\n";
                                
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }

                            // Send all the hits info
                            if (boost::iequals(chat_command, ".chhits"))
                            {
                                send_str = source + " PRIVMSG " + channel + " :Channel Hits: ";
                                
                                for (uint16_t i = 0; i < hits.size(); i++)
                                {
                                    //if (hits[i].second > 0)
                                    if (hits[i].get<1>() > 0)
                                    {
                                        std::ostringstream num_to_str;
                                        //num_to_str << hits[i].second;
                                        num_to_str << boost::get<1>(drinks[i]);
                                        //send_str += hits[i].first + ": " + num_to_str.str() + ". ";
                                        send_str += boost::get<0>(drinks[i]) + ": " + num_to_str.str() + ". ";
                                    }
                                }
                                
                                send_str += "\r\n";
                                
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                             
                            // Operator command to reset all drinks
                            if (boost::iequals(chat_text, name + ": reset all drinks") && user_is_operator)
                            {
                                for (uint16_t i = 0; i < drinks.size(); i++)
                                {
                                    drinks[i].get<1>() = 0;
                                    // drinks[i].second = 0;
                                }
                                
                                write_counts(drinks, "data/drinkcount");
                                
                                send_str = source + " PRIVMSG " + channel + " :All drinks were reset.\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            // Operator command to reset all hits
                            if (boost::iequals(chat_text, name + ": reset all hits") && user_is_operator)
                            {
                                for (uint16_t i = 0; i < hits.size(); i++)
                                {
                                    //hits[i].second = 0;
                                    hits[i].get<1>() = 0;
                                }
                                
                                write_counts(hits, "data/hitcount");
                                
                                send_str = source + " PRIVMSG " + channel + " :All hits were reset.\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            // Operator command to reset both counters
                            if (boost::iequals(chat_text, name + ": reset all") && user_is_operator)
                            {
                                for (uint16_t i = 0; i < drinks.size(); i++)
                                {
                                    //drinks[i].second = 0;
                                    drinks[i].get<1>() = 0;
                                }
                                
                                write_counts(drinks, "data/drinkcount");
                                
                                
                                for (uint16_t i = 0; i < hits.size(); i++)
                                {
                                    //hits[i].second = 0;
                                    hits[i].get<1>() = 0;
                                    
                                }
                                
                                write_counts(hits, "data/hitcount");   
                                
                                send_str = source + " PRIVMSG " + channel + " :All drinks and hits were reset.\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            // modifying responses while running
                            if (boost::iequals(chat_text, name + ": reload responses") && user_is_operator)
                            {
                                responses = get_pairs_from_file("data/responses");
                                send_str = source + " PRIVMSG " + channel + " :Reloaded responses.\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            
                            // simple response commands
                            for (std::vector<std::pair<std::string, std::string> >::iterator resp_it = responses.begin(); resp_it != responses.end(); resp_it++)
                            {
                                if (boost::iequals(chat_command, (*resp_it).first))
                                {
                                    send_str = source + " PRIVMSG " + channel + " :" + (*resp_it).second + "\r\n";
                                    boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                                }
                            }
                        }
                        else if (tokens[1] == "KICK" && tokens[3] == name) // The bot was kicked
                        {
                            boost::char_separator<char> user_tok_sep(":!");
                            boost::tokenizer<boost::char_separator<char> > user_tok(tokens[0], user_tok_sep);
                            std::string sending_user = *(user_tok.begin());
                            bool user_is_operator = (std::find(operators.begin(), operators.end(), sending_user) != operators.end());

                            if (auto_reconnect && !user_is_operator)
                            {
                                // rejoin the channel
                                std::string send_str = source + " JOIN :" + channel + "\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                            }
                            else
                            {
                                // don't rejoin; just quit
                                send_str = source + " QUIT " + channel + " :quitting\r\n";
                                boost::asio::write(socket, boost::asio::buffer(send_str), ignored_error);
                                running = false;
                            }
                        }
                    }
                }
            }
Ejemplo n.º 2
0
plim_program
compile_for_plim( const mig_graph& mig,
                  const properties::ptr& settings,
                  const properties::ptr& statistics )
{
  /* settings */
  const auto verbose              = get( settings, "verbose", false );
  const auto progress             = get( settings, "progress", false );
  const auto enable_cost_function = get( settings, "enable_cost_function", true );
  const auto generator_strategy   = get( settings, "generator_strategy", 0u ); /* 0u: LIFO, 1u: FIFO */

  /* timing */
  properties_timer t( statistics );

  plim_program program;

  const auto& info = mig_info( mig );

  boost::dynamic_bitset<>                 computed( num_vertices( mig ) );
  std::unordered_map<mig_function, memristor_index> func_to_rram;
  auto_index_generator<memristor_index> memristor_generator(
      generator_strategy == 0u
          ? auto_index_generator<memristor_index>::request_strategy::lifo
          : auto_index_generator<memristor_index>::request_strategy::fifo );

  /* constant and all PIs are computed */
  computed.set( info.constant );
  for ( const auto& input : info.inputs )
  {
    computed.set( input );
    func_to_rram.insert( {{input, false}, memristor_generator.request()} );
  }

  /* keep a priority queue for candidates
     invariant: candidates elements' children are all computed */
  compilation_compare cmp( mig, enable_cost_function );
  std::priority_queue<mig_node, std::vector<mig_node>, compilation_compare> candidates( cmp );

  /* find initial candidates */
  for ( const auto& node : boost::make_iterator_range( vertices( mig ) ) )
  {
    /* PI and constant cannot be candidate */
    if ( out_degree( node, mig ) == 0 ) { continue; }

    if ( all_children_computed( node, mig, computed ) )
    {
      candidates.push( node );
    }
  }

  const auto parent_edges = precompute_ingoing_edges( mig );

  null_stream ns;
  std::ostream null_out( &ns );
  boost::progress_display show_progress( num_vertices( mig ), progress ? std::cout : null_out );

  /* synthesis loop */
  while ( !candidates.empty() )
  {
    ++show_progress;

    /* pick the best candidate */
    auto candidate = candidates.top();
    candidates.pop();

    L( "[i] compute node " << candidate );

    /* perform computation (e.g. mark which RRAM is used for this node) */
    const auto children = get_children( mig, candidate );
    boost::dynamic_bitset<> children_compl( 3u );
    for ( const auto& f : index( children ) )
    {
      children_compl.set( f.index, f.value.complemented );
    }

    /* indexes and registers */
    auto i_src_pos = 3u, i_src_neg = 3u, i_dst = 3u;
    plim_program::operand_t src_pos;
    plim_program::operand_t src_neg;
    memristor_index         dst;

    /* find the inverter */
    /* if there is one inverter */
    if ( children_compl.count() == 1u )
    {
      i_src_neg = children_compl.find_first();

      if ( children[i_src_neg].node == 0u )
      {
        src_neg = false;
      }
      else
      {
        src_neg = func_to_rram.at( {children[i_src_neg].node, false} );
      }
    }
    /* if there are more than one inverters, but one of them is a constant */
    else if ( children_compl.count() > 1u && children[children_compl.find_first()].node == 0u )
    {
      i_src_neg = children_compl.find_next( children_compl.find_first() );
      src_neg = func_to_rram.at( {children[i_src_neg].node, false} );
    }
    /* if there is no inverter but a constant */
    else if ( children_compl.count() == 0u && children[0u].node == 0u )
    {
      i_src_neg = 0u;
      src_neg = !children[0u].complemented;
    }
    /* if there are more than one inverters */
    else if ( children_compl.count() > 1u )
    {
      do /* in order to escape early */
      {
        /* pick an input that has multiple fanout */
        for ( auto i = 0u; i < 3u; ++i )
        {
          if ( !children_compl[i] ) continue;

          if ( cmp.fanout_count( children[i].node ) > 1u )
          {
            i_src_neg = i;
            src_neg = func_to_rram.at( {children[i_src_neg].node, false} );
            break;
          }
        }

        if ( i_src_neg < 3u ) { break; }

        i_src_neg = children_compl.find_first();
        src_neg = func_to_rram.at( {children[i_src_neg].node, false} );
      } while ( false );
    }
    /* if there is no inverter */
    else
    {
      do /* in order to escape early */
      {
        /* pick an input that has multiple fanout */
        for ( auto i = 0u; i < 3u; ++i )
        {
          const auto it_reg = func_to_rram.find( {children[i].node, true} );
          if ( it_reg != func_to_rram.end() )
          {
            i_src_neg = i;
            src_neg = it_reg->second;
            break;
          }
        }

        if ( i_src_neg < 3u ) { break; }

        /* pick an input that has multiple fanout */
        for ( auto i = 0u; i < 3u; ++i )
        {
          if ( cmp.fanout_count( children[i].node ) > 1u )
          {
            i_src_neg = i;
            break;
          }
        }

        /* or pick the first one */
        if ( i_src_neg == 3u ) { i_src_neg = 0u; }

        /* create new register for inversion */
        const auto inv_result = memristor_generator.request();

        program.invert( inv_result, func_to_rram.at( {children[i_src_neg].node, false} ) );
        func_to_rram.insert( {{children[i_src_neg].node, true}, inv_result} );
        src_neg = inv_result;
      } while ( false );
    }
    children_compl.reset( i_src_neg );

    /* find the destination */
    unsigned oa, ob;
    std::tie( oa, ob ) = three_without( i_src_neg );

    /* if there is a child with one fan-out */
    /* check whether they fulfill the requirements (non-constant and one fan-out) */
    const auto oa_c = children[oa].node != 0u && cmp.fanout_count( children[oa].node ) == 1u;
    const auto ob_c = children[ob].node != 0u && cmp.fanout_count( children[ob].node ) == 1u;

    if ( oa_c || ob_c )
    {
      /* first check for complemented cases (to avoid them for last operand) */
      std::unordered_map<mig_function, memristor_index>::const_iterator it;
      if ( oa_c && children[oa].complemented && ( it = func_to_rram.find( {children[oa].node, true} ) ) != func_to_rram.end() )
      {
        i_dst = oa;
        dst   = it->second;
      }
      else if ( ob_c && children[ob].complemented && ( it = func_to_rram.find( {children[ob].node, true} ) ) != func_to_rram.end() )
      {
        i_dst = ob;
        dst   = it->second;
      }
      else if ( oa_c && !children[oa].complemented )
      {
        i_dst = oa;
        dst   = func_to_rram.at( {children[oa].node, false} );
      }
      else if ( ob_c && !children[ob].complemented )
      {
        i_dst = ob;
        dst   = func_to_rram.at( {children[ob].node, false} );
      }
    }

    /* no destination found yet? */
    if ( i_dst == 3u )
    {
      /* create new work RRAM */
      dst = memristor_generator.request();

      /* is there a constant (if, then it's the first one) */
      if ( children[oa].node == 0u )
      {
        i_dst = oa;
        program.read_constant( dst, children[oa].complemented );
      }
      /* is there another inverter, then load it with that one? */
      else if ( children_compl.count() > 0u )
      {
        i_dst = children_compl.find_first();
        program.invert( dst, func_to_rram.at( {children[i_dst].node, false} ) );
      }
      /* otherwise, pick first one */
      else
      {
        i_dst = oa;
        program.assign( dst, func_to_rram.at( {children[i_dst].node, false} ) );
      }
    }

    /* positive operand */
    i_src_pos = 3u - i_src_neg - i_dst;
    const auto node = children[i_src_pos].node;

    if ( node == 0u )
    {
      src_pos = children[i_src_pos].complemented;
    }
    else if ( children[i_src_pos].complemented )
    {
      const auto it_reg = func_to_rram.find( {node, true} );
      if ( it_reg == func_to_rram.end() )
      {
        /* create new register for inversion */
        const auto inv_result = memristor_generator.request();

        program.invert( inv_result, func_to_rram.at( {node, false} ) );
        func_to_rram.insert( {{node, true}, inv_result} );
        src_pos = inv_result;
      }
      else
      {
        src_pos = it_reg->second;
      }
    }
    else
    {
      src_pos = func_to_rram.at( {node, false} );
    }

    program.compute( dst, src_pos, src_neg );
    func_to_rram.insert( {{candidate, false}, dst} );

    /* free free registers */
    for ( const auto& c : children )
    {
      if ( cmp.remove_fanout( c.node ) == 0u && c.node != 0u )
      {
        const auto reg = func_to_rram.at( {c.node, false} );
        if ( reg != dst )
        {
          memristor_generator.release( reg );
        }

        const auto it_reg = func_to_rram.find( {c.node, true} );
        if ( it_reg != func_to_rram.end() && it_reg->second != dst )
        {
          memristor_generator.release( it_reg->second );
        }
      }
    }

    /* update computed and find new candidates */
    computed.set( candidate );
    const auto it = parent_edges.find( candidate );
    if ( it != parent_edges.end() ) /* if it has parents */
    {
      for ( const auto& e : it->second )
      {
        const auto parent = boost::source( e, mig );

        if ( !computed[parent] && all_children_computed( parent, mig, computed ) )
        {
          candidates.push( parent );
        }
      }
    }

    L( "    - src_pos: " << i_src_pos << std::endl <<
       "    - src_neg: " << i_src_neg << std::endl <<
       "    - dst:     " << i_dst << std::endl );
  }

  set( statistics, "step_count", (int)program.step_count() );
  set( statistics, "rram_count", (int)program.rram_count() );

  std::vector<int> write_counts( program.write_counts().begin(), program.write_counts().end() );
  set( statistics, "write_counts", write_counts );

  return program;
}
Ejemplo n.º 3
0
int main(int argc, char **argv)
{
	struct hist_record rec;
	char *line;
	game initgame;
	bool localdat = false;
	char cwd_buf[1024];
	unsigned int (*bcounts)[3];
	int ca[2];
	date current = {0, 0, 0};
	int arg;
	int rc;
	for (arg = 1; arg < argc; arg++)
	{
		if (!strcmp(argv[arg], "--localdat"))
		{
			localdat=true;
		}
		else
		{
			fprintf(stderr, "Unrecognised argument '%s'\n", argv[arg]);
			return 5;
		}
	}

	if(!(cwd=getcwd(cwd_buf, 1024)))
	{
		perror("getcwd");
		return 5;
	}

	fprintf(stderr, "Loading data files...\n");
	
#ifndef WINDOWS
	if(chdir(localdat?cwd:DATIDIR))
	{
		perror("Failed to enter data dir: chdir");
		if(!localdat)
			fprintf(stderr, "(Maybe try with --localdat, or make install)\n");
		return 5;
	}
#endif

	rc = load_data();
	if (rc)
		return rc;
	bcounts = calloc(ntypes, sizeof(*bcounts));
	if (!bcounts)
	{
		perror("calloc");
		return 5;
	}
	rc = set_init_state(&initgame);
	if (rc)
		return rc;

	fprintf(stderr, "Data files loaded\n");

	while(!feof(stdin))
	{
		line = fgetl(stdin);
		if (!line)
		{
			fprintf(stderr, "Unexpected EOF\n");
			return 3;
		}
		if (!strncmp(line, "History:", 8))
		{
			free(line);
			break;
		}
	}

	while(!feof(stdin))
	{
		line = fgetl(stdin);
		if (!line) break;
		rc = parse_event(&rec, line);
		if (rc)
		{
			fprintf(stderr, "Error %d in line: %s\n", rc, line);
			free(line);
			return rc;
		}
		free(line);
		if (rec.type == HT_INIT)
		{
			char savbuf[80];

			snprintf(savbuf, 80, "save/%s", rec.init);
			rc = loadgame(savbuf, &initgame);
			if (rc)
			{
				fprintf(stderr, "Error %d loading INITgame '%s'\n", rc, savbuf);
				return 6;
			}
			for (unsigned int i = 0; i < initgame.nbombers; i++)
				bcounts[initgame.bombers[i].type][0]++;
			ca[0] = initgame.cshr;
			ca[1] = initgame.cash;
		}
		else if (rec.type == HT_AC)
		{
			if (rec.ac.type == AE_CT)
			{
				if (!rec.ac.fighter)
				{
					bcounts[rec.ac.ac_type][0]++;
					bcounts[rec.ac.ac_type][1]++;
				}
			}
			else if (rec.ac.type == AE_CROB)
			{
				if (!rec.ac.fighter)
				{
					bcounts[rec.ac.ac_type][0]--;
					bcounts[rec.ac.ac_type][2]++;
				}
			}
		}
		else if (rec.type == HT_MISC)
		{
			if (rec.misc.type == ME_CASH)
			{
				ca[0] = rec.misc.cash.delta;
				ca[1] = rec.misc.cash.current;
			}
		}
		if (diffdate(rec.date, current))
			write_counts(current = rec.date, bcounts, ca);
	}
	return 0;
}