Пример #1
0
        private int LaskeSuoritusluku(Ottelulista ottelut)
        {
            if (ottelut == null)
            {
                throw new ArgumentNullException(nameof(ottelut));
            }

            double low  = MinRating;
            double high = MaxRating;

            double guess, we;
            int    i;
            int    elo;

            int scorex100 = (int)Math.Round(100F * (TurnauksenTulos2x / 2F));

            if (scorex100 < 50)
            {
                return(-9999);
            }
            if (100 * VastustajienLkm - scorex100 < 1)
            {
                return(9999);
            }

            while (high - low > Epsilon)
            {
                we = 0.0; guess = (low + high) / 2.0;
                for (i = 0; i < VastustajienLkm; i++)
                {
                    elo = (i == 0) ? ottelut.HaeEnsimmainen().Item1 : ottelut.HaeSeuraava().Item1;
                    we += 0.5 * (1 + Erf((guess - elo) / 400F));
                }
                if (100 * we < scorex100)
                {
                    low = guess;
                }
                else
                {
                    high = guess;
                }
            }
            return((int)Math.Round(high + 0.000001));
        }
Пример #2
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();
        }