Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Lottorivijoukkojen generointi

Sivun loppuun

Grez [21.05.2021 14:46:52]

#

Onko olemassa menetelmää, jolla pystyisi laskemaan minimaalisen joukon rivejä, jotka pelaamalla saisi varmasti vähintään 4 oikein lotossa?

Jos haluasi varmasti voittaa 7 oikein, niin täytyisi lotota kaikki 18 643 560 riviä.

4 oikein voiton todennäköisyys on 4774 / 466089 eli 1% luokkaa. Jos siis laittaa 98 satunnaista riviä, niin odotusarvo 4 oikein voitoille on noin 1. Saattaa kuitenkin olla että ei saa yhtään voittoa tai sitten saattaa saada useamman.

Kysymys kuuluukin, että mikä on pienin mahdollinen määrä rivejä, joilla voittaisi varmasti vähintään kerran vähintään 4 oikein?

Tein kokeellisen ohjelman, joka käy kaikki lottorivit satunnaisessa järjestyksessä läpi, ja poimii rivin, jos mikään jo poimituista riveistä ei tuottaisi vähintään 4 oikein tulosta.

Ajelin sen pari kertaa ja pienin vastaantullut määrä rivejä oli 725. Uskonkin että että vastaus aiempaan kysymykseen on 98 ja 725 välillä.

using System;
using System.Collections.Generic;
using System.Runtime.Intrinsics.X86;

namespace Lotto
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program().Run();
        }

        int allCount = 0;
        ulong[] all = new ulong[18643560];

        private void Run()
        {
            fill(0, 0, 0);
            var r = new Random();

            var own = new List<ulong>();

            while (allCount > 0)
            {
                var i = r.Next(allCount);
                bool found = false;
                foreach (var o in own)
                {
                    if (Popcnt.X64.PopCount(o & all[i]) > 3)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found) { own.Add(all[i]); }
                allCount--;
                all[i] = all[allCount];
            }

            Console.WriteLine(own.Count);
        }
        private void fill(ulong accu, int pos, int firstavail)
        {
            var mn = (ulong)1 << firstavail;
            for (int l = firstavail; l <= (33 + pos); l++)
            {
                if (pos == 6)
                {
                    all[allCount++] = accu | mn;
                }
                else
                {
                    fill(accu | mn, pos + 1, l + 1);
                }
                mn <<= 1;
            }
        }
    }
}

Pahoittelut taikanumeroiden runsaasta käytöstä. Tässä muodossa vaatii .Net Core 3 tai uudemman ja sopivan prosessorin. Muussa tapauksessa tuon PopCount komennon voi korvata tällä:

static int PopCount(ulong n)
{
    int count = 0;
    while (n > 0)
    {
        n &= (n - 1);
        count++;
    }
    return count;
}

Metabolix [21.05.2021 16:37:12]

#

Yleisesti ei ole tehokasta ratkaisua. Ratkaiset ilmeisesti nykyistä 7/40-lottoa ilman lisänumeroita. Lottovoitto-putkapostissa on selvitetty rivejä silloiseen 7/39-lottoon, olet näköjään itsekin osallistunut.

Spoiler alert! Paras toistaiseksi saavutettu ratkaisu Putkapostin 7/39-lotossa perustuu tietoon, että kun lukujoukko jaetaan kahtia, oikeasta rivistä ainakin neljä osuu samalle puolelle, joten voidaan tehdä molemmille puolille omat rivit, joilla katetaan kaikki nelikot siltä puolelta. Erilaisia jakoja voi kokeilla, mutta Golay-koodin avulla saadaan kaksikymmentäkolme lottonumeroa katettua optimaalisesti, joten mahdollisesti kannattaa jakaa siitä kohti. Muiden tapausten ratkaisua joutuu etsimään arpomalla, apuna voi käyttää vaikka simuloitua jäähdytystä (simulated annealing), ja rivejä voi yrittää painottaa sillä, montako puuttuvaa tapausta ne ratkaisevat. Itselläni on näköjään helposti muokattavissa ahne algoritmi, joka siis valitsee aina sen rivin, jolla saa peitettyä eniten puuttuvia nelikoita, ja sitten on tiedossa tuo yllä mainitun osajoukon optimiratkaisu.

Näistä palasista 7/40-lotto ratkeaa ainakin 126 + 253 = 379 rivillä, ja kun 7/39-lottoon tunnetaan vuosienkin jälkeen vain 329 rivin ratkaisu, hakemasi luku osuu melko todennäköisesti tuohon väliin.

Neutrino [21.05.2021 19:44:12]

#

Metabolix kirjoitti:

rivejä voi yrittää painottaa sillä, montako puuttuvaa tapausta ne ratkaisevat. Itselläni on näköjään helposti muokattavissa ahne algoritmi, joka siis valitsee aina sen rivin, jolla saa peitettyä eniten puuttuvia nelikoita

Minäkin kokeilin tätä joskus, mutta se ei johda kovin onnistuneeseen lopputulokseen. Aluksi "puuttuvien tapausten" peitto, sen paras osuma toimii hyvin, mutta homman edetessä peitto vajoaa ollen lopulta vain muutamia rivejä.

Eniten puuttuvia nelikoita peittävällä algoritmilla pääsee (ulkomuistista) jonnekin 400 rivin paikkeille. Parempaan pitäisi pystyä, joten jotakin fiksumpaa strategiaa onnistuminen edellyttää.

Google: Lotto wheel

Metabolix [21.05.2021 20:20:26]

#

Neutrino kirjoitti:

Eniten puuttuvia nelikoita peittävällä algoritmilla pääsee (ulkomuistista) jonnekin 400 rivin paikkeille.

Menikö jokin ohi edellisessä viestissäni vai onko meillä eri käsitys onnistuneesta tuloksesta? Mainitsemillani lisäyksillä 7/39-lotossa saavutetaan 349 riviä (tunnettu ennätys 329), ja 7/40-lotossa saadaan 379 riviä, kun esimerkiksi Grezin kokeellinen ratkaisu tuotti 725 riviä. Minusta nämä ovat jo aika hyviä tuloksia.

jlaire [21.05.2021 22:29:19]

#

Metabolix kirjoitti:

Muiden tapausten ratkaisua joutuu etsimään arpomalla, apuna voi käyttää vaikka simuloitua jäähdytystä (simulated annealing), ja rivejä voi yrittää painottaa sillä, montako puuttuvaa tapausta ne ratkaisevat.

Simuloidun jäähdytyksen lisäksi on olemassa monia muitakin metaheuristisia menetelmiä (https://en.wikipedia.org/wiki/Metaheuristic).

Esimerkiksi tabu search.

Yleistin aikoinaan julkaisun A tabu search algorithm for the covering design problem ideoita "covering design"-ongelmasta "lottery design"-ongelmaan (lähinnä Table 2 vaati uusia tapauksia), mutta en saanut kovin kummoisia tuloksia. En itse asiassa onnistunut edes toistamaan pdf:ssä mainostettuja tuloksia covering designiin. Yksi kriittinen kohta on jätetty täysin selittämättä ja pseudokoodissa lukee vain "Compute lgtl_out and lgtl_in;". Otin toiseen artikkelin kirjoittajista yhteyttä ja ilmeisesti "Compute" viittaa johonkin innovatiiviseen fraktaalitabumenetelmään(???), josta on tarjolla tarkempaa tietoa saman kaverin toisessa julkaisussa. Syystä tai toisesta siihen ei kuitenkaan viitata. Enkä saanut toistettua tuloksia edes tämän vihjeen avulla.

Yleisesti ottaen merkittävä osa metaheuristiikkatutkimuksesta on täyttä hölynpölyä ja pseudotiedettä (https://en.wikipedia.org/wiki/List_of_metaphor-based_metaheuristics#Criticism). Tiettyyn ongelmaan voi löytää hyviä tuloksia jos jaksaa kärsivällisesti kokeilla mahdollisimman montaa ideaa yksi toisensa jälkeen, mutta loppujen lopuksi käteen ei välttämättä jää mitään yleiskäyttöistä vaan uuden ongelman kohdalla pitää taas aloittaa koko homma alusta.

Eksaktit ongelmat ja selkästi määritellyt algoritmit ovat paljon mielekkäämpiä.

Grez [22.05.2021 07:54:03]

#

Metabolix kirjoitti:

Lottovoitto-putkapostissa on selvitetty rivejä silloiseen 7/39-lottoon, olet näköjään itsekin osallistunut.

Mietinkin, että tämä pulma tuntuu jotenkin tutulta. :D Kuten tuosta aiemman putkapostin tuloksestakin voi päätellä, niin silloinen menetelmäni oli samaa huonousluokkaa tähän laittamani koodin kanssa. Eli silloinkin taisin arpoa satunnaisia rivejä ja valita pienimmän löydetyn setin.

Kiitoksia kaikista vinkeistä. Tosiaan näyttää siltä että valitettavan iso määrä rivejä joutuisi tekemään. Äkkiseltäänhän sitä voisi kuvitella että jos kerran keskimäärin joka 98. rivi tuottaa 4 oikein tuloksen, niin 98 rivillä 4 oikein tuloksen saisi varmasti. Toki jos yhtään on harrastanut todennäköisyyslaskentaa niin tietää että niin ei ole.

Grez [22.05.2021 09:46:14]

#

Neutrino kirjoitti:

Google: Lotto wheel

Lottowheeleissä pitäisi valita tietyt "onnennumerot", joten ne ei nyt sovellu ihan tähän. Tai sitten tietysti asiaa voisi ajatella nollan onnennumeron lotto wheelinä.

Grez [22.05.2021 09:50:32]

#

Pohdin että tätä "pakotetun voiton" pulmaa voisi soveltaa myös Eurojackpottiin. Siinähän 2+1 rivin todennäköisyys on luokkaa 1:42.

Tuosta yhdestä tähtinumerosta näkeekin jo todella helposti miksi pakotus vaatii reippaasti enemmän rivejä kuin yhden voiton odotusarvo: Kun onnennumeroita on 10 ja niitä arvotaan kaksi ja jomman kumman pitäisi täsmätä, niin yhden osuman odotusarvoon riittää 5 riviä. Jos taas haluaa olla varma, niin tarvitsee 9 riviä.

neosofta [22.05.2021 10:36:04]

#

Ja voittoa pukkaa?

Grez [22.05.2021 14:42:17]

#

Tappiollehan noissa jää tietenkin millä tahansa systeemillä.

Voittoa voi pukata vain jos on tuuria, mutta ei siihen systeemiä tarvitse. Parhaiten voitolle jää jos pelaa yhden rivin ja on niin hyvä tuuri että voittaa ainoana päävoiton.

The Alchemist [22.05.2021 15:59:06]

#

Grez kirjoitti:

Tappiollehan noissa jää tietenkin millä tahansa systeemillä.

Voittoa voi pukata vain jos on tuuria, mutta ei siihen systeemiä tarvitse. Parhaiten voitolle jää jos pelaa yhden rivin ja on niin hyvä tuuri että voittaa ainoana päävoiton.

Tämä ei ole yksikäsitteisesti totta, sillä joinakin viikkoina päävoitto on niin paljon tavallista suurempi, että siitä jäisi enemmän käteen vaikka jakaisi sen yhden tai kahden muun henkilön kanssa, kuin voittamalla yksin niinä viikonloppuina, kun päävoitto on "pieni".

Metabolix [22.05.2021 16:32:56]

#

Grez kirjoitti:

Äkkiseltäänhän sitä voisi kuvitella että jos kerran keskimäärin joka 98. rivi tuottaa 4 oikein tuloksen, niin 98 rivillä 4 oikein tuloksen saisi varmasti. Toki jos yhtään on harrastanut todennäköisyyslaskentaa niin tietää että niin ei ole.

Toisaalta aiemmassa keskustelussa mainittiin, että 99-prosenttisen ratkaisun saisi jo merkittävästi pienemmällä rivimäärällä kuin täydellisen. Pitää varmasti paikkansa, mutta en itse testannut rivimääriä.

Jos haluaa oikeasti näitä lottorivejä pelata, ehkä kannattaa silloin valita juuri ahneella algoritmilla parhaiten peittäviä rivejä, kunnes uuden rivin hyötysuhde laskee liian matalaksi. Raja on tietysti henkilöstä riippuva; rahallinen odotusarvo on tappiolla ensimmäisestä rivistä alkaen ja huononee vain rivejä lisäämällä. Kaikkein varminta rahaa saa, kun ulkoistaa pelaamisen riskin eli myy rivit jollekulle muulle pelattavaksi.

jlaire kirjoitti:

Simuloidun jäähdytyksen lisäksi on olemassa monia muitakin metaheuristisia menetelmiä (https://en.wikipedia.org/wiki/Metaheuristic).

Kiitos tarkennuksesta. Pitäisi varmaan opetella käyttämään tuota termiä. En edes tarkoittanut tarkalleen simuloitua jäähdytystä (jonka tarkka toteutus tuntuu typerältä) vaan ylipäänsä sitä ideaa, että ei arvota aina uusia lottorivejä alusta asti vaan yritetään jotenkin optimoida jo löydettyä ratkaisua.

Grez [22.05.2021 16:49:51]

#

The Alchemist kirjoitti:

Tämä ei ole yksikäsitteisesti totta, sillä joinakin viikkoina päävoitto on niin paljon tavallista suurempi, että siitä jäisi enemmän käteen vaikka jakaisi sen yhden tai kahden muun henkilön kanssa, kuin voittamalla yksin niinä viikonloppuina, kun päävoitto on "pieni".

Kyllä se, mitä sanoin on yksikäsitteisesti totta. Voittamiseen (siis siihen että saa takaisin enemmän kuin mitä on sijoittanut) tarvitaan aina tuuria. Tottakai tiedän, että pelityylillä voi jonkin verran vaikuttaa lopputulokseen. Eli kärjistäen sanoen typerästi pelaamalla häviää vielä enemmän.

Ilman tuuria päävoiton saaminen edellyttäisi kaikkien rivien pelaamista, eikä se nykysäännöillä näytä koskaan olevan kannattavaa.

Esimerkiksi Eurojackpotissa (palautusprosentti pitkässä juoksussa n. 50%) vuoden 2020 viikolla 18 oli ennätyssuuret voitot. Ensimmäisellä tasolla jaettiin 90M ja 2. tason kesken 24M. Kaikki voitot oli yhteensä 133 170 003,90€. Kaikkien rivien pelaaminen olisi maksanut 190 688 400€.

Lotossa pitkän juoksun palautus% on vain vajaa 40%, joten ei ole vaikea arvata että siinä voitolle pääseminen on vielä vaikeampaa.

Suurin lottopotti tähän mennessä on ollut 14/2021. Jos voittaja tuolla kierroksella olisi ollut kaikki rivit pelannut (18 643 560 eurolla), niin voittoja olisi ropissut yhteensä alle 19 690 651,08 € (koska osa voittoluokkien summista olisi mennyt muille pelaajille). Eli ihan huippukierroksella saattaa niukin naukin jäädä voitolle, jos käy niin hyvä tuuri että kukaan muu ei saa päävoittoa. Eli voitolle jääminen edellyttää tässäkin tapauksessa sitä tuuria.

neosofta [23.05.2021 00:14:05]

#

Poistettu!

Metabolix [23.05.2021 03:01:52]

#

neosofta kirjoitti:

Mun ikivanha HP vääntää tätä hieman alle 4 min. – – tähänastiset tulokset välillä 723 - 738

Grezin koodi on lyhyempi ja selvempi ja tuottaa samanlaisen tuloksen, joten mikä on lisäarvo?

Jos aiemmin mainitsemani Golay-koodi kiinnostaa, tässä on sen sovellus Grezin kysymykseen, tuloksena 495 lottoriviä. Tästä voi huomattavasti parantaa tulosta menetelmillä, jotka on jo edellä kerrottu.

#include <iostream>
#include <bit>
#include <stdint.h>

void tulosta(uint64_t rivi) {
	for (auto i = rivi; i; i ^= i & -i) {
		std::cout << (1 + std::countr_zero(i)) << ' ';
	}
	std::cout << '\n';
}

int main() {
	uint32_t gen[12] = {
		0x40051d, 0x20068e, 0x100347, 0x0805a3, 0x0406d1, 0x020768,
		0x0103b4, 0x0081da, 0x0040ed, 0x002476, 0x00123b, 0x000fff
	};
	// Kokeillaan kaikki osajoukot näistä 12 rivistä, yhdistys xorilla.
	for (int i = 0; i <= 0xfff; ++i) {
		uint64_t rivi = 0;
		for (int j = 0; j < 12; ++j) {
			if (i & (1 << j)) {
				rivi ^= gen[j];
			}
		}
		// Jos riviin jää 7 bittiä, se kelpaa lottoriviksi.
		if (std::popcount(rivi) == 7) {
			tulosta(rivi);
			if (std::popcount(rivi << 17 >> 23) >= 4) {
				tulosta(rivi << 17);
			}
		}
	}
}

neosofta [23.05.2021 07:08:26]

#

Metabolix kirjoitti:

Grezin koodi on lyhyempi ja selvempi...joten mikä on lisäarvo?

[epätasaus]Ehkäpä Grez oli hieman meikäläistä selvempi kirjoitellessaan koodiaan.[/epätasaus]
Ja kuten jo edellisessä mainitsin, niin mitään lisäarvoa ei Lotosta tullut tälläkään kertaa :-D

neosofta [23.05.2021 13:21:08]

#

Metabolinen ulostejutska VB.NET: Poistettu!

AtskaFin [23.05.2021 13:47:59]

#

Mun mielestä tämänkaltaisista trolliviesteistä voisi iskeä tilin jäihin vähintään vaikka viikoksi

Metabolix [23.05.2021 18:57:51]

#

AtskaFin kirjoitti:

Mun mielestä tämänkaltaisista trolliviesteistä voisi iskeä tilin jäihin vähintään vaikka viikoksi

Olen samaa mieltä, mutta ehkä viikko on alkuun liioittelua. Koeta nyt neosofta käyttäytyä ihmisiksi, lopeta ulostukset ja jutskat ja kirjoita viestejä vain selvänä. Lopeta myös pelleily sisennyksillä, ei tämä ole mikään keski-ikäisten Word, jossa välilyönneillä asetellaan tekstiä.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta