#include <vector>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstddef>
#include <cassert>
#include <cmath>

struct pos {
  double x, y;
};

std::ostream &operator<<( std::ostream &os, const pos &p ) {
  os << "(" << p.x << ", " << p.y << ")";
  return os;
}

class color {
private:
  std::string name;
  explicit color( const std::string &s ): name(s) { }
public:
  std::string get_name( ) const { return name; }

  static const color BLACK;
  static const color RED;
  static const color WHITE;
};

const color color::BLACK( "black" );
const color color::RED( "red" );
const color color::WHITE( "blue" );

std::ostream &operator<<( std::ostream &os, const color &c ) {
  os << c.get_name( );
  return os;
}

class Shape {
private:
  virtual double area_impl( ) const = 0;
  virtual void print_impl( std::ostream &os ) const = 0;
public:
  double area( ) const { return area_impl( ); }
  void print( std::ostream &os ) const { print_impl( os ); }
};

std::ostream &operator<<( std::ostream &os, const Shape &s ) {
  s.print( os );
  return os;
}

class Triangle: public Shape {
private:
  pos p[3];
  color col;
  double area_impl( ) const {
    double x1 = std::fabs( p[1].x-p[0].x );
    double x2 = std::fabs( p[2].x-p[0].x );
    double y1 = std::fabs( p[1].y-p[0].y );
    double y2 = std::fabs( p[2].y-p[0].y );
    return std::fabs( x1*y2 - x2*y1 )/2.0;
  }
  void print_impl( std::ostream &os ) const {
    os << "color=" << col << ", p[0]=" << p[0] << ", p[1]=" << p[1] << ", p[2]=" << p[2];
  }
public:
  Triangle( const pos (&px)[3], const color &c ): col(c) {
    std::copy( px, px+3, p );
  }
};

class Circle: public Shape {
private:
  pos centre;
  double radius;
  color col;

  double area_impl( ) const {
    return radius * radius * 3.14;
  }
  void print_impl( std::ostream &os ) const {
    os << "color=" << col << ", centre=" << centre << ", radious=" << radius;
  }
public:
  Circle( const pos &c, double r, const color &cx ): centre(c), radius(r), col(cx) { }
};

// ------------------------------------------------------------

namespace {
  static const double x_min =   0.0; // excl.
  static const double x_max = 500.0; // excl.
  static const double y_min =   0.0; // excl.
  static const double y_max = 600.0; // excl.
  static const double r_min = x_min; // excl.
  static const double r_max = x_max; // excl.
  static const unsigned int n_min = 3; // incl.
  static const unsigned int n_max = 10; // incl.
}

double generate_random_double( double dmin, double dmax ) {
  double diff = dmax-dmin;
  double dr = static_cast<double>(std::rand( )) / RAND_MAX;
  if( dr == 0 ) return generate_random_double( dmin, dmax );
  return dmin + diff * dr;
}

color generate_random_color( ) {
  switch( std::rand( ) % 3 ) {
case 0: return color::BLACK;
case 1: return color::RED;
default: return color::WHITE;

  }
}

pos generate_random_pos( ) {
  pos p = { generate_random_double( x_min, x_max ), generate_random_double( y_min, y_max ) };
  return p;
}

Triangle *generate_random_triangle( ) {
  color c = generate_random_color( );
  pos p[3];
  for( int i = 0; i < sizeof(p)/sizeof(p[0]); ++i ) p[i] = generate_random_pos( );
  return new Triangle( p, c );
}

Circle *generate_random_circle( ) {
  color c = generate_random_color( );
  pos p = generate_random_pos( );
  double r = generate_random_double( r_min, r_max );
  return new Circle( p, r, c );
}

int main( ) {
  assert( n_min >= 2 );

  unsigned int n = std::rand( ) % ( n_max-n_min + 1 ) + n_min;

  std::vector<Shape*> v;
  v.push_back( generate_random_triangle( ));
  v.push_back( generate_random_circle( ));
  for( unsigned int i = 0; i < n-2; ++i ) {
    if( std::rand( ) & 1 ) {
      v.push_back( generate_random_triangle( ));
    }
    else {
      v.push_back( generate_random_circle( ));
    }
  }

  for( std::vector<Shape*>::iterator it = v.begin( ); it != v.end( ); ++it ) {
    std::cout << **it << std::endl;
  }

  std::vector<double> areas;
  std::transform( v.begin( ), v.end( ), std::back_inserter( areas ), std::mem_fun( &Shape::area ));
  std::cout << "sum_area = " << std::accumulate( areas.begin( ), areas.end( ), 0.0 ) << std::endl;

  for( std::vector<Shape*>::iterator it = v.begin( ); it != v.end( ); ++it ) {
    delete *it;
  }
}
