<commit_before>#include "form.h"
#include "explain.h"
#include "util.h"
#include "rand.h"

#include <algorithm>
#include <numeric>
#include <sstream>
#include <cassert>



namespace saki
{



std::array<const char *, NUM_YAKUS> YAKU_STRS {
    "Rci", "Ipt", "Tmo", "Tny", "Pnf",
    "Y1y", "Y2y", "Y3y",
    "Y1f", "Y2f", "Y3f", "Y4f", // jkz and bkz has same strings
    "Y1f", "Y2f", "Y3f", "Y4f",
    "Ipk", "Rns", "Hai", "Hou", "Ckn",
    "Ssk", "Itt", "Cta",

    "Wri", "Ssk", "Itt", "Cta",
    "Toi", "Ctt", "Sak", "Skt", "Stk", "Hrt", "S3g", "H1t", "Jnc",

    "Mnh", "Jnc", "Rpk", "C1t", "Mnc",

    "X13", "Xd3", "X4a",  "Xt1", "Xs4", "Xd4",
    "Xcr", "Xr1", "Xth", "Xch", "X4k", "X9r",
    "W13", "W4a", "W9r"
};



Form::Form(const Hand &ready, const T37 &pick, const PointInfo &info, const RuleInfo &rule,
           const std::vector<T37> &drids, const std::vector<T37> &urids)
    : mDealerWin(info.selfWind == 1)
    , mRon(true)
    , mExtraRound(info.extraRound)
{
    initDora(drids, urids, ready, pick);

    if (ready.withPick(pick).step13() == -1) {
        init13(info, ready.closed(), pick);
    } else if (ready.withPick(pick).step4() == -1) {
        init4(info, rule, ready, pick);
    } else {
        // assume (?) 2pk is always bigger than 7-pairs
        assert(ready.withPick(pick).step7() == -1);
        init7(info, rule, ready.closed());
    }
}

Form::Form(const Hand &full, const PointInfo &info, const RuleInfo &rule,
           const std::vector<T37> &drids, const std::vector<T37> &urids)
    : mDealerWin(info.selfWind == 1)
    , mRon(false)
    , mExtraRound(info.extraRound)
{
    assert(full.hasDrawn()); // no drawn you tsumo a J8

    initDora(drids, urids, full);

    if (full.step13() == -1) {
        init13(info, full.closed(), full.drawn());
    } else if (full.step4() == -1) {
        init4(info, rule, full, full.drawn());
    } else {
        // assume (?) 2pk is always bigger than 7-pairs
        assert(full.step7() == -1);
        init7(info, rule, full.closed());
    }
}

bool Form::isPrototypalYakuman() const
{
    return mYakuman;
}

int Form::fu() const
{
    return mFu;
}

int Form::han() const
{
    return mHan;
}

int Form::base() const
{
    return mBase;
}

const Form::Yakus &Form::yakus() const
{
    return mYakus;
}

ManganType Form::manganType() const
{
    if (mBase == 2000)
        return ManganType::MG;
    if (mBase == 3000)
        return ManganType::HNM;
    if (mBase == 4000)
        return ManganType::BM;
    if (mBase == 6000)
        return ManganType::SBM;
    if (mBase == 8000)
        return ManganType::KZEYKM;
    return ManganType::HR;
}

bool Form::hasYaku() const
{
    return mYakus.any();
}

int Form::netLoss(bool explode) const
{
    int res;
    int b = base();

    res = mDealerWin ? (mRon ? b * 6 : b * 2)
                     : (mRon ? b * 4 : (explode ? b * 2 : b));

    if (res % 100 != 0)
        res = res - res % 100 + 100;

    return res;
}

int Form::netGain() const
{
    if (mRon) // ron: gain == loss
        return netLoss(false); // param 'explode' unused
    else if (mDealerWin) // dealer tsumo
        return 3 * netLoss(false);
    else // non-dealer tsumo
        return netLoss(true) + 2 * netLoss(false);
}

int Form::loss(bool explode) const
{
    return netLoss(explode) + (mExtraRound * (mRon ? 300 : 100));
}

int Form::gain() const
{
    if (mRon) // ron: gain == loss
        return loss(false); // param 'explode' unused
    else if (mDealerWin) // dealer tsumo
        return 3 * loss(false);
    else // non-dealer tsumo
        return loss(true) + 2 * loss(false);
}

std::string Form::spell() const
{
    std::ostringstream oss;

    if (mYakuman) {
        // forgot why I even append spaces at the end
        // maybe it does or does not matter for the gui layout
        for (int i = Yaku::KKSMS; i < NUM_YAKUS; i++)
            if (mYakus[i])
                oss << YAKU_STRS[i] << "  ";
    } else {
        Yakus copy = mYakus;
        if (copy[Yaku::RC] && copy[Yaku::TYC] && copy[Yaku::PF]) {
            copy.reset(Yaku::RC);
            copy.reset(Yaku::TYC);
            copy.reset(Yaku::PF);
            oss << "Mtp";
        }

        if (copy[Yaku::RC] && copy[Yaku::PF]) {
            copy.reset(Yaku::RC);
            copy.reset(Yaku::PF);
            oss << "Mpn";
        }

        if (copy[Yaku::RC] && copy[Yaku::TYC]) {
            copy.reset(Yaku::RC);
            copy.reset(Yaku::TYC);
            oss << "Mtn";
        }

        if (copy[Yaku::TYC] && copy[Yaku::PF]) {
            copy.reset(Yaku::TYC);
            copy.reset(Yaku::PF);<commit_msg>tune spell output<commit_after>#include "form.h"
#include "explain.h"
#include "util.h"
#include "rand.h"

#include <algorithm>
#include <numeric>
#include <sstream>
#include <cassert>



namespace saki
{



std::array<const char *, NUM_YAKUS> YAKU_STRS {
    "Rci", "Ipt", "Tmo", "Tny", "Pnf",
    "Y1y", "Y2y", "Y3y",
    "Y1f", "Y2f", "Y3f", "Y4f", // jkz and bkz has same strings
    "Y1f", "Y2f", "Y3f", "Y4f",
    "Ipk", "Rns", "Hai", "Hou", "Ckn",
    "Ssk", "Itt", "Cta",

    "Wri", "Ssk", "Itt", "Cta",
    "Toi", "Ctt", "Sak", "Skt", "Stk", "Hrt", "S3g", "H1t", "Jnc",

    "Mnh", "Jnc", "Rpk", "C1t", "Mnc",

    "X13", "Xd3", "X4a",  "Xt1", "Xs4", "Xd4",
    "Xcr", "Xr1", "Xth", "Xch", "X4k", "X9r",
    "W13", "W4a", "W9r"
};



Form::Form(const Hand &ready, const T37 &pick, const PointInfo &info, const RuleInfo &rule,
           const std::vector<T37> &drids, const std::vector<T37> &urids)
    : mDealerWin(info.selfWind == 1)
    , mRon(true)
    , mExtraRound(info.extraRound)
{
    initDora(drids, urids, ready, pick);

    if (ready.withPick(pick).step13() == -1) {
        init13(info, ready.closed(), pick);
    } else if (ready.withPick(pick).step4() == -1) {
        init4(info, rule, ready, pick);
    } else {
        // assume (?) 2pk is always bigger than 7-pairs
        assert(ready.withPick(pick).step7() == -1);
        init7(info, rule, ready.closed());
    }
}

Form::Form(const Hand &full, const PointInfo &info, const RuleInfo &rule,
           const std::vector<T37> &drids, const std::vector<T37> &urids)
    : mDealerWin(info.selfWind == 1)
    , mRon(false)
    , mExtraRound(info.extraRound)
{
    assert(full.hasDrawn()); // no drawn you tsumo a J8

    initDora(drids, urids, full);

    if (full.step13() == -1) {
        init13(info, full.closed(), full.drawn());
    } else if (full.step4() == -1) {
        init4(info, rule, full, full.drawn());
    } else {
        // assume (?) 2pk is always bigger than 7-pairs
        assert(full.step7() == -1);
        init7(info, rule, full.closed());
    }
}

bool Form::isPrototypalYakuman() const
{
    return mYakuman;
}

int Form::fu() const
{
    return mFu;
}

int Form::han() const
{
    return mHan;
}

int Form::base() const
{
    return mBase;
}

const Form::Yakus &Form::yakus() const
{
    return mYakus;
}

ManganType Form::manganType() const
{
    if (mBase == 2000)
        return ManganType::MG;
    if (mBase == 3000)
        return ManganType::HNM;
    if (mBase == 4000)
        return ManganType::BM;
    if (mBase == 6000)
        return ManganType::SBM;
    if (mBase == 8000)
        return ManganType::KZEYKM;
    return ManganType::HR;
}

bool Form::hasYaku() const
{
    return mYakus.any();
}

int Form::netLoss(bool explode) const
{
    int res;
    int b = base();

    res = mDealerWin ? (mRon ? b * 6 : b * 2)
                     : (mRon ? b * 4 : (explode ? b * 2 : b));

    if (res % 100 != 0)
        res = res - res % 100 + 100;

    return res;
}

int Form::netGain() const
{
    if (mRon) // ron: gain == loss
        return netLoss(false); // param 'explode' unused
    else if (mDealerWin) // dealer tsumo
        return 3 * netLoss(false);
    else // non-dealer tsumo
        return netLoss(true) + 2 * netLoss(false);
}

int Form::loss(bool explode) const
{
    return netLoss(explode) + (mExtraRound * (mRon ? 300 : 100));
}

int Form::gain() const
{
    if (mRon) // ron: gain == loss
        return loss(false); // param 'explode' unused
    else if (mDealerWin) // dealer tsumo
        return 3 * loss(false);
    else // non-dealer tsumo
        return loss(true) + 2 * loss(false);
}

std::string Form::spell() const
{
    std::ostringstream oss;

    if (mYakuman) {
        // forgot why I even append spaces at the end
        // maybe it does or does not matter for the gui layout
        for (int i = Yaku::KKSMS; i < NUM_YAKUS; i++)
            if (mYakus[i])
                oss << YAKU_STRS[i] << "  ";
    } else {
        Yakus copy = mYakus;
        if (copy[Yaku::RSKH]) {
            copy.reset(Yaku::RSKH);
            oss << "Rns";
            if (copy.count() > 1)
                oss << "Kah";
        }

        if (copy[Yaku::HTRY_T]) {
            copy.reset(Yaku::HTRY_T);
            oss << "Hai";
            if (copy.count() > 1)
                oss << "Rye";
        }

        if (copy[Yaku::DBRRC]) {
            copy.reset(Yaku::DBRRC);
            oss << "Wri";
        }

        if (copy[Yaku::RC] && copy[Yaku::TYC] && copy[Yaku::PF]) {
            copy.reset(Yaku::RC);
            copy.reset(Yaku::TYC);
            copy.reset(Yaku::PF);
            oss << "Mtp";
        }

        if (copy[Yaku::RC] && copy[Yaku::PF]) {
            copy.reset(Yaku::RC);
            copy.reset(Yaku::PF);
            oss << "Mpn";
        }

        if (copy[Yaku::RC] && copy[Yaku::TYC]) {
            copy.reset(Yaku::RC);
            copy.reset(Yaku::TYC);
            oss << "Mtn";
        }

        if (copy[Yaku::TYC] && copy[Yaku::PF]) {
            copy.reset(Yaku::TYC);
            copy.reset(Yaku::PF);
{'fraction_non_alphanumeric': 0.18135890297968862, 'fraction_numerical': 0.023095164449943292, 'mean_word_length': 2.2648939750925616, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6280278', 'n_tokens_mistral': 3958, 'n_tokens_neox': 3711, 'n_words': 876}