Author Topic: graph command  (Read 2534 times)

Offline chaos

  • BFF
  • ***
  • Posts: 290
  • Job, school, social life, sleep. Pick 2.5.
    • View Profile
    • Lost Souls
graph command
« on: April 04, 2008, 10:28:00 AM »
This is a command definition from my unreleased mudlib, so I'm afraid that if you like it you've got some porting to do.

Code: [Select]
#include <command.h>
#include <display.h>
#include <security.h>

inherit "/std/def/command";

#define Default_Domain_Low   0.0
#define Default_Domain_High  1.0

void configure() {
    ::configure();
    set_creator("chaos");
    set_command_type(Command_Type_Administrative);
    set_command_privilege_required(STANDARD);
    set_command_name("graph");
    set_command_ooc(True);
    set_command_help_usage("graph [-c <columns>] [-r <rows>] <f(x)> [over <n>..<m>] [on <a>..<b>]");
    set_command_help(
        "Constructs and displays a simple graph of a given mathematical "
        "function, specified as a function of the variable x.  This command "
        "was developed for the convenience of lib designers working with "
        "interesting formulae (see the last two examples below).\n"
        "\fThe domain (input values) over which the function will be "
        "evaluated may be specified with the [over <n>..<m>] clause.  The "
        "default is to evaluate over 0..1.\n"
        "\fThe range (output values) which the graph will cover may be "
        "specified with the [on <a>..<b>] clause.  The default is to "
        "adaptively construct the range of the graph according to the "
        "range of values found for the function over the domain.\n"
        "\fThe -c option can be used to specify the number of columns in "
        "the graph (which determines the number and exact values of the "
        "points used within the domain).  The default is to use your "
        "terminal columns - 10 (leaving room for labels and so on).\n"
        "\fThe -r option can be used to specify the number of rows in the "
        "graph.  The default is to use your terminal rows - 10.\n"
    );
    set_command_help_examples(({
        "graph pow(x, 2)",
        "    {{layout: deemphasis}Graph the square of X}",
        "graph sin(x) over 0..6.3",
        "    {{layout: deemphasis}Graph a lovely sine curve}",
        "graph 1 / pow(x, 2) over 1..10 on 0..1",
        "    {{layout: deemphasis}Graph 1 over X squared from 1 to 10, scaled from 0 to 1}",
        "graph standard_scale(x, 20, True) over 0..300",
        "    {{layout: deemphasis}Graph the character speed values obtained for speed}",
        "    {{layout: deemphasis}modification levels from 0 to 300}",
        "graph standard_scale(x, 20, True) over -300..0",
        "    {{layout: deemphasis}Graph the character speed values obtained for speed}",
        "    {{layout: deemphasis}modification levels from -300 to 0}",
    }));
    set_command_help_see_also(({ "eval", "man log", "man exp", "man pow", "man standard_scale" }));
}

private string short_number(float val, int num) {
    string out = to_string(val);
    if(strlen(out) <= num)
        return out;
    string mantissa, exponent;
    if(sscanf(out, "%se%s", mantissa, exponent) == 2)
        return mantissa[0 .. num - strlen(exponent) - 2] + "e" + exponent;
    else
        return out[0 .. num - 1];
}

mixed execute(string arg, object who, string verb, status override, string full) {
    if(!arg)
        return "Usage: graph [-c <columns>] [-r <rows>] <f(x)> [over <n>..<m>] [on <a>..<b>]";
    int rows;
    int columns;
    unless(sscanf(arg, "-c %d %s", columns, arg) == 2)
        columns = who->query_term_columns() - 10;
    unless(sscanf(arg, "-r %d %s", rows, arg) == 2)
        rows = who->query_term_rows() - 10;
    string from, to;
    float range_low, range_high, range;
    if(sscanf(arg, "%s on %s..%s", arg, from, to) == 3) {
        if(sizeof(regexp(({ from, to }), "[^0-9\.\-]")))
            return "Range elements must be numbers.";
        range_low = to_float(from);
        range_high = to_float(to);
        unless(range_high > range_low)
            return "Upper end of range must be greater than lower end.";
        range = range_high - range_low;
    } else {
        range = 0;
    }
    float domain_low, domain_high;
    if(sscanf(arg, "%s over %s..%s", arg, from, to) == 3) {
        if(sizeof(regexp(({ from, to }), "[^0-9\.\-]")))
            return "Domain elements must be numbers.";
        domain_low = to_float(from);
        domain_high = to_float(to);
        unless(domain_high > domain_low)
            return "Upper end of domain must be greater than lower end.";
    } else {
        domain_low = Default_Domain_Low;
        domain_high = Default_Domain_High;
    }
    float domain = domain_high - domain_low;
    unless(check_privilege(who, GAME_SECURITY))
        log_file("Eval", ctime() + ": " + object_name(who) + " graphing function " + arg);
    string file = "/w/" + who->query_real_name() + "/temp_graph.c";
    rm(file);
    object obj = find_object(file);
    if(obj)
        destruct(obj);
    write_file(file,
        "float func(float x) {\n"
        "\treturn to_float(" + arg + ");\n"
        "}\n"
    );
    string error = catch(obj = load_object(file));
    rm(file);
    if(error)
        return "Your specified function could not be compiled.";
    float array data = ({});
    for(int index = 0; index < columns; index++)
        data += ({ obj->func(domain_low + domain * index / (columns - 1)) });
    destruct(obj);
    unless(range) {
        range_low = min(data);
        range_high = max(data);
        range = range_high - range_low;
    }
    mixed array plot = allocate(columns, allocate(rows));
    int point;
    for(int index = 0; index < columns; index++) {
        point = round((data[index] - range_low) * (rows - 1) / range);
        if(point >= 0 && point < rows)
            plot[index][point] = True;
    }
    string out = "";
    for(int y = 0; y < rows; y++) {
        out += left_justify(short_number(range_low + (rows - y - 1) * range / (rows - 1), 7), 7) + " |";
        for(int x = 0; x < columns; x++)
            if(plot[x][rows - y - 1])
                out += "*";
            else
                out += " ";
        out += "\n";
    }
    out += "        \\" + ("-" * columns) + "\n";
    string array labels = ({});
    string label;
    for(int index = 0; index < columns; index++) {
        label = short_number(domain_low + domain * index / (columns - 1), 8);
        if(index == 0 || index == columns - 1 || strlen(label) < 4 || labels[index - 1] == "")
            labels += ({ label });
        else
            labels += ({ "" });
    }
    int lines = max(map(labels, #'strlen));
    for(int line = 0; line < lines; line++) {
        out += "         ";
        for(int index = 0; index < columns; index++)
            if(labels[index][line])
                out += labels[index][line..line];
            else
                out += " ";
        out += "\n";
    }
    who->display(out, Display_Preformatted);
    return True;
}

Output of 'help graph':

Code: [Select]
Command: Graph

    Administrative Command
    System Privilege Required: standard (enabled)
    Usage: graph [-c <columns>] [-r <rows>] <f(x)> [over <n>..<m>] [on <a>..<b>]

    Constructs and displays a simple graph of a given mathematical function, specified as a function of the variable x.  This
command was developed for the convenience of lib designers working with interesting formulae (see the last two examples below).

    The domain (input values) over which the function will be evaluated may be specified with the [over <n>..<m>] clause.  The
default is to evaluate over 0..1.

    The range (output values) which the graph will cover may be specified with the [on <a>..<b>] clause.  The default is to
adaptively construct the range of the graph according to the range of values found for the function over the domain.

    The -c option can be used to specify the number of columns in the graph (which determines the number and exact values of the
points used within the domain).  The default is to use your terminal columns - 10 (leaving room for labels and so on).

    The -r option can be used to specify the number of rows in the graph.  The default is to use your terminal rows - 10.

    Examples: graph pow(x, 2)
                  Graph the square of X
              graph sin(x) over 0..6.3
                  Graph a lovely sine curve
              graph 1 / pow(x, 2) over 1..10 on 0..1
                  Graph 1 over X squared from 1 to 10, scaled from 0 to 1
              graph standard_scale(x, 20, True) over 0..300
                  Graph the character speed values obtained for speed
                  modification levels from 0 to 300
              graph standard_scale(x, 20, True) over -300..0
                  Graph the character speed values obtained for speed
                  modification levels from -300 to 0

    Development Information: The graph command (/def/command/graph) was created by Chaos; the source code was last updated Wed Feb
14 08:47:41 2007.

    See Also: eval, man log, man exp, man pow, man standard_scale

Output of 'graph sin(x) over 0..6.3':

0.99996 |                           ********                                                                                       
0.95915 |                        ***        **                                                                                     
0.91834 |                      **             **                                                                                   
0.87753 |                    **                 **                                                                                 
0.83672 |                   *                     *                                                                               
0.79591 |                  *                       **                                                                             
0.75510 |                **                          *                                                                             
0.71429 |               *                             *                                                                           
0.67349 |              *                               *                                                                           
0.63268 |             *                                 *                                                                         
0.59187 |            *                                   *                                                                         
0.55106 |           *                                     *                                                                       
0.51025 |          *                                       *                                                                       
0.46944 |         *                                         *                                                                     
0.42863 |                                                    *                                                                     
0.38782 |        *                                            *                                                                   
0.34702 |       *                                                                                                                 
0.30621 |      *                                               *                                                                   
0.26540 |     *                                                 *                                                                 
0.22459 |    *                                                   *                                                                 
0.18378 |                                                         *                                                               
0.14297 |   *                                                                                                                     
0.10216 |  *                                                       *                                                               
0.06135 | *                                                         *                                                             
0.02054 |                                                            *                                                            *
-0.0202 |*                                                            *                                                          *
-0.0610 |                                                                                                                         
-0.1018 |                                                              *                                                        * 
-0.1426 |                                                               *                                                      *   
-0.1834 |                                                                *                                                    *   
-0.2243 |                                                                 *                                                  *     
-0.2651 |                                                                                                                         
-0.3059 |                                                                  *                                                *     
-0.3467 |                                                                   *                                              *       
-0.3875 |                                                                    *                                            *       
-0.4283 |                                                                     *                                          *         
-0.4691 |                                                                      *                                        *         
-0.5099 |                                                                       *                                      *           
-0.5507 |                                                                        *                                                 
-0.5915 |                                                                                                             *           
-0.6323 |                                                                         *                                  *             
-0.6732 |                                                                          **                              **             
-0.7140 |                                                                            *                            *               
-0.7548 |                                                                             *                          *                 
-0.7956 |                                                                              *                        *                 
-0.8364 |                                                                               **                    **                   
-0.8772 |                                                                                 *                  *                     
-0.9180 |                                                                                  **              **                     
-0.9588 |                                                                                    ***        ***                       
-0.9996 |                                                                                       ********                           
        \--------------------------------------------------------------------------------------------------------------------------
         0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 6 6 66
           . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
           1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 0 1 23
           0 0 1 1 2 2 2 3 3 4 4 4 5 5 6 6 7 7 7 8 8 9 9 9 0 0 1 1 1 2 2 3 3 4 4 4 5 5 6 6 6 7 7 8 8 9 9 9 0 0 1 1 1 2 2 3 3 3 4 4
           4 8 2 6 0 4 8 3 7 1 5 9 3 7 1 6 0 4 8 2 6 0 5 9 3 7 1 5 9 3 8 2 6 0 4 8 2 7 1 5 9 3 7 1 5 0 4 8 2 6 0 4 9 3 7 1 5 9 3 7
           1 2 3 5 6 7 9 0 1 3 4 5 7 8 9 1 2 3 5 6 7 9 0 1 3 4 5 7 8 9 1 2 3 5 6 7 8 0 1 2 4 5 6 8 9 0 2 3 4 6 7 8 0 1 2 4 5 6 8 9
           3 6 9 2 6 9 2 5 9 2 5 9 2 5 8 2 5 8 1 4 8 1 4 7 1 4 7   3 7   3 6   3 6 9 2 6 9 2 5 9 2 5 8 1 5 8 1 4 8 1 4 7   4 7   3
           2 4 7 9 1 3 6 8                                                                                                         

Offline amylase

  • Friend
  • **
  • Posts: 73
    • View Profile
    • gpLand
Re: graph command
« Reply #1 on: April 05, 2008, 06:14:35 AM »
Wow good job. What a nostalgic graph. Thanks for sharing!