Guest User

Taxi interpreter: fixed

a guest
Oct 3rd, 2018
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 36.04 KB | None | 0 0
  1. //--------------------------------------------
  2. // TAXI PROGRAMMING LANGUAGE
  3. // by: BigZaphod [email protected]
  4. // http://www.bigzaphod.org/taxi/
  5. //
  6. // License: Public Domain
  7. //--------------------------------------------
  8. // Version 1.7 (with some changes)
  9. // + 1.7 changes:
  10. //       applied patch from Nick Turner which
  11. //       added in some debugging support and
  12. //       fixed a string quoting issue
  13. //--------------------------------------------
  14.  
  15.  
  16. #include <stdarg.h>
  17. #include <stdlib.h>
  18. #include <time.h>
  19. #include <cmath>
  20. #include <iostream>
  21. #include <fstream>
  22. #include <string>
  23. #include <map>
  24. #include <list>
  25. #include <vector>
  26. #include <sstream>
  27. #include <algorithm>
  28. #include <set>
  29. using namespace std;
  30.  
  31. #ifdef WIN32
  32.     #define random rand
  33.     #define srandom srand
  34. #endif
  35.  
  36. int debuglevel = 0;
  37.  
  38. void error( const char* msg )
  39. {
  40.     cout.flush();
  41.     cerr << "error: " << msg << endl;
  42.     exit( -1 );
  43. }
  44.  
  45. template <class T>
  46. string toString( const T& val )
  47. {
  48.         ostringstream buffer;
  49.         buffer << val;
  50.         return buffer.str();
  51. }
  52.  
  53. string to_lower( string s )
  54. {
  55.         transform( s.begin(), s.end(), s.begin(), (int(*)(int))tolower );
  56.         return s;
  57. }
  58.  
  59. string to_upper( string s )
  60. {
  61.         transform( s.begin(), s.end(), s.begin(), (int(*)(int))toupper );
  62.         return s;
  63. }
  64.  
  65. string trim( const string& s )
  66. {
  67.         string r = s;
  68.         r.erase( 0, r.find_first_not_of(" \r\n\t") );
  69.         r = r.substr( 0, 1+r.find_last_not_of(" \r\n\t") );
  70.         return r;
  71. }
  72.  
  73. typedef enum { D_WEST, D_NORTH, D_SOUTH, D_EAST } nesw_t;
  74. typedef enum { D_LEFT, D_RIGHT } rel_dir_t;
  75.  
  76. class taxi_value
  77. {
  78.     typedef enum { T_NUM, T_STR } value_type;
  79.  
  80.     value_type  val_type;
  81.     double      num_val;
  82.     string      str_val;
  83.  
  84. public:
  85.     taxi_value()                { clear(); }
  86.     taxi_value( double n )          { set_num(n); }
  87.     taxi_value( const string& s )       { set_str(s); }
  88.     taxi_value( const taxi_value& v )   { *this = v; }
  89.  
  90.     taxi_value& operator=( const taxi_value& v ) {
  91.         val_type = v.val_type;
  92.         num_val = v.num_val;
  93.         str_val = v.str_val;
  94.         return *this;
  95.     }
  96.  
  97.     void clear()            { val_type = T_NUM; num_val = 0; str_val.clear(); }
  98.     void set_num( double n )    { val_type = T_NUM; num_val = n; }
  99.     void set_str( const string& s ) { val_type = T_STR; str_val = s; }
  100.  
  101.     bool is_number() const      { return val_type == T_NUM; }
  102.     bool is_string() const      { return val_type == T_STR; }
  103.  
  104.     double num() const      { return num_val; }
  105.     string str() const      { return str_val; }
  106. };
  107.  
  108. typedef list<taxi_value> value_list;
  109.  
  110. class location;
  111. class taxi;
  112. class node;
  113. class location;
  114.  
  115. class passenger_t
  116. {
  117. public:
  118.     passenger_t() : dest(NULL), distance_traveled(0) {}
  119.     passenger_t( const taxi_value& v, location* d ) : dest(d), distance_traveled(0), value(v) {}
  120.     passenger_t( const passenger_t& p ) { *this = p; }
  121.     passenger_t& operator=( const passenger_t& p ) {
  122.         dest = p.dest;
  123.         value = p.value;
  124.         distance_traveled = p.distance_traveled;
  125.         return *this;
  126.     }
  127.  
  128.     location* dest;
  129.     double distance_traveled;
  130.     taxi_value value;
  131. };
  132. typedef list<passenger_t> passenger_list;
  133.  
  134.  
  135. class taxi
  136. {
  137. public:
  138.     passenger_list passengers;
  139.     nesw_t direction;
  140.     node* current_node;
  141.     location* current_location;
  142.     node* next_node;
  143.     node* prev_node;
  144.     const double pixels_per_mile;
  145.     const double max_gas;
  146.     double gas;
  147.     double gas_usage;
  148.     double credits;
  149.     double fare;
  150.     double miles_driven;
  151.  
  152.     taxi( location* start_from, double ppm, double max_gas_, double gas_, double gas_usage_, double credits_, double fare_ );
  153.     void pickup_passenger( location* whereto );
  154.     void passenger_pays( passenger_t& p );
  155.  
  156.     void set_direction( nesw_t dir );
  157.     void take_xth_turn( int num, rel_dir_t dir );
  158.     void drive_to( location* to );
  159.  
  160. private:
  161.     void drive();
  162.     void turn( rel_dir_t dir ) {
  163.         if( direction == D_WEST ) direction=(dir==D_LEFT)?  D_SOUTH: D_NORTH;
  164.         else if( direction == D_EAST ) direction=(dir==D_LEFT)? D_NORTH: D_SOUTH;
  165.         else if( direction == D_NORTH ) direction=(dir==D_LEFT)?D_WEST: D_EAST;
  166.         else if( direction == D_SOUTH) direction=(dir==D_LEFT)? D_EAST: D_WEST;
  167.     }
  168. };
  169.  
  170. class incoming_list
  171. {
  172.     taxi& car;
  173.     passenger_list incoming;
  174.  
  175. public:
  176.     incoming_list( taxi& c, location* dest ) : car(c) {
  177.         for( passenger_list::iterator i=car.passengers.begin(); i!=car.passengers.end(); ) {
  178.             if( i->dest == dest ) {
  179.                 incoming.push_back(*i);
  180.                 i = car.passengers.erase( i );
  181.             } else {
  182.                 i++;
  183.             }
  184.         }
  185.     }
  186.  
  187.     int size() const    { return incoming.size(); }
  188.     bool empty() const  { return incoming.empty(); }
  189.  
  190.     taxi_value next() {
  191.         if( empty() )
  192.             error( "cannot read incoming list" );
  193.  
  194.         taxi_value r = incoming.front().value;
  195.         car.passenger_pays( incoming.front() );
  196.         incoming.pop_front();
  197.         return r;
  198.     }
  199.  
  200.     void update_taxi()  { car.passengers.splice( car.passengers.end(), incoming ); incoming.clear(); }
  201. };
  202.  
  203. class node
  204. {
  205. public:
  206.     int x;
  207.     int y;
  208.  
  209.     typedef list< pair<node*,node*> > neighbor_list;
  210.     neighbor_list neighbors;
  211.  
  212.     node( int x_=0, int y_=0 ) { position( x_, y_ ); }
  213.     void position( int x_, int y_ ) { x=x_; y=y_; }
  214.  
  215.     static void street( int num_nodes, ... ) {
  216.         if( num_nodes < 2 )
  217.             return;
  218.         node* p = NULL;
  219.         va_list args;
  220.         va_start( args, num_nodes );
  221.         while( num_nodes-- ) {
  222.             pair<node*,node*> e;
  223.             node* n = va_arg( args, node* );
  224.             if( p ) {
  225.                 p->neighbors.back().second = n;
  226.                 e.first = p;
  227.                 e.second = NULL;
  228.             } else {
  229.                 e.first = NULL;
  230.                 e.second = NULL;
  231.             }
  232.             n->neighbors.push_back( e );
  233.             p = n;
  234.         }
  235.         va_end( args );
  236.     }
  237.  
  238.     bool is_intersection() const { return neighbors.size() > 1; }
  239.  
  240.     node* get_straight_path( node* from ) {
  241.         for( neighbor_list::iterator i=neighbors.begin(); i!=neighbors.end(); i++ ) {
  242.             if( i->first == from ) return i->second;
  243.             else if( i->second == from ) return i->first;
  244.         }
  245.         return NULL;
  246.     }
  247.  
  248.     node* get( nesw_t dir, node* prev=NULL ) {
  249.         for( neighbor_list::iterator i=neighbors.begin(); i!=neighbors.end(); i++ ) {
  250.             if( !prev || (i->first != prev && i->second != prev) ) {
  251.                 for( int z=0; z<2; z++ ) {
  252.                     node* n = (z==0)? i->first: i->second;
  253.                     if( !n ) continue;
  254.                     bool b = false;
  255.                     switch( dir ) {
  256.                     case D_NORTH:   b = ( n->y < y );   break;
  257.                     case D_SOUTH:   b = ( n->y > y );   break;
  258.                     case D_EAST:    b = ( n->x > x );   break;
  259.                     case D_WEST:    b = ( n->x < x );   break;
  260.                     }
  261.                     if( b ) return n;
  262.                 }
  263.             }
  264.         }
  265.  
  266.         return NULL;
  267.     }
  268.  
  269.     double dist_to( node* n ) {
  270.         double a = fabs( (double)(x - n->x) );
  271.         double b = fabs( (double)(y - n->y) );
  272.         a *= a;
  273.         b *= b;
  274.         return sqrt( a + b );
  275.     }
  276.  
  277.     node* can_turn( rel_dir_t dir, node* prev ) {
  278.         for( neighbor_list::iterator i=neighbors.begin(); i!=neighbors.end(); i++ ) {
  279.             if( i->first != prev && i->second != prev ) {
  280.                 for( int z=0; z<2; z++ ) {
  281.                     node* n = (z==0)? i->first: i->second;
  282.                     if( !n ) continue;
  283.                     int r = ((x - prev->x)*(n->y - prev->y)) + ((y - prev->y)*(prev->x - n->x));
  284.                     switch( dir ) {
  285.                     case D_LEFT:    if( r < 0 ) return n;   break;
  286.                     case D_RIGHT:   if( r > 0 ) return n;   break;
  287.                     }
  288.                 }
  289.             }
  290.         }
  291.         return NULL;
  292.     }
  293. };
  294.  
  295.  
  296. typedef enum { B_FIFO, B_LIFO, B_RANDOM } buffer_type;
  297. typedef void (*arrival_func)( location&, incoming_list& );
  298. typedef void (*create_outgoing_passenger_func)( location& );
  299. typedef void (*create_waiting_passenger_func)( location&, const char* );
  300.  
  301. class location : public node
  302. {
  303.     value_list outgoing;
  304.  
  305. public:
  306.     location() : buffer_order(B_FIFO)
  307.         , max_passengers(-1)    // infinite
  308.         , arrival_function(NULL)
  309.         , create_outgoing_passenger_function(NULL)
  310.         , create_waiting_passenger_function(NULL)
  311.         , passengers_pay(true)
  312.         , gas_price(0) {}
  313.  
  314.     buffer_type buffer_order;
  315.     int max_passengers;
  316.     arrival_func arrival_function;
  317.     create_outgoing_passenger_func create_outgoing_passenger_function;
  318.     create_waiting_passenger_func create_waiting_passenger_function;
  319.     bool passengers_pay;
  320.     double gas_price;
  321.  
  322.     void add_outgoing_passenger( const taxi_value& v ) {
  323.         if( max_passengers == 0 || (int)outgoing.size() == max_passengers )
  324.             error( "too many outgoing passengers" );
  325.  
  326.         switch( buffer_order ) {
  327.         case B_FIFO:    outgoing.push_back(v); break;
  328.         case B_LIFO:    outgoing.push_front(v); break;
  329.         case B_RANDOM:
  330.             {
  331.                 value_list::iterator i=outgoing.begin();
  332.                 size_t ran = size_t((1+outgoing.size()) * (random() / (RAND_MAX+1.0)));
  333.                 for( ; ran; ran--, i++ );
  334.                 outgoing.insert( i, v );
  335.             }
  336.         }
  337.     }
  338.  
  339.     void arrival( incoming_list& incoming ) {
  340.         if (debuglevel>=2) {
  341.             cout  << "outgoing:";
  342.             for( value_list::iterator i=outgoing.begin(); i!=outgoing.end(); i++ ) {
  343.                 cout << " [";
  344.                 if( i->is_number() )
  345.                     cout << i->num();
  346.                 else
  347.                     cout << i->str();
  348.                 cout << "]";
  349.             }
  350.             cout << endl;
  351.         }
  352.  
  353.         if( arrival_function ) {
  354.             (*arrival_function)( *this, incoming );
  355.         } else {
  356.             while( !incoming.empty() && (max_passengers == -1 || (int)outgoing.size()<max_passengers) ) {
  357.                 add_outgoing_passenger( incoming.next() );
  358.             }
  359.         }
  360.     }
  361.  
  362.     int outgoing_passengers() const { return outgoing.size(); }
  363.     taxi_value get_outgoing_passenger() {
  364.         if( max_passengers == 0 )
  365.             error( "no outgoing passengers allowed at this location" );
  366.  
  367.         if( outgoing_passengers() == 0 && create_outgoing_passenger_function )
  368.             (*create_outgoing_passenger_function)( *this );
  369.  
  370.         if( outgoing_passengers() == 0 )
  371.             error( "no outgoing passengers found" );
  372.  
  373.         taxi_value r = outgoing.front();
  374.         outgoing.pop_front();
  375.         return r;
  376.     }
  377.  
  378.     void waiting( const char* input ) {
  379.         if( max_passengers == 0 )
  380.             error( "no outgoing passengers allowed at this location" );
  381.         if( !create_waiting_passenger_function )
  382.             error( "passengers cannot be made to wait here" );
  383.         if( max_passengers != -1 && outgoing_passengers() == max_passengers )
  384.             error( "too many passengers already waiting here" );
  385.         (*create_waiting_passenger_function)( *this, input );
  386.     }
  387. };
  388.  
  389. taxi::taxi( location* start_from, double ppm, double max_gas_, double gas_, double gas_usage_, double credits_, double fare_ )
  390.     : direction(D_NORTH), current_node(dynamic_cast<node*>(start_from))
  391.     , current_location(start_from), next_node(NULL), prev_node(NULL)
  392.     , pixels_per_mile(ppm)
  393.     , max_gas(max_gas_), gas(gas_), gas_usage(gas_usage_), credits(credits_), fare(fare_)
  394.     , miles_driven(0)
  395. {
  396. }
  397.  
  398. void taxi::pickup_passenger( location* whereto )
  399. {
  400.     if( !current_location )
  401.         error( "not at a location where passengers can even be picked up from" );
  402.  
  403.     if( passengers.size() == 3 )
  404.         error( "too many passengers in the taxi" );
  405.  
  406.     passengers.push_back( passenger_t(current_location->get_outgoing_passenger(),whereto) );
  407. }
  408.  
  409. void taxi::drive() {
  410.     if( !next_node )
  411.         error( "cannot drive in that direction" );
  412.     node* t = next_node->get_straight_path( current_node );
  413.     prev_node = current_node;
  414.     current_node = next_node;
  415.     next_node = t;
  416.     current_location = NULL;
  417.  
  418.     // accounting...
  419.     double dist = prev_node->dist_to( current_node ) / pixels_per_mile;
  420.     miles_driven += dist;
  421.     gas -= (1/gas_usage) * dist;
  422.     if( gas < 0 )
  423.         error( "out of gas" );
  424.  
  425.     for( list<passenger_t>::iterator i=passengers.begin(); i!=passengers.end(); i++ )
  426.         i->distance_traveled += dist;
  427. }
  428.  
  429. void taxi::set_direction( nesw_t dir )
  430. {
  431.     direction = dir;
  432.     next_node = current_node->get( direction );
  433. }
  434.  
  435. void taxi::take_xth_turn( int num, rel_dir_t dir )
  436. {
  437.     node* t = NULL;
  438.     for( ; num>0; num-- ) {
  439.         drive();
  440.         while( !(t=current_node->can_turn(dir,prev_node)) )
  441.             drive();
  442.     }
  443.     next_node = t;
  444.     turn( dir );
  445. }
  446.  
  447. void taxi::drive_to( location* to )
  448. {
  449.     node* n = dynamic_cast<node*>(to);
  450.     while( current_node != n )
  451.         drive();
  452.     current_location = to;
  453.     incoming_list il( *this, current_location );
  454.     current_location->arrival( il );
  455.     il.update_taxi();
  456.     if( current_location->gas_price ) {
  457.         double gallons = min( max_gas-gas, credits/current_location->gas_price );
  458.         gas += gallons;
  459.         credits -= gallons * current_location->gas_price;
  460.         if (debuglevel >= 1) cout << "You now have " << gas << " gas and " << credits << " credits." << endl;
  461.     }
  462. }
  463.  
  464. void taxi::passenger_pays( passenger_t& p )
  465. {
  466.     if( p.dest->passengers_pay ) {
  467.         credits += p.distance_traveled * fare;
  468.     }
  469. }
  470.  
  471. void taxi_garage( location& here, incoming_list& incoming )
  472. {
  473.     cout << endl << "The taxi is back in the garage.  Program complete." << endl;
  474.     exit( 0 );
  475. }
  476.  
  477. void post_office_arrive( location& here, incoming_list& incoming )
  478. {
  479.     while( !incoming.empty() ) {
  480.         taxi_value v = incoming.next();
  481.         if( !v.is_string() )
  482.             error( "post office cannot handle non-string values" );
  483.         cout << v.str();
  484.     }
  485. }
  486.  
  487. void post_office_create( location& here )
  488. {
  489.     if (debuglevel >= 1) cout << "Waiting for input: ";
  490.     string line;
  491.     getline( cin, line );
  492.     here.add_outgoing_passenger( taxi_value(line) );
  493. }
  494.  
  495. void heisenbergs( location& here )
  496. {
  497.     double r = random();
  498.     here.add_outgoing_passenger( taxi_value(r) );
  499. }
  500.  
  501. void starchild_numerology( location& here, const char* input )
  502. {
  503.     if (debuglevel >= 1) cout << input << " is waiting at Starchild Numerology" << endl;
  504.     here.add_outgoing_passenger( taxi_value(strtod(input,NULL)) );
  505. }
  506.  
  507. void writers_depot( location& here, const char* input )
  508. {
  509.     string in;
  510.     bool slash = false;
  511.     for( ; *input; input++ ) {
  512.         if( *input == '\\' && !slash ) {
  513.             slash = true;
  514.         } else if( slash ) {
  515.             slash = false; // ensure escaped characters in the middle of a string work properly
  516.             switch( *input ) {
  517.             case '\\':  in.append( "\\" );  break;
  518.             case 'n':   in.append( "\n" );  break;
  519.             case 'r':   in.append( "\r" );  break;
  520.             case 't':   in.append( "\t" );  break;
  521.             default:    break;
  522.             }
  523.         } else {
  524.             in.append( input, 1 );
  525.         }
  526.     }
  527.     if (debuglevel >= 1) cout << "\"" << in << "\" is waiting at the Writer's Depot" << endl;
  528.     here.add_outgoing_passenger( taxi_value(in) );
  529. }
  530.  
  531. void the_babelfishery( location& here, incoming_list& incoming )
  532. {
  533.     while( !incoming.empty() ) {
  534.         taxi_value v = incoming.next();
  535.         if( v.is_number() ) {
  536.             here.add_outgoing_passenger( taxi_value(toString(v.num())) );
  537.         } else if( v.is_string() ) {
  538.             here.add_outgoing_passenger( taxi_value(strtod(v.str().c_str(),NULL)) );
  539.         } else error( "unknown type cannot be translated" );
  540.     }
  541. }
  542.  
  543. void charboil_grill( location& here, incoming_list& incoming )
  544. {
  545.     while( !incoming.empty() ) {
  546.         taxi_value v = incoming.next();
  547.         if( v.is_string() && v.str().length() > 1 )
  548.             error( "charboil grill can only handle strings of length 1" );
  549.         if( v.is_string() )
  550.             here.add_outgoing_passenger( taxi_value((double)v.str()[0]) );
  551.         else if( v.is_number() )
  552.             here.add_outgoing_passenger( taxi_value( string(1,(char)v.num()) ) );
  553.         else
  554.             error( "unknown data type" );
  555.     }
  556. }
  557.  
  558. void addition_alley( location& here, incoming_list& incoming )
  559. {
  560.     if( !incoming.empty() ) {
  561.         double ret = 0;
  562.  
  563.         while( !incoming.empty() ) {
  564.             taxi_value v = incoming.next();
  565.             if( !v.is_number() )
  566.                 error( "requires a numerical value" );
  567.             ret += v.num();
  568.         }
  569.  
  570.         here.add_outgoing_passenger( taxi_value(ret) );
  571.     }
  572. }
  573.  
  574. void multiplication_station( location& here, incoming_list& incoming )
  575. {
  576.     if( !incoming.empty() ) {
  577.         double ret = 1;
  578.  
  579.         while( !incoming.empty() ) {
  580.             taxi_value v = incoming.next();
  581.             if( !v.is_number() )
  582.                 error( "requires a numerical value" );
  583.             ret *= v.num();
  584.         }
  585.  
  586.         here.add_outgoing_passenger( taxi_value(ret) );
  587.     }
  588. }
  589.  
  590. void divide_and_conquer( location& here, incoming_list& incoming )
  591. {
  592.     if( !incoming.empty() ) {
  593.         taxi_value v = incoming.next();
  594.         if( !v.is_number() )
  595.             error( "requires a numerical value" );
  596.         double ret = v.num();
  597.  
  598.         while( !incoming.empty() ) {
  599.             v = incoming.next();
  600.             if( !v.is_number() )
  601.                 error( "requires a numerical value" );
  602.             if( v.num() == 0 )
  603.                 error( "divide by zero" );
  604.             ret /= v.num();
  605.         }
  606.  
  607.         here.add_outgoing_passenger( taxi_value(ret) );
  608.     }
  609. }
  610.  
  611. void whats_the_difference( location& here, incoming_list& incoming )
  612. {
  613.     if( !incoming.empty() ) {
  614.         taxi_value v = incoming.next();
  615.         if( !v.is_number() )
  616.             error( "requires a numerical value" );
  617.         double ret = v.num();
  618.  
  619.         while( !incoming.empty() ) {
  620.             v = incoming.next();
  621.             if( !v.is_number() )
  622.                 error( "requires a numerical value" );
  623.             ret -= v.num();
  624.         }
  625.  
  626.         here.add_outgoing_passenger( taxi_value(ret) );
  627.     }
  628. }
  629.  
  630. void konkats( location& here, incoming_list& incoming )
  631. {
  632.     if( !incoming.empty() ) {
  633.         string ret;
  634.  
  635.         while( !incoming.empty() ) {
  636.             taxi_value v = incoming.next();
  637.             if( !v.is_string() )
  638.                 error( "requires a string value" );
  639.             ret.append( v.str() );
  640.         }
  641.  
  642.         here.add_outgoing_passenger( taxi_value(ret) );
  643.     }
  644. }
  645.  
  646. void magic_eight( location& here, incoming_list& incoming )
  647. {
  648.     if( incoming.size() < 2 )
  649.         error( "requires two passengers" );
  650.  
  651.     taxi_value v1 = incoming.next();
  652.     taxi_value v2 = incoming.next();
  653.  
  654.     if( !(v1.is_number() && v2.is_number()) )
  655.         error( "requires numerical values" );
  656.  
  657.     if( v1.num() < v2.num() )
  658.         here.add_outgoing_passenger( v1 );
  659. }
  660.  
  661. void collator_express( location& here, incoming_list& incoming )
  662. {
  663.     if( incoming.size() < 2 )
  664.         error( "requires two passengers" );
  665.  
  666.     taxi_value v1 = incoming.next();
  667.     taxi_value v2 = incoming.next();
  668.  
  669.     if( !(v1.is_string() && v2.is_string()) )
  670.         error( "requires string values" );
  671.  
  672.     if( v1.str() < v2.str() )
  673.         here.add_outgoing_passenger( v1 );
  674. }
  675.  
  676. void the_underground( location& here, incoming_list& incoming )
  677. {
  678.     if( !incoming.empty() ) {
  679.         taxi_value v1 = incoming.next();
  680.  
  681.         if( !(v1.is_number()) )
  682.             error( "requires a numerical value" );
  683.  
  684.         double val = v1.num() - 1;
  685.         if( val > 0 )
  686.             here.add_outgoing_passenger( taxi_value(val) );
  687.     }
  688. }
  689.  
  690. void riverview_bridge( location& here, incoming_list& incoming )
  691. {
  692.     // this trashes values from existence.  sleep with the fishies!
  693.     while( !incoming.empty() )
  694.         incoming.next();
  695. }
  696.  
  697. void auctioneer_school( location& here, incoming_list& incoming )
  698. {
  699.     while( !incoming.empty() ) {
  700.         taxi_value v = incoming.next();
  701.         if( !v.is_string() )
  702.             error( "requires a string value" );
  703.         here.add_outgoing_passenger( taxi_value(to_upper(v.str())) );
  704.     }
  705. }
  706.  
  707. void little_league_field( location& here, incoming_list& incoming )
  708. {
  709.     while( !incoming.empty() ) {
  710.         taxi_value v = incoming.next();
  711.         if( !v.is_string() )
  712.             error( "requires a string value" );
  713.         here.add_outgoing_passenger( taxi_value(to_lower(v.str())) );
  714.     }
  715. }
  716.  
  717. void toms_trims( location& here, incoming_list& incoming )
  718. {
  719.     while( !incoming.empty() ) {
  720.         taxi_value v = incoming.next();
  721.         if( !v.is_string() )
  722.             error( "requires a string value" );
  723.         here.add_outgoing_passenger( taxi_value(trim(v.str())) );
  724.     }
  725. }
  726.  
  727. void trunkers( location& here, incoming_list& incoming )
  728. {
  729.     while( !incoming.empty() ) {
  730.         taxi_value v = incoming.next();
  731.         if( !v.is_number() )
  732.             error( "requires a numerical value" );
  733.         here.add_outgoing_passenger( taxi_value((int)v.num()) );
  734.     }
  735. }
  736.  
  737. void rounders_pub( location& here, incoming_list& incoming )
  738. {
  739.     while( !incoming.empty() ) {
  740.         taxi_value v = incoming.next();
  741.         if( !v.is_number() )
  742.             error( "requires a numerical value" );
  743.         here.add_outgoing_passenger( taxi_value(round(v.num())) );
  744.     }
  745. }
  746.  
  747. void knots_landing( location& here, incoming_list& incoming )
  748. {
  749.     while( !incoming.empty() ) {
  750.         taxi_value v = incoming.next();
  751.         if( !v.is_number() )
  752.             error( "requires a numerical value" );
  753.         here.add_outgoing_passenger( taxi_value( (double)(!v.num()) ) );
  754.     }
  755. }
  756.  
  757. void cyclone( location& here, incoming_list& incoming )
  758. {
  759.     while( !incoming.empty() ) {
  760.         taxi_value v = incoming.next();
  761.         here.add_outgoing_passenger( v );
  762.         here.add_outgoing_passenger( v );
  763.     }
  764. }
  765.  
  766. void chop_suey( location& here, incoming_list& incoming )
  767. {
  768.     while( !incoming.empty() ) {
  769.         taxi_value v = incoming.next();
  770.         if( !v.is_string() )
  771.             error( "requires a string value" );
  772.         for( size_t i=0; i<v.str().length(); i++ )
  773.             here.add_outgoing_passenger( taxi_value( string(1,v.str()[i]) ) );
  774.     }
  775. }
  776.  
  777. void crime_lab( location& here, incoming_list& incoming )
  778. {
  779.     if( incoming.size() < 2 ) {
  780.         error( "requires at least 2 passengers" );
  781.         return;
  782.     }
  783.  
  784.     taxi_value v = incoming.next();
  785.     if( !v.is_string() ) {
  786.         error( "requires a string value" );
  787.         return;
  788.     }
  789.  
  790.     do {
  791.         taxi_value tmp = incoming.next();
  792.         if( !tmp.is_string() ) {
  793.             error( "requires a string value" );
  794.             return;
  795.         }
  796.         if( v.str() != tmp.str() )
  797.             return;
  798.     } while( !incoming.empty() );
  799.  
  800.     here.add_outgoing_passenger( v );
  801. }
  802.  
  803. void equals_corner( location& here, incoming_list& incoming )
  804. {
  805.     if( incoming.size() < 2 ) {
  806.         error( "requires at least 2 passengers" );
  807.         return;
  808.     }
  809.     taxi_value v = incoming.next();
  810.     if( !v.is_number() ) {
  811.         error( "requires a numerical value" );
  812.         return;
  813.     }
  814.  
  815.     do {
  816.         taxi_value tmp = incoming.next();
  817.         if( !tmp.is_number() ) {
  818.             error( "requires a numerical value" );
  819.             return;
  820.         }
  821.         if( v.num() != tmp.num() )
  822.             return;
  823.     } while( !incoming.empty() );
  824.  
  825.     here.add_outgoing_passenger( v );
  826. }
  827.  
  828. class road_map
  829. {
  830.     map<string,location> dest;
  831.     map<unsigned int, node*> inter;
  832.     map<unsigned int, node*> corner;
  833.  
  834. public:
  835.     road_map() {
  836.         // setup the intersections
  837.         inter[1] = new node( 424, 145 );
  838.         inter[2] = new node( 596, 138 );
  839.         inter[3] = new node( 1120, 115 );
  840.         inter[4] = new node( 1285, 112 );
  841.         inter[5] = new node( 1370, 108 );
  842.         inter[6] = new node( 1295, 84 );
  843.         inter[7] = new node( 1094, 78 );
  844.         inter[8] = new node( 355, 222 );
  845.         inter[9] = new node( 215, 376 );
  846.         inter[10]= new node( 482, 468 );
  847.         inter[11]= new node( 379, 638 );
  848.         inter[12]= new node( 246, 529 );
  849.         inter[13]= new node( 291, 783 );
  850.         inter[14]= new node( 209, 916 );
  851.         inter[15]= new node( 501, 910 );
  852.         inter[16]= new node( 50, 639 );
  853.         inter[17]= new node( 739, 557 );
  854.         inter[18]= new node( 702, 374 );
  855.         inter[19]= new node( 875, 740 );
  856.         inter[20]= new node( 991, 599 );
  857.         inter[21]= new node( 1003, 825 );
  858.         inter[22]= new node( 1241, 963 );
  859.         inter[23]= new node( 1155, 709 );
  860.         inter[24]= new node( 1382, 716 );
  861.         inter[25]= new node( 1118, 683 );
  862.         inter[26]= new node( 1132, 634 );
  863.         inter[27]= new node( 1437, 617 );
  864.         inter[28]= new node( 1171, 503 );
  865.         inter[29]= new node( 1061, 407 );
  866.         inter[30]= new node( 1061, 445 );
  867.         inter[31]= new node( 1197, 414 );
  868.         inter[32]= new node( 1227, 313 );
  869.         inter[33]= new node( 1372, 314 );
  870.         inter[34]= new node( 1160, 920 );
  871.  
  872.         // setup the corners
  873.         corner[1] = new node( 510, 52 );
  874.         corner[2] = new node( 108, 492 );
  875.         corner[3] = new node( 682, 442 );
  876.         corner[4] = new node( 818, 710 );
  877.         corner[5] = new node( 1106, 724 );
  878.         corner[6] = new node( 1181, 847 );
  879.  
  880.         // configure destinations
  881.         dest["Taxi Garage"].arrival_function = &taxi_garage;
  882.         dest["Taxi Garage"].position( 1246, 639 );
  883.  
  884.         dest["Post Office"].arrival_function = &post_office_arrive;
  885.         dest["Post Office"].create_outgoing_passenger_function = &post_office_create;
  886.         dest["Post Office"].position( 910, 695 );
  887.  
  888.         dest["Heisenberg\'s"].create_outgoing_passenger_function = &heisenbergs;
  889.         dest["Heisenberg\'s"].position( 1372, 237 );
  890.  
  891.         dest["Starchild Numerology"].create_waiting_passenger_function = &starchild_numerology;
  892.         dest["Starchild Numerology"].position( 278, 917 );
  893.  
  894.         dest["Writer\'s Depot"].create_waiting_passenger_function = &writers_depot;
  895.         dest["Writer\'s Depot"].position( 164, 433 );;
  896.  
  897.         dest["The Babelfishery"].arrival_function = &the_babelfishery;
  898.         dest["The Babelfishery"].position( 949, 879 );
  899.  
  900.         dest["Charboil Grill"].arrival_function = &charboil_grill;
  901.         dest["Charboil Grill"].position( 152, 702 );
  902.  
  903.         dest["Addition Alley"].arrival_function = &addition_alley;
  904.         dest["Addition Alley"].position( 652, 211 );
  905.  
  906.         dest["Multiplication Station"].arrival_function = &multiplication_station;
  907.         dest["Multiplication Station"].position( 1286, 888 );
  908.  
  909.         dest["Divide and Conquer"].arrival_function = &divide_and_conquer;
  910.         dest["Divide and Conquer"].position( 1117, 311 );
  911.  
  912.         dest["What\'s The Difference"].arrival_function = &whats_the_difference;
  913.         dest["What\'s The Difference"].position( 176, 153 );;
  914.  
  915.         dest["KonKat\'s"].arrival_function = &konkats;
  916.         dest["KonKat\'s"].position( 1262, 195 );
  917.  
  918.         dest["Magic Eight"].arrival_function = &magic_eight;
  919.         dest["Magic Eight"].position( 797, 666 );
  920.  
  921.         dest["Riverview Bridge"].arrival_function = &riverview_bridge;
  922.         dest["Riverview Bridge"].passengers_pay = false;
  923.         dest["Riverview Bridge"].position( 888, 127 );
  924.  
  925.         dest["Sunny Skies Park"].buffer_order = B_FIFO;
  926.         dest["Sunny Skies Park"].position( 456, 412 );
  927.  
  928.         dest["Joyless Park"].buffer_order = B_FIFO;
  929.         dest["Joyless Park"].position( 1361, 424 );
  930.  
  931.         dest["Narrow Path Park"].buffer_order = B_LIFO;
  932.         dest["Narrow Path Park"].position( 1162, 78 );
  933.  
  934.         dest["Auctioneer School"].arrival_function = &auctioneer_school;
  935.         dest["Auctioneer School"].position( 246, 856 );
  936.  
  937.         dest["Little League Field"].arrival_function = &little_league_field;
  938.         dest["Little League Field"].position( 1267, 711 );
  939.  
  940.         dest["Tom's Trims"].arrival_function = &toms_trims;
  941.         dest["Tom's Trims"].position( 951, 648 );
  942.  
  943.         dest["Trunkers"].arrival_function = &trunkers;
  944.         dest["Trunkers"].position( 692, 543 );
  945.  
  946.         dest["Rounders Pub"].arrival_function = &rounders_pub;
  947.         dest["Rounders Pub"].position( 1063, 482 );
  948.  
  949.         dest["Fueler Up"].gas_price = 1.92;
  950.         dest["Fueler Up"].max_passengers = 0;
  951.         dest["Fueler Up"].position( 1155, 557 );
  952.  
  953.         dest["Go More"].gas_price = 1.75;
  954.         dest["Go More"].max_passengers = 0;
  955.         dest["Go More"].position( 258, 764 );
  956.  
  957.         dest["Zoom Zoom"].gas_price = 1.45;
  958.         dest["Zoom Zoom"].max_passengers = 0;
  959.         dest["Zoom Zoom"].position( 546, 52 );
  960.  
  961.         dest["Knots Landing"].arrival_function = &knots_landing;
  962.         dest["Knots Landing"].position( 1426, 314 );
  963.  
  964.         dest["Bird\'s Bench"].max_passengers = 1;
  965.         dest["Bird\'s Bench"].position( 197, 653 );
  966.  
  967.         dest["Rob\'s Rest"].max_passengers = 1;
  968.         dest["Rob\'s Rest"].position( 323, 473 );
  969.  
  970.         dest["Firemouth Grill"].buffer_order = B_RANDOM;
  971.         dest["Firemouth Grill"].position( 770, 440 );
  972.  
  973.         dest["Cyclone"].arrival_function = &cyclone;
  974.         dest["Cyclone"].position( 272, 314 );
  975.  
  976.         dest["Chop Suey"].arrival_function = &chop_suey;
  977.         dest["Chop Suey"].position( 1374, 169 );
  978.  
  979.         dest["The Underground"].arrival_function = &the_underground;
  980.         dest["The Underground"].position( 1182, 462 );
  981.  
  982.         dest["Collator Express"].arrival_function = &collator_express;
  983.         dest["Collator Express"].position( 424, 351 );
  984.  
  985.         dest["Crime Lab"].arrival_function = &crime_lab;
  986.         dest["Crime Lab"].position( 1031, 796 );
  987.  
  988.         dest["Equal\'s Corner"].arrival_function = &equals_corner;
  989.         dest["Equal\'s Corner"].position( 210, 976 );
  990.  
  991.         // link the nodes together forming the map
  992.         node::street( 9, &dest["Zoom Zoom"], corner[1], inter[1], inter[8], &dest["Cyclone"], inter[9], &dest["Writer\'s Depot"], corner[2], inter[16] );
  993.         node::street( 7, &dest["What\'s The Difference"], inter[1], inter[2], &dest["Riverview Bridge"], inter[3], inter[4], inter[5] );
  994.         node::street( 2, inter[7], inter[3] );
  995.         node::street( 3, inter[7], &dest["Narrow Path Park"], inter[6] );
  996.         node::street( 2, inter[2], &dest["Addition Alley"] );
  997.         node::street( 4, inter[9], inter[10], &dest["Trunkers"], inter[17] );
  998.         node::street( 3, &dest["Rob\'s Rest"], inter[12], &dest["Bird\'s Bench"] );
  999.         node::street( 2, inter[12], inter[11] );
  1000.         node::street( 5, inter[16], &dest["Charboil Grill"], &dest["Go More"], inter[13], inter[15] );
  1001.         node::street( 9, inter[8], &dest["Collator Express"], &dest["Sunny Skies Park"], inter[10], inter[11], inter[13], &dest["Auctioneer School"], inter[14], &dest["Equal\'s Corner"] );
  1002.         node::street( 3, inter[14], &dest["Starchild Numerology"], inter[15] );
  1003.         node::street( 3, inter[29], inter[30], &dest["Rounders Pub"] );
  1004.         node::street( 3, inter[29], inter[31], &dest["Joyless Park"] );
  1005.         node::street( 2, inter[28], inter[27] );
  1006.         node::street( 4, inter[27], inter[24], &dest["Multiplication Station"], inter[22] );
  1007.         node::street( 3, inter[23], &dest["Little League Field"], inter[24] );
  1008.         node::street( 2, inter[26], &dest["Taxi Garage"] );
  1009.         node::street( 4, &dest["Divide and Conquer"], inter[32], inter[33], &dest["Knots Landing"] );
  1010.         node::street( 9, inter[18], corner[3], inter[17], &dest["Magic Eight"], corner[4], inter[19], inter[21], inter[34], inter[22] );
  1011.         node::street( 3, inter[23], corner[6], inter[34] );
  1012.         node::street( 5, inter[18], &dest["Firemouth Grill"], inter[20], inter[25], inter[23] );
  1013.         node::street( 4, inter[20], &dest["Tom's Trims"], &dest["Post Office"], inter[19] );
  1014.         node::street( 14, &dest["The Babelfishery"], inter[21], &dest["Crime Lab"], corner[5], inter[25], inter[26], &dest["Fueler Up"], inter[28], &dest["The Underground"], inter[31], inter[32], &dest["KonKat\'s"], inter[4], inter[6] );
  1015.         node::street( 4, inter[5], &dest["Chop Suey"], &dest["Heisenberg\'s"], inter[33] );
  1016.     }
  1017.  
  1018.     location* get_location( const string& name ) {
  1019.         if( !dest.count(name) )
  1020.             return NULL;
  1021.         return &dest[name];
  1022.     }
  1023. };
  1024.  
  1025. class program
  1026. {
  1027.     typedef enum { C_NONE, C_WAITING, C_GOTO, C_SWITCH, C_SWITCH_IF, C_PICKUP } command_t;
  1028.     typedef struct code_t_ {
  1029.         command_t cmd;
  1030.         string    loc;
  1031.         string    data;
  1032.         code_t_() : cmd(C_NONE) {}
  1033.         code_t_( const code_t_& c ) : cmd(c.cmd), loc(c.loc), data(c.data) {}
  1034.     } code_t;
  1035.     vector<code_t>     script;
  1036.     map<string,size_t> labels;
  1037.  
  1038. public:
  1039.     program( const string& filename ) {
  1040.         ifstream file( filename.c_str() );
  1041.         if( !file.is_open() )
  1042.             error( "could not open file" );
  1043.  
  1044.         string input;
  1045.         while( !file.eof() ) {
  1046.             string in;
  1047.             getline( file, in );
  1048.             input += in;
  1049.         }
  1050.  
  1051.         parse( input );
  1052.     }
  1053.  
  1054.     void parse( string& in ) {
  1055.         vector<string> tokens;
  1056.         while( !in.empty() ) {
  1057.             // skip spaces
  1058.             string::size_type e = in.find_first_not_of(" \t\r\n");
  1059.             if( e != string::npos )
  1060.                 in = in.substr( e );
  1061.  
  1062.             // check for labels
  1063.             // or check for normal statements (which end in a period)
  1064.             if( in[0] == '[' ) {
  1065.                 string::size_type p = in.find(']');
  1066.                 if( p != string::npos ) {
  1067.                     labels[in.substr(1,p-1)] = script.size();
  1068.                     in.erase( 0, p+1 );
  1069.                 } else {
  1070.                     error( "parse error: incomplete label" );
  1071.                     break;
  1072.                 }
  1073.             } else {
  1074.                 bool was_quoted = false;
  1075.                 string tok = get_token( in, was_quoted );
  1076.                 if( tok.empty() )
  1077.                     break;
  1078.                 if( tok == "." && !was_quoted ) {
  1079.                     compile( tokens );
  1080.                 } else {
  1081.                     tokens.push_back( tok );
  1082.                 }
  1083.             }
  1084.         }
  1085.  
  1086.         if( !tokens.empty() )
  1087.             error( "parse error: likely incomplete statement" );
  1088.     }
  1089.  
  1090.     void compile( vector<string>& in ) {
  1091.         code_t c;
  1092.         // is waiting at...
  1093.         if( in.size()>=5 && in[1]=="is" && in[2]=="waiting" && in[3]=="at" ) {
  1094.             c.cmd = C_WAITING;
  1095.             c.data = in[0];
  1096.             size_t s = (in[4]=="the")? 5: 4;
  1097.             for( size_t p=0; p+s < in.size(); p++ ) {
  1098.                 if( p ) c.loc += " ";
  1099.                 c.loc += in[p+s];
  1100.             }
  1101.         } else if( in.size()>=5 && in[0]=="Go" && in[1] == "to" ) {
  1102.             c.cmd = C_GOTO;
  1103.             size_t s = (in[2]=="the")? 3: 2;
  1104.             size_t p = 0;
  1105.             for( ; (p+s < in.size()) && (in[p+s] != ":"); p++ ) {
  1106.                 if( p ) c.loc += " ";
  1107.                 c.loc += in[p+s];
  1108.             }
  1109.             p++;    // skip the colon
  1110.             for( ; p+s < in.size(); p++ ) {
  1111.                 string str = in[p+s];
  1112.                 int n = strtol( str.c_str(), NULL, 10 );
  1113.                 if( n > 0 ) c.data += toString(n) + ":";
  1114.                 else if( !str.empty() ) c.data += to_upper(str)[0];
  1115.             }
  1116.         } else if( in.size()>=6 && in[0]=="Pickup" && (in[1]=="a" || in[1]=="another") && in[2]=="passenger" && in[3]=="going" && in[4]=="to" ) {
  1117.             c.cmd = C_PICKUP;
  1118.             size_t s = (in[5]=="the")? 6: 5;
  1119.             for( size_t p=0; p+s < in.size(); p++ ) {
  1120.                 if( p ) c.loc += " ";
  1121.                 c.loc += in[p+s];
  1122.             }
  1123.         } else if( in.size()>=4 && in[0]=="Switch" && in[1]=="to" && in[2]=="plan" ) {
  1124.             c.cmd = (in.size()>4)? C_SWITCH_IF: C_SWITCH;
  1125.             c.data = in[3];
  1126.         } else {
  1127.             string err = "parse error near:";
  1128.             for( size_t p=0; p<in.size(); p++ ) {
  1129.                 err += " ";
  1130.                 err += in[p];
  1131.             }
  1132.             error( err.c_str() );
  1133.         }
  1134.  
  1135.         if (debuglevel >= 2) cout << "debug: " << c.cmd << " \"" << c.data << "\" " << c.loc << endl;
  1136.         script.push_back( c );
  1137.         in.clear();
  1138.     }
  1139.  
  1140.     string get_token( string& in, bool& was_quoted ) {
  1141.         string r;
  1142.         string::size_type p;
  1143.         was_quoted = false;
  1144.         if( !in.empty() ) {
  1145.             char c = in[0];
  1146.             if( (c=='\'' || c=='"') && string::npos != (p=in.find(c,1)) ) {
  1147.                 r = in.substr( 1, p-1 );
  1148.                 in.erase( 0, r.size()+2 );
  1149.                 was_quoted = true;
  1150.             } else if( c == '.' || c == ':' ) {
  1151.                 r = c;
  1152.                 in.erase( 0, 1 );
  1153.             } else {
  1154.                 r = in.substr( 0, in.find_first_of(" \r\n\t.:") );
  1155.                 in.erase( 0, r.size() );
  1156.             }
  1157.         }
  1158.         return r;
  1159.     }
  1160.  
  1161.     void run( road_map& the_map ) {
  1162.         // 1 mile:          264 pixels
  1163.         // Max gallons of gas:      20
  1164.         // Starting gallons:        20
  1165.         // miles per gallon:        18
  1166.         // starting credits:        0
  1167.         // fare in credits per mile:    0.07
  1168.         taxi car( the_map.get_location("Taxi Garage"), 264, 20, 20, 18.0, 0, 0.07 );
  1169.  
  1170.         // now let's do it!
  1171.         for( size_t i=0; i<script.size(); i++ ) {
  1172.             code_t* c = &script[i];
  1173.             location* loc = the_map.get_location( c->loc );
  1174.  
  1175.             if (debuglevel >= 2) cout << "debug2: " << c->cmd << " \"" << c->data << "\" " << c->loc << " gas: " << car.gas << " credits: " << car.credits << " miles: " << car.miles_driven << endl;
  1176.  
  1177.             if( c->cmd == C_WAITING ) {
  1178.                 if( !loc ) {
  1179.                     error( "missing location for waiting statement" );
  1180.                     continue;
  1181.                 }
  1182.                 loc->waiting( c->data.c_str() );
  1183.             } else if( c->cmd == C_PICKUP ) {
  1184.                 if( !loc ) {
  1185.                     error( "missing destination in pickup statement" );
  1186.                     continue;
  1187.                 }
  1188.                 car.pickup_passenger( loc );
  1189.             } else if( c->cmd == C_GOTO ) {
  1190.                 if( !loc ) {
  1191.                     error( "missing destination in go to statement" );
  1192.                     continue;
  1193.                 }
  1194.                 if( c->data.empty() ) {
  1195.                     error( "invalid directions in go to statement" );
  1196.                     continue;
  1197.                 }
  1198.                 string path = c->data;
  1199.                 switch( path[0] ) {
  1200.                 case 'N':   car.set_direction( D_NORTH );   break;
  1201.                 case 'E':   car.set_direction( D_EAST );    break;
  1202.                 case 'S':   car.set_direction( D_SOUTH );   break;
  1203.                 case 'W':   car.set_direction( D_WEST );    break;
  1204.                 default: {
  1205.                         error( "invalid cardinal direction" );
  1206.                         continue;
  1207.                     }
  1208.                 }
  1209.                 path.erase( 0, 1 );
  1210.                 while( !path.empty() ) {
  1211.                     int turns = strtol( path.c_str(), NULL, 10 );
  1212.                     if( turns < 1 ) break;
  1213.                     string::size_type p = path.find(':');
  1214.                     if( p == string::npos || p+1 == path.size() ) break;
  1215.                     path = path.substr( p+1 );
  1216.                     rel_dir_t d = (path[0]=='L')? D_LEFT: D_RIGHT;
  1217.                     path.erase( 0, 1 );
  1218.                     car.take_xth_turn( turns, d );
  1219.                 }
  1220.                 if( !path.empty() ) {
  1221.                     error( "invalid directions in go to statement" );
  1222.                     continue;
  1223.                 }
  1224.                 if (debuglevel >= 1) cout << "Driving to " << c->loc << endl;
  1225.                 car.drive_to( loc );
  1226.             } else if( c->cmd == C_SWITCH ) {
  1227.                 if( c->data.empty() ) {
  1228.                     error( "missing label in switch command" );
  1229.                     continue;
  1230.                 }
  1231.                 if( !labels.count(c->data) ) {
  1232.                     error( "no such label" );
  1233.                     continue;
  1234.                 }
  1235.                 i = labels[c->data] - 1;
  1236.                 if (debuglevel >= 1) cout << "Switching to plan [" << c->data << "]" << endl;
  1237.             } else if( c->cmd == C_SWITCH_IF ) {
  1238.                 if( c->data.empty() ) {
  1239.                     error( "missing label in switch_if command" );
  1240.                     continue;
  1241.                 }
  1242.                 if( !labels.count(c->data) ) {
  1243.                     error( "no such label" );
  1244.                     continue;
  1245.                 }
  1246.                 if( !car.current_location ) {
  1247.                     error( "cannot switch, not at a passenger destination" );
  1248.                     continue;
  1249.                 }
  1250.                 if( !car.current_location->outgoing_passengers() ) {
  1251.                     i = labels[c->data] - 1;
  1252.                     if (debuglevel >= 1) cout << "Switching to plan [" << c->data << "] since nobody is waiting" << endl;
  1253.                 } else {
  1254.                     if (debuglevel >= 1) cout << "Not switching to plan [" << c->data << "] because someone is waiting" << endl;
  1255.                 }
  1256.             }
  1257.         }
  1258.     }
  1259. };
  1260.  
  1261. int main( int argc, char** argv )
  1262. {
  1263.     if( argc <= 1 ) {
  1264.         cerr << "usage: " << argv[0] << " script.txt [debuglevel]" << endl << endl;
  1265.         exit( -1 );
  1266.     }
  1267.  
  1268.     cout << "Welcome to Taxi!" << endl;
  1269.     cout << "Let the journey begin..." << endl << endl;
  1270.     srandom( time(NULL) );
  1271.  
  1272. //-------------------------------------------------------------------------------------------
  1273.  
  1274.     road_map the_map;
  1275.     if (argc == 3) debuglevel = atoi(argv[2]);
  1276.     program pgm( argv[1] );
  1277.     pgm.run( the_map );
  1278.  
  1279. //-------------------------------------------------------------------------------------------
  1280.  
  1281.     error( "The boss couldn't find your taxi in the garage.  You're fired!" );
  1282.     return -1;
  1283. }
Advertisement
Add Comment
Please, Sign In to add comment