예제 #1
0
        private Syotetiedot alkuperaisetSyotteet;           // store the initial input data with matches


        // --------------------------------------------------------------------------------
        // Laskenta
        // --------------------------------------------------------------------------------

        // AlustaLaskenta
        //
        // Ennen laskentaa alustetaan muuttujat saatujen syötteiden mukaan
        //
        private void AlustaLaskenta(Syotetiedot syotteet)
        {
            //
            // Alustetaan Selopelaajan paikalliset muuttujat
            //
            alkuperaisetSyotteet = syotteet;  // selo, pelimaara, miettimisaika, lomakkeelle mm. seloero

            // laskettavat tiedot, selon ja pelimaaran laskenta aloitetaan syötetyistä arvoista
            UusiSelo      = syotteet.AlkuperainenSelo;
            UusiPelimaara = syotteet.AlkuperainenPelimaara;

            TurnauksenTulos2x = 0; // lasketaan otteluista kokonaislukuna
            Odotustulos       = 0; // summa yksittäisten otteluiden odotustuloksista

            // palautettava kerroin alkuperäisen selon mukaan
            // laskennassa käytetään sen hetkisestä selosta laskettua kerrointa
            Kerroin = MaaritaKerroin(UusiSelo);

            // vaihteluvälin alustus
            MinSelo = Vakiot.MAX_SELO;
            MaxSelo = Vakiot.MIN_SELO;

            // Lisäksi selvitä syötetiedoista (tarvitaan laskennassa, tulostetaan lomakkeelle)
            //   - vastustajien eli otteluiden lkm
            //   - turnauksen eli vastustajien keskivahvuus
            VastustajienLkm           = syotteet.Ottelut.Lukumaara;
            UudenPelaajanPelitLKM     = syotteet.UudenPelaajanPelitEnsinLKM;
            TurnauksenKeskivahvuus    = syotteet.Ottelut.Keskivahvuus;
            TurnauksenKeskivahvuus10x = syotteet.Ottelut.Keskivahvuus10x;

            //VastustajaMin = syotteet.Ottelut.MinVahvuus;
            //VastustajaMax = syotteet.Ottelut.MaxVahvuus;
        }
예제 #2
0
        // Laske tulokset, syöte on jo tarkistettu tätä ennen
        //
        // Kutsuttu:
        //      -SelolaskuriForm.cs
        //      -Selolaskuri.Tests/UnitTest1.cs
        //
        // Lisäksi kopioi lasketut tulokset tietorakenteeseen Tulokset, josta ne myöhemmin
        // näytetään (SelolaskuriForm.cs) tai ) yksikkötestauksessa tarkistetaan (Selolaskuri.Tests/UnitTest1.cs)
        //
        public Selopelaaja SuoritaLaskenta(Syotetiedot syotteet)
        {
            //  *** NYT LASKETAAN ***
            //
            selopelaaja.PelaaKaikkiOttelut(syotteet);   // pelaa kaikki ottelut listalta

            //  *** PALAUTA TULOKSET ***

            return(selopelaaja);
        }
예제 #3
0
        // TarkistaSyote
        //
        // Kutsuttu:
        //      -SelolaskuriForm.cs
        //      -Selolaskuri.Tests/UnitTest1.cs
        //
        // Tarkistaa
        //      -miettimisaika-valintanapit (ei voi olla virhettä)
        //      -oma SELO eli nykyinen vahvuusluku (onko kelvollinen numero)
        //      -oma pelimäärä (kelvollinen numero tai tyhjä)
        //      -vastustajan SELO (onko numero) tai vastustajien SELOT (onko turnauksen tulos+selot tai selot tuloksineen)
        //      -yhtä ottelua syötettäessä tuloksen valintanapit (jos yksi vastustaja, niin tulos pitää valita)
        //
        // Syotetiedot syotteet  = oma nykyinen selo ja pelimäärä, vastustajan selo, ottelun tulos sekä merkkijono
        //
        // Tuloksena
        //    syotteet.ottelut sisältää listan vastustajista tuloksineen: ottelu(selo, tulos)
        //    syotteet.VastustajanSeloYksittainen on joko yhden vastustajan selo tai 0 (jos monta ottelua)
        //
        // Virhetilanteet:
        //    Kenttiä tarkistetaan yo. järjestyksessä ja lopetetaan, kun kohdataan ensimmäinen virhe.
        //    Palautetaan tarkka virhestatus ja virheilmoitukset näytetään ylemmällä tasolla.
        //
        public int TarkistaSyote(Syotetiedot syotteet)
        {
            if (syotteet == null)
            {
                throw new ArgumentNullException(nameof(syotteet));
            }

            int tulos; // = Vakiot.SYOTE_STATUS_OK;

            // tyhjennä ottelulista, johon tallennetaan vastustajat tuloksineen
            //syotteet.ottelut.Tyhjenna();  Ei tarvitse, kun aiempi new Syotetiedot() tyhjentää

            // ************ TARKISTA SYÖTE ************

            do
            {
                // ENSIN TARKISTA MIETTIMISAIKA.
                if ((tulos = TarkistaMiettimisaika(syotteet.Miettimisaika)) == Vakiot.SYOTE_VIRHE_MIETTIMISAIKA_CSV)
                {
                    break;
                }

                // Hae ensin oma nykyinen vahvuusluku ja pelimäärä
                if ((tulos = TarkistaOmaSelo(syotteet.AlkuperainenSelo_str)) == Vakiot.SYOTE_VIRHE_OMA_SELO)
                {
                    break;
                }
                syotteet.AlkuperainenSelo = tulos;

                if ((tulos = TarkistaPelimaara(syotteet.AlkuperainenPelimaara_str)) == Vakiot.SYOTE_VIRHE_PELIMAARA)
                {
                    break;
                }
                syotteet.AlkuperainenPelimaara = tulos;  // Voi olla PELIMAARA_TYHJA tai numero >= 0

                //    JOS YKSI OTTELU,   saadaan sen yhden vastustajan vahvuusluku, eikä otteluja ole listassa.
                //      ottelumäärän tarkistamisen jälkeen tässä tehdään yhden ottelun lista
                //    JOS MONTA OTTELUA, palautuu 0 ja ottelut on tallennettu tuloksineen listaan
                //
                //    JOS MONTA OTTELUA ja VÄLISSÄ '/'-merkki, NIIN SYÖTETTY ENSIN UUDEN PELAAJAN LASKENTA JA SITTEN NORMAALI LASKENTA
                //    Tällöin syotteet,.AlkuperainenPelimaara oltava enintään 10

                selopelaaja.UudenPelaajanPelitLKM = 0; // XXX: oletus ettei vaihdeta laskentaa ja voidaan tarkistaa, ettei ole '/' kahdesti


                // 1) Usea ottelu: syotteet.Ottelut sisältää listan otteluista tuloksineen
                //
                // 2) yksi ottelu: syotteet.Ottelut yksi ottelu
                //
                // TULOSSA:
                // 3) "tulos ottelumäärä keskiselo" esim. 5.5 8 1888.6
                //          Selopelaaja.AnnettuTurnauksenTulos2x, TurnauksenKeskivahvuus, TurnauksenKeskivahvuus10x, VastustajienLkm
                if ((tulos = TarkistaVastustajanSelo(syotteet.Ottelut, syotteet.VastustajienSelot_str)) < Vakiot.SYOTE_STATUS_OK)
                {
                    break;
                }

                if (selopelaaja.UudenPelaajanPelitLKM > 0)
                {
                    if (syotteet.AlkuperainenPelimaara > 10)
                    {
                        // ei voinut olla uuden pelaajan laskenta, jos alkuperäinen pelimäärä oli yli 10
                        tulos = Vakiot.SYOTE_VIRHE_UUDEN_PELAAJAN_OTTELUT_ENINT_10;
                        break;
                    }
                    if (selopelaaja.UudenPelaajanPelitLKM + syotteet.AlkuperainenPelimaara < 11)
                    {
                        // jos alkuperäinen pelimäärä + nyt uuden pelaajan laskentaan saatu pelimäärä eivät ole vähintään 11
                        tulos = Vakiot.SYOTE_VIRHE_UUDEN_PELAAJAN_OTTELUT_VAHINT_11;
                        break;
                    }
                    syotteet.UudenPelaajanPelitEnsinLKM = selopelaaja.UudenPelaajanPelitLKM;
                }

                // tässä siis voi olla vahvuusluku tai 0
                syotteet.YksiVastustajaTulosnapit = tulos;

                // vain jos otteluita ei jo ole listalla (ja TarkistaVastustajanSelo palautti kelvollisen vahvuusluvun),
                // niin tarkista ottelutuloksen valintanapit -> TarkistaOttelunTulos()
                // ja sitten lisää tämä yksi ottelu listaan!
                if (syotteet.Ottelut.Lukumaara == 0)
                {
                    //
                    // Vastustajan vahvuusluku on nyt vastustajanSeloYksittainen-kentässä
                    // Haetaan vielä ottelunTulos -kenttään tulospisteet tuplana (0=tappio,1=tasapeli,2=voitto)

                    // Tarvitaan tulos (voitto, tasapeli tai tappio)
                    if ((tulos = TarkistaOttelunTulos(syotteet.OttelunTulos)) == Vakiot.SYOTE_VIRHE_BUTTON_TULOS)
                    {
                        break;
                    }

                    // Nyt voidaan tallentaa ainoan ottelun tiedot listaan (vastustajanSelo, ottelunTulos), josta
                    // ne on helppo hakea laskennassa.
                    // Myös vastustajanSeloYksittainen jää alustetuksi, koska siitä nähdään että vahvuusluku oli
                    // annettu erikseen, jolloin myös ottelun tuloksen on oltava annettuna valintapainikkeilla.
                    syotteet.Ottelut.LisaaOttelunTulos(syotteet.YksiVastustajaTulosnapit, syotteet.OttelunTulos);
                }

                tulos = Vakiot.SYOTE_STATUS_OK; // syötekentät OK, jos päästy tänne asti ja ottelu/ottelut ovat listassa
            } while (false);

            // Virheen käsittelyt ja virheilmoitus ovat kutsuvissa rutiineissa
            return(tulos);
        }
예제 #4
0
        // Pelaa kaikki listalta (syotteet.Ottelut) löytyvät ottelut!
        //
        // Tapaukset:
        // 1) Uuden pelaajan laskenta, jossa tulokset formaatissa "1.5 1622 1880 1683"
        // 2) Normaali laskenta, jossa käydään kaikki listan ottelut läpi, tulokset "+1525 =1600 -1611 +1558"
        // 3) Uuden pelaajan laskenta, jossa tulokset formaatissa "1.5 1622 1880 1683"
        //
        // Päivittää: UusiSelo, UusiPelimaara, turnauksenTulos, MinSelo ja MaxSelo
        // Palauttaa: -
        //
        public void PelaaKaikkiOttelut(Syotetiedot syotteet)
        {
            if (syotteet == null)
            {
                throw new ArgumentNullException(nameof(syotteet));
            }

            // XXX: KÄSITTELE ERIKOISTAPAUS, JOSSA ON VAIN annettuTurnauksenTulos2x, VastustajienLkm ja Turnauksenkeskivahvuus
            // XXX: silloin ei ole ottelulistaa

            Ottelulista ottelulista = syotteet.Ottelut;

            // asettaa omat tiedot (selo ja pelimäärä) seloPelaaja-luokkaan, nollaa tilastotiedot ym.
            AlustaLaskenta(syotteet);

            VastustajaMin = ottelulista.VastustajaMin;
            VastustajaMax = ottelulista.VastustajaMax;

            // XXX: Kun ensimmäinen ottelu, niin UusiSelo ja UusiPelimaara ovat käyttäjän antamat alkuarvot omaSelo ja pelimaara
            // XXX: Laskennan edetessä niitä päivitetään

            // Erikoistapauksena uuden pelaajan tuloksien laskenta turnauksesta,
            // jossa tulokset on ilmoitettu formaatissa "1.5 1622 1880 1683"
            //

            if (OnkoAnnettuTurnauksenTulos && UudenPelaajanLaskenta)
            {
                //  selo += pistemäärä - ottelut/2 * 200
                // 1 ottelu:
                //    1525 + 0.5 1525 -> tulos 1525
                // 2 ottelua:
                //  2    1525 1441   summa: 2966  keskim. 1483   tulos on keskim+200
                // keskitulos/matsi = 1

                // apumuuttujia (lausekkeiden selkiyttämiseksi ja lyhentämiseksi)
                float keskimTulos = (annettuTurnauksenTulos2x / 2F) / VastustajienLkm; // 0.0 - 1.0
                float muutos      = 400 * (keskimTulos - 0.5F) + 0.5F;                 // tuloksella tasapeli pysytään samassa kuin keskimTulos

                // vanhan selon painoarvo ja uuden lasketun selon painoarvo riippuvat pelimääristä
                UusiSelo       = ((UusiSelo * UusiPelimaara) + (int)(TurnauksenKeskivahvuus + muutos) * VastustajienLkm) / (UusiPelimaara + VastustajienLkm);
                UusiPelimaara += VastustajienLkm;

                // turnauksen tulos annettu, joten ei laskettavaa
                TurnauksenTulos2x = annettuTurnauksenTulos2x;

                // koska laskenta tehtiin kerralla, ei saatu minSeloa ja maxSeloa
                MinSelo = UusiSelo;
                MaxSelo = UusiSelo;
                //return;
            }
            else
            {
                // Varsinainen laskenta: Käydään läpi kaikki listan ottelut, jotka olivat formaatissa
                // "+1525 =1600 -1611 +1558". Tällöin myös MinSelo ja MaxSelo voidaan selvittää.
                //
                var ottelu     = ottelulista.HaeEnsimmainen(); // vastustajanSelo, ottelunTulos
                int pelattuLKM = 0;

                // Kun lista on tyhjä, saadaan ottelun tulos TULOS_MAARITTELEMATON
                while (ottelu.Item2 != Vakiot.OttelunTulos_enum.TULOS_MAARITTELEMATON)
                {
                    // päivitä seloa ja tilastoja jokaisen ottelun laskennassa, myös laske Odotustulos
                    UusiSelo = PelaaOttelu(ottelu.Item1, ottelu.Item2,
                                           (syotteet.UudenPelaajanPelitEnsinLKM > 0 && pelattuLKM >= syotteet.UudenPelaajanPelitEnsinLKM));

                    // päivitä pelimäärää vain jos oli annettu
                    if (UusiPelimaara != Vakiot.PELIMAARA_TYHJA)
                    {
                        UusiPelimaara++;
                        pelattuLKM++;
                    }
                    ottelu = ottelulista.HaeSeuraava();
                }

                // Onko pikashakin pelit annettu "väärässä formaatissa", kun pitäisi olla esim. "1.5 1622 1880 1683"
                if (!OnkoAnnettuTurnauksenTulos && alkuperaisetSyotteet.Miettimisaika <= Vakiot.Miettimisaika_enum.MIETTIMISAIKA_ENINT_10MIN)
                {
                    // asetetaan turnauksen tulokseksi otteluista "laskettu" tulos
                    // ja sitten voidaan käyttää oikeaa pikashakin vahvuusluvun laskentakaavaa
                    SetAnnettuTurnauksenTulos(TurnauksenTulos2x / 2.0F);
                }

                // Entä jos vanhan pelaajan ottelut olivatkin formaatissa "1.5 1622 1880 1683"?
                // Jos näin oli, niin unohdetaan vanha laskenta, josta käytetään vain Odotustulos sekä UusiPelimaara.
                //
                // HUOM! Seuraava ei toimisi uudella pelaajalla, mutta se erikoistapaus onkin käsitelty aiemmin
                //
                if (OnkoAnnettuTurnauksenTulos)
                {
                    //
                    // Aiemmasta laskennasta tarvitaan Odotustulos
                    // apumuuttuja selo, koska sitä tarvitaan kaavassa usein
                    //
                    int vanha = alkuperaisetSyotteet.AlkuperainenSelo; // aloitetaan alusta, oma apumuuttuja
                    TurnauksenTulos2x = annettuTurnauksenTulos2x;      // turnauksen tulos annettu, joten ei laskettavaa

                    if (alkuperaisetSyotteet.Miettimisaika <= Vakiot.Miettimisaika_enum.MIETTIMISAIKA_ENINT_10MIN)
                    {
                        //
                        // PELO: pikashakilla on oma laskentakaavansa
                        //
                        // http://skore.users.paivola.fi/selo.html kertoo:
                        // Pikashakin laskennassa Odotustulos lasketaan samoin, mutta ilman 0,85 - sääntöä.
                        // Itse laskentakaava onkin sitten hieman vaikeampi:
                        // pelo = vanha pelo + 200 - 200 * e(Odotustulos - tulos) / 10 , kun saavutettu tulos on odotustulosta suurempi
                        // pelo = vanha pelo - 200 + 200 * e(tulos - Odotustulos) / 10 , kun saavutettu tulos on odotustulosta pienempi
                        //            Loppuosan pitää olla e((tulos - Odotustulos) / 10)  eli sulut lisää, jakolasku ensin.
                        //
                        // turnauksen tulos on kokonaislukuna, pitää jakaa 2:lla
                        // Odotustulos on kokonaisluku ja pitää jakaa 100:lla
                        //
                        // Laskentakaavaan lisätty pyöristys Math.Round, jonka jälkeen kaikista Joukkuepikashakin laskennoista saadaan samat tulokset
                        if ((annettuTurnauksenTulos2x / 2.0) > (Odotustulos / 100.0))
                        {
                            UusiSelo =
                                (int)Math.Round(vanha + 200.0 - 200.0 * Math.Pow(Math.E, (Odotustulos / 100.0 - annettuTurnauksenTulos2x / 2.0) / 10.0) + 0.0001);
                        }
                        else
                        {
                            UusiSelo =
                                (int)Math.Round(vanha - 200.0 + 200.0 * Math.Pow(Math.E, (annettuTurnauksenTulos2x / 2.0 - Odotustulos / 100.0) / 10.0) + 0.0001);
                        }
                    }
                    else
                    {
                        //
                        // SELO: pidemmän miettimisajan pelit eli > 10 min
                        //
                        float lisakerroin = MaaritaLisakerroin(vanha, alkuperaisetSyotteet.Miettimisaika);
                        // Lisätään vielä pelattujen pelien lkm * 0.1
                        UusiSelo =
                            (int)Math.Round((vanha + MaaritaKerroin(vanha) * lisakerroin * (annettuTurnauksenTulos2x / 2.0 - Odotustulos / 100.0)) + ottelulista.Lukumaara * 0.1 + 0.0001);
                    }

                    // koska laskenta tehtiin kerralla, ei saatu minSeloa ja maxSeloa
                    MinSelo = UusiSelo;
                    MaxSelo = UusiSelo;
                }
            }
            Suoritusluku            = LaskeSuoritusluku(syotteet.Ottelut);
            SuorituslukuFIDE        = LaskeSuorituslukuFIDE();
            SuorituslukuLineaarinen = LaskeSuorituslukuLineaarinen();
        }