Search code examples
c++algorithmascii-artfiglet

How figlet fit and smush?


I am creating a figlet like code in c++ and i am currently doing fiting by inserting null at left side character and find min space and remove minspace and null the character,( for understanding take null as '0' )

" __0          "
"| _|0         "
"| |0    _____ "
"| |0   |_____|"
"| |0      $   "
"|__|0         "

(if any space line i insert null at start) Now here min space is 3 so i remove 3 space and null in that and this code works perfect and smushing by inheriting the fitting class and i will pass the right side char by inserting null like

"       0"
"       0"
" _0____ "
"|0_____|"
"   $0   "
"       0"

it will give result like

" __       0"
"| _|      0"
"| | _0____ "
"| ||0_____|"
"| |   $0   "
"|__|      0"

Now i will store pos of null and remove it, In next loop check the two character before the null, if any one are HardBlank then i return the function else i smush it in next loop, but above are not smush( not work correctly ) due to HardBlank, so i want to know how figlet actually smush i downloaded the figlet code from here but i did not understand the code.

  1. There is any better algorithm than this or How figlet actually do fitting and smushing ?

All suggestions are welcome, Thanks in advance.


Solution

  • I asked this question long time ago now, But I answering this question now for future readers I have written algorithm a better than this some time ago that do the following,

    Kerning or fitting :

    The main part of this thing is trim, so lets create an function that takes two input that figs is left side FIGchar and figc is right side FIGchar. The first thing to do is find the number of space that need to be removed from right side of figs and left side of figc, we can easily find this by counting total space in right size of figs and left side of figc. Finally take minimum of that that is the space count that has to be removed here is that implementation,

    /**
     * @brief trims in a deep
     * 
     * @param figs fig string
     * @param figc fig character
     */
    void trim_deep(Figs_type &figs, Figc_type &figc) const
    {
        std::vector<size_type> elem;
    
        for (size_type i = 0; i < figs.size(); ++i)
        {
            int lcount = 0, rcount = 0;
    
            for (auto itr = figs[i].rbegin(); itr != figs[i].rend(); ++itr)
            {
                if (*itr == ' ')
                    ++lcount;
                else
                    break;
            }
    
            for (auto itr = figc[i].begin(); itr != figc[i].end(); ++itr)
            {
                if (*itr == ' ')
                    ++rcount;
                else
                    break;
            }
    
            elem.push_back(lcount + rcount);
        }
    
        size_type space = *std::min_element(elem.begin(), elem.end());
    
        for (size_type i = 0; i < figs.size(); ++i)
        {
            size_type siz = space;
    
            while (siz > 0 && figs[i].back() == ' ')
            {
                figs[i].pop_back();
                --siz;
            }
    
            figc[i].erase(0, siz);
        }
    }
    

    Smushing:

    This smushing can be done easily by using above function with only smush right most character of figs and left side character of figc if it is smushble here is implementation,

    /**
     * @brief smush rules
     * @param lc left character
     * @param rc right character
     * @return smushed character
     */
    char_type smush_rules(char_type lc, char_type rc) const
    {
        //()
        if (lc == ' ')
        {
            return rc;
        }
    
        if (rc == ' ')
        {
            return lc;
        }
    
        //(Equal character smush)
        if (lc == rc)
        {
            return rc;
        }
    
        //(Underscores smush)
        if (lc == '_' && this->cvt("|/\\[]{}()<>").find(rc) != string_type::npos)
        {
            return rc;
        }
    
        if (rc == '_' && this->cvt("|/\\[]{}()<>").find(lc) != string_type::npos)
        {
            return lc;
        }
    
        //(Hierarchy Smushing)
        auto find_class = [](char_type ch) -> size_type
        {
            if (ch == '|')
            {
                return 1;
            }
    
            if (ch == '/' || ch == '\\')
            {
                return 3;
            }
    
            if (ch == '[' || ch == ']')
            {
                return 4;
            }
    
            if (ch == '{' || ch == '}')
            {
                return 5;
            }
    
            if (ch == '(' || ch == ')')
            {
                return 6;
            }
    
            return 0;
        };
    
        size_type c_lc = find_class(lc);
        size_type c_rc = find_class(rc);
    
        if (c_lc > c_rc)
        {
            return lc;
        }
    
        if (c_rc > c_lc)
        {
            return rc;
        }
    
        //(Opposite smush)
        if (lc == '[' && rc == ']')
        {
            return '|';
        }
    
        if (lc == ']' && rc == '[')
        {
            return '|';
        }
    
        if (lc == '{' && rc == '}')
        {
            return '|';
        }
    
        if (lc == '}' && rc == '{')
        {
            return '|';
        }
    
        if (lc == '(' && rc == ')')
        {
            return '|';
        }
    
        if (lc == ')' && rc == '(')
        {
            return '|';
        }
    
        //(Big X smush)
        if (lc == '/' && rc == '\\')
        {
            return '|';
        }
    
        if (lc == '\\' && rc == '/')
        {
            return 'Y';
        }
    
        if (lc == '>' && rc == '<')
        {
            return 'X';
        }
    
        //(universel smush)
        return lc;
    }
    
    /**
     * @brief smush algoriths on kerned Fig string and character
     * 
     * @param figs 
     * @param figc 
     */
    void smush(Figs_type &figs, Figc_type figc, char_type hb) const
    {
        bool smushble = true;
    
        for (size_type i = 0; i < figs.size(); ++i)
        {
            if (figs[i].size() == 0 || figc[i].size() == 0)
            {
                smushble = false;
            }
            else if ((figs[i].back() == hb) && !(figc[i].front() == hb))
            {
                smushble = false;
            }
        }
    
        if (smushble)
        {
            for (size_type i = 0; i < figs.size(); ++i)
            {
                char_type val = smush_rules(figs[i].back(), figc[i].front());
                figs[i].pop_back();
                figc[i].erase(0, 1);
                figs[i] += string_type(1, val) + figc[i];
            }
        }
        else
        {
            for (size_type i = 0; i < figs.size(); ++i)
            {
                figs[i] += figc[i];
            }
        }
    }
    

    This code is directly copied from this file, So the types can be confusing here is overview Figs_type and Figc_type are just like vector of string and other type are reflects in their name and the repo can be found here.