/*
* Copyright (C) 2009 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
*
* This file is part of nucad (Non-Uniform CA Designer).
*
* nucad 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
* any later version.
*
* nucad 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 nucad. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file check.cpp
* Command-line utility which can work with (partial or complete) solutions
* found by nucad.
*/
#include "CaDesigner.h"
#include "CaFactory.h"
#include "Color.h"
#ifndef BUILDING_DOX
# include <iostream>
# include <string>
#endif
#include <getopt.h>
using std::string;
// cmd-line option list
static struct option const long_opts[] = {
{ "echo", no_argument, 0, 'e' },
{ "input", required_argument, 0, 'i' },
{ "list", no_argument, 0, 'l' },
{ "quiet", no_argument, 0, 'q' },
{ "rules", no_argument, 0, 'r' },
{ "simulate", no_argument, 0, 's' },
{ "help", no_argument, 0, 'h' },
// this line avoids SIGSEGV if an invalid long option is given
{ NULL, 0, NULL, 0}
};
namespace {
/**
* Print usage for executable.
* @param name Name of the executable (usually argv[0]).
* @param status Expected status code ought to be returned.
*/
void usage(const char *name, int status)
{
if (status != EXIT_SUCCESS)
std::cerr << "Try `" << name
<< " --help' for more information." << std::endl;
else
std::cout << "Usage: " << name << " [OPTIONS] CIRCUIT_NAME\n\
-e, --echo diagnostic echo for rules\n\
-i, --input=INPUT simulation for given input\n\
-l, --list print circuit list\n\
-q, --quiet suppress statistics\n\
-r, --rules dump rules in human readable form\n\
-s, --simulate simulation for all inputs\n\
--help print this help to stdout"
<< std::endl;
}
/**
* Write CA's rules to stream in human-readable format.
* @param rules The CA's rules to write.
* @param str Standard output stream to write to.
*/
void writeRules(GaCaRules *rules, size_t caSize, std::ostream &str)
{
for (unsigned row = 0; row < caSize; ++row) {
for (unsigned col = 0; col < caSize; ++col) {
str << Color(C_LIGHT_PURPLE) << "--- cell ["
<< row << "," << col << "]"
<< Color(C_NO_COLOR) << std::endl;
TRule5N rule;
rules->getRuleAtPos(Pos(row, col), rule);
writeRule(str, rule);
}
}
}
}
int main(int argc, char *argv[]) {
// name of executable which is printed on user interaction
static const char *szAppName = argv[0];
// enable colorized output only if stdout/stderr are connected to terminal
Color::enable(isatty(STDOUT_FILENO) && isatty(STDERR_FILENO));
// state variables necessary to always delete an existing (if any) evaluator
int ec = 0;
CaEvaluator *evaluator = 0;
try {
// parameters to be read from cmd-line by getopt_long
bool echo = false;
bool printList = false;
bool quiet = false;
bool dumpRules = false;
bool simOne = false;
bool simAll = false;
TBus in = 0;
// parse cmd-line arguments
int c;
while ((c = getopt_long (argc, argv, "ei:lqrs", long_opts, 0)) != -1) {
switch (c) {
case 'e':
echo = true;
break;
case 'i':
simOne = true;
// FIXME: check if the string is really a number
if (!optarg)
throw std::runtime_error(
"invalid --input (-i) argument");
// FIXME: avoid using atoi()
in = atoi(optarg);
break;
case 'l':
printList = true;
break;
case 'q':
quiet = true;
break;
case 'r':
dumpRules = true;
break;
case 's':
simAll = true;
break;
case 'h':
// print usage and exit successfully
usage(argv[0], EXIT_SUCCESS);
return EXIT_SUCCESS;
}
}
// check for possible cmd-line arguments conflicts
if (simOne && simAll)
throw std::runtime_error(
"options -i and -s are mutually exclusive");
// create factory on stack (to avoid possible memory leak)
CaEvaluatorFactory factory;
if (printList) {
// print circuit list and exit
factory.printList(std::cout);
return 0;
}
// read circuit name from cmd-line
argc -= optind;
argv += optind;
if (argc != 1)
throw std::runtime_error("invalid count of arguments");
// try to create evaluator for desired circuit
// this might fail if circuit name is not valid
evaluator = factory.create(argv[0]);
// parse data from stdin line after line
string line;
while (getline(std::cin, line)) {
// deserialize non-uniform CA's rules
GaCaRules rules(line);
// check size of the deserialized CA's
if (rules.size() !=
evaluator->caSize() * evaluator->caSize() * RULE_WIDTH)
throw std::runtime_error(
"GaCaRules size mismatch (not implemented)");
if (echo)
// print echo if requested by cmd-line parameter
std::cout << rules << std::endl;
if (!quiet) {
// simulate given CA's rules and print statistics
unsigned min, max;
if (evaluator->cntSteps(&rules, min, max)) {
std::cout << "--- nSteps: <" << min << ", " << max << ">"
<< std::endl;
} else {
std::cout << "--- fitness = " << evaluator->eval(&rules)
<< std::endl;
}
}
if (dumpRules)
// write CA's rules in human-readable format
writeRules(&rules, evaluator->caSize(), std::cout);
if (simOne)
// simulate CA for given input value
evaluator->simulate(&rules, std::cout, in);
if (simAll)
// simulate CA for all possible input values
evaluator->simulate(&rules, std::cout);
}
}
catch (std::runtime_error &e) {
std::cerr << szAppName << ": "
<< Color(C_LIGHT_RED) << "error: " << Color(C_NO_COLOR)
<< e.what() << std::endl;
ec = 1;
}
delete evaluator;
return ec;
}