#include <iostream>

#include <iomanip>
#include <vector>

//#include <vec-simple.h>

#ifndef VECSIMPLE_H
#define VECSIMPLE_H
#ifndef VEC_H
#define VEC_H
#include <ostream>

#define ASSERT(n) (n);
using namespace std;

template <size_t Dim,typename Number> class vec
{

public:
    typedef Number NumberT;
    static const size_t DimN=Dim;
    Number items[Dim];

    vec()
    {

    }

    vec(const vec<Dim,Number >& src)
    {
        for(size_t i=Dim;i--;)
        {
            items[i]=src[i];
        }
    }

    vec(const Number* src)
    {
        for(size_t i=Dim;i--;)
        {
            items[i]=src[i];
        }
    }

    size_t maxPos() const
    {
        size_t ret=0;
        for(size_t i=Dim;--i;)
        {
            if(items[i]>items[ret])
            {
                ret=i;
            }
        }
        return(ret);
    }

    ostream& print(ostream& out) const
    {
        out<<"{ ";
        for(size_t i=0;i<Dim;i++)
        {
            out<<setw(6)<<items[i]<<" ";
        }
        out<<"} ";
        return(out);
    }
    static vec<Dim,Number > fill(const Number& val=0)
    {
        vec<Dim, Number> ret;
        for(size_t i=Dim;i--;)
        {
            ret[i]=val;
        }
        return(ret);
    }

    bool operator!=(const vec<Dim,Number>&v)
    {
        for(size_t i=Dim;i--;)
        {
            if(v[i]!=items[i])
            {
                return(true);
            }
        }
        return(false);
    }

    Number& operator [](size_t index)
    {
        return(items[index]);
    }
    const Number& operator [](size_t index) const
    {
        return(items[index]);
    }
};

template<size_t Dim,typename Number>vec<Dim,Number > operator+(vec<Dim,Number > lhs, const vec<Dim,Number >& rhs)
{
    for(size_t i=Dim;i--;)
    {
        lhs[i]+=rhs[i];
    }
    return(lhs);

}

template<size_t Dim,typename Number>vec<Dim,Number > operator-(vec<Dim,Number > lhs, const vec<Dim,Number >& rhs)
{
    for(size_t i=Dim;i--;)
    {
        lhs[i]-=rhs[i];
    }
    return(lhs);
}

template<size_t Dim,typename Number>vec<Dim,Number > operator*(vec<Dim,Number > lhs, const Number& rhs)
{
    for(size_t i=Dim;i--;)
    {
        lhs[i]*=rhs;
    }
    return(lhs);
}



template<size_t Dim,typename Number>vec<Dim,Number > operator/(vec<Dim,Number > lhs, const Number& rhs)
{
    for(size_t i=Dim;i--;)
    {
        lhs[i]/=rhs;
    }
    return(lhs);
}


template<size_t Dim,typename Number> Number operator*(const vec<Dim,Number >&lhs, const vec<Dim,Number >& rhs)
{
    Number ret=0;
    for(size_t i=Dim;i--;)
    {
        ret+=lhs[i]*rhs[i];
    }
    return(ret);
}


template<size_t len,size_t Dim, typename Number> vec<len,Number > proj(const vec<Dim,Number> &v,size_t start=0)
{
    return(vec<len,Number >(&v.items[start]));
}

template<size_t len,size_t Dim, typename Number> vec<len,Number > dive(const vec<Dim,Number> &v,size_t start=0)
{
    vec<len,Number> ret(&v.items[start]);
    for(size_t i=Dim+start;i<len;i++)
    {
        ret[i]=1;
    }
    return(ret);
}

template<size_t Dim,typename Number> ostream& operator<<(ostream& os,const vec<Dim,Number >& v)
{
    return(v.print(os));
}

template<size_t DimRows,size_t DimCols,typename Number> class mat;

template<size_t DimCols,size_t DimRows,typename Number> struct dt
{
    static Number det(const mat<DimRows,DimCols,Number>& src)
    {
        Number ret=0;
        for(size_t i=DimCols;i--;)
        {
            ret+=src[0][i]*src.algAdd(0,i);
        }
        return(ret);
    }
};

template<typename Number> struct dt<1,1,Number>
{
    static Number det(const mat<1,1,Number>& src)
    {
        return(src[0][0]);
    }
};

template<size_t DimRows,size_t DimCols,typename Number> class mat
{
    vec<DimCols,Number> rows[DimRows];


public:
    typedef Number NumberT;
    static size_t shift(size_t in,const size_t& val)
    {
        return(in<val ? in : ++in);
    }

    mat()
    {
    }
    mat(const mat<DimRows,DimCols,Number >& src)
    {
        for(size_t i=DimCols;i--;)
        {
            for(size_t j=DimRows;j--;)
            {
                const Number t=src[i][j];
                rows[i][j]=t;
            }
        }
    }

    ostream& print(ostream& out) const
    {
        for(size_t i=0;i<DimRows;i++)
        {
            out<<rows[i]<<"\n";
        }
        return(out);
    }
    vec<DimCols,Number > minimums()
    {
        vec<DimCols,Number > ret=rows[0];
        for(size_t i=DimRows;--i;)
        {
            for(size_t j=DimCols;j--;)
            {
                ret[j]=min(ret[j],rows[i][j]);
            }
        }
        return(ret);
    }

    vec<DimCols,Number > maximums()
    {
        vec<DimCols,Number > ret=rows[0];
        for(size_t i=DimRows;--i;)
        {
            for(size_t j=DimCols;j--;)
            {
                ret[j]=max(ret[j],rows[i][j]);
            }
        }
        return(ret);
    }
    vec<DimCols,Number>& operator[] (size_t index)
    {
        return(rows[index]);
    }

    const vec<DimCols,Number>& operator[] (size_t index) const
    {
        return(rows[index]);
    }
    static mat<DimCols,DimRows,Number> ones()
    {
        mat<DimCols,DimRows,Number> ret;
        for(size_t i=DimRows;i--;)
        {
            for(size_t j=DimCols;j--;)
            {
                ret[i][j]=(i==j);
            }

        }
        return(ret);
    }

    Number det() const
    {
        return(dt<DimCols,DimRows,Number>::det(*this));
    }

    mat<DimRows-1,DimCols-1,Number> minor(size_t row,size_t col) const
    {
        mat<DimRows-1,DimCols-1,Number> ret;
        for(size_t i=DimRows-1;i--;)
        {
            for(size_t j=DimCols-1;j--;)
            {
                ret[i][j]=rows[ret.shift(i,row)][ret.shift(j,col)];
            }
        }
        return(ret);
    }


    Number algAdd(size_t row,size_t col) const
    {
        return(minor(row,col).det()*( (row+col)%2 ? -1 : 1));
    }

    mat<DimRows,DimCols,Number> Adjacent()const
    {
        mat<DimRows,DimCols,Number> ret;
        for(size_t i=DimRows;i--;)
        {
            for(size_t j=DimCols;j--;)
            {
                ret[i][j]=algAdd(i,j);
            }
        }
        return(ret);
    }

    mat<DimRows,DimCols,Number> invertT()const
    {
        mat<DimRows,DimCols,Number> ret=Adjacent();
        return(ret/(ret[0]*rows[0]));
    }

    void setCol(const Number& val,size_t col)
    {
        for(size_t i=DimRows;i--;)
        {
            rows[i][col]=val;
        }
    }

};

template<size_t Dim,typename Number>vec<Dim,Number > operator*(const mat<Dim,Dim,Number >& lhs, const vec<Dim,Number>& rhs)
{
    vec<Dim,Number> ret;
    for(size_t i=Dim;i--;)
    {
        ret[i]=lhs[i]*rhs;
    }
    return(ret);
}

template<size_t DimCols,size_t DimRows,typename Number>mat<DimCols,DimRows,Number > operator/(mat<DimCols,DimRows,Number> lhs, const Number& rhs)
{
    for(size_t i=DimRows;i--;)
    {
        lhs[i]=lhs[i]/rhs;
    }
    return(lhs);
}

template<size_t DimRows,size_t DimCols,typename Number> ostream& operator<<(ostream& os,const mat<DimRows,DimCols,Number>& v)
{
    return(v.print(os));
}

typedef mat<2,2,float > tempMat;

#endif // VEC_H


#endif // VECSIMPLE_H



using namespace std;

typedef vec<3,float> pixel;

class screen
{
    vector<pixel > buffer;
    size_t width;
    size_t height;
public:
    screen(size_t width,size_t height):width(width),height(height)
    {
        buffer.assign(width*height,pixel());
    }
    template<typename t> void putpixel(const t& location,const pixel& px)
    {

        buffer[location[0]+location[1]*width]=px;
    }

    ostream& print(ostream& out) const
    {
        for(size_t i=0;i<height;i++)
        {
            out<<"|";
            for(size_t j=0;j<width;j++)
            {                
                const size_t mp=buffer[i+j*width].maxPos();
                static const char syms[]={' ','.','\'','-','+','*'};
                static const char syms2[]={'R','G','B'};
                if(buffer[i+j*width][mp] > static_cast<pixel::NumberT>(sizeof(syms)-1)/static_cast<pixel::NumberT>(sizeof(syms)))
                {
                    cout<<syms2[mp];
                }
                else
                {
                    const size_t idx=buffer[i+j*width][mp]*float(sizeof(syms)-1);
                    out<<syms[idx];
                }
            }
            out<<"|\n";
        }
        return(out);
    }
};

typedef vec<3,float > v3i;
typedef vec<2,float > v2i;
typedef mat<3,3,float>  m3i;


template<typename V>class allPointsOfSquare
{
    vec<V::DimN,typename V::NumberT> topLeft;
    vec<V::DimN,typename V::NumberT> bottomRight;
    vec<V::DimN,typename V::NumberT> pos;
public:
    allPointsOfSquare(const V& topLeft,const V& bottomRight):topLeft(topLeft),bottomRight(bottomRight),pos(topLeft)
    {
    }
    const v2i& operator *() const
    {
        return(pos);
    }
    bool next()
    {
        const bool ret=(pos!=bottomRight);
        for(size_t i=V::DimN;i--;)
        {
            pos[i]++;
            if(pos[i]>bottomRight[i])
            {
                pos[i]=0;
            }
            else
            {
                break;
            }
        }
        return(ret);
    }
};

class IShader
{
public:
    virtual ~IShader()
    {

    }

    virtual pixel shade(const v3i& a)=0;
};

class baryShader:public IShader
{
public:
    virtual ~baryShader()
    {

    }

    virtual pixel shade(const v3i&a)
    {
        return(a);
    }
};


void fillTria(mat<3,3,float > coord,IShader* shader,screen& scr)
{
    //находим углы прямоугольника, в котором лежит треугольник.
    //это соответственно минимумы и максимумы сторон, его содержащих

    v3i topLeft=coord.minimums();
    v3i bottomRight=coord.maximums();

    coord.setCol(1,2);

    mat<3,3,float > bcm=coord.invertT();

    mat<3,2,float > directions;

    for(size_t i=3;i--;)
    {
        directions[i]=proj<2>(coord[ (i+1) % 3 ])-proj<2>(coord[i]);
    }

    for(allPointsOfSquare<v2i> sweep=allPointsOfSquare<v2i>(
                                                                proj<2>(topLeft),
                                                                proj<2>(bottomRight))
                        ;
                                                                sweep.next()
                        ;
                                                            )
    {
            size_t i=0;
            for(;i<3;i++)
            {
                v2i curDirection=(*sweep)-proj<2>(coord[i]);

                tempMat crss;
                crss[0]=proj<2>(curDirection);
                crss[1]=proj<2>(directions[i]);

                if(crss.det()>0)
                {                    
                    break;
                }
            }
            if(i==3)
            {                
                v3i a=bcm*dive<3>(*sweep);

                scr.putpixel(*sweep,shader->shade(a));

            }
    }
}




ostream& operator<<(ostream& os,const screen& v)
{
    return(v.print(os));
}




int main()
{
    screen scr(80,80);
//    cout<<scr;
    mat<3,3,float > t;
    t[0][0]=5;
    t[0][1]=7;
    t[0][2]=3;


    t[1][0]=70;
    t[1][1]=13;
    t[1][2]=13;



    t[2][0]=20;
    t[2][1]=50;
    t[2][2]=21;
    cerr<<"started";


    baryShader bs;
    fillTria(t,&bs,scr);
    cerr<<"filled";

    cout<<scr;

    return 0;
}

