MainWindow.xaml.cs 16.1 KB
Newer Older
M1888's avatar
M1888 committed
1 2
using System;
using System.Collections.Generic;
M1888's avatar
M1888 committed
3
using System.Collections.ObjectModel;
M1888's avatar
M1888 committed
4
using System.Collections.Specialized;
M1888's avatar
M1888 committed
5
using System.Diagnostics;
M1888's avatar
M1888 committed
6
using System.Globalization;
M1888's avatar
M1888 committed
7 8
using System.Linq;
using System.Text;
M1888's avatar
M1888 committed
9
using System.Threading;
M1888's avatar
M1888 committed
10 11 12 13 14 15
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
M1888's avatar
M1888 committed
16
using System.Windows.Markup;
M1888's avatar
M1888 committed
17 18 19 20
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
M1888's avatar
M1888 committed
21
using Lottokone.Model;
M1888's avatar
M1888 committed
22 23 24 25 26 27 28 29

namespace Lottokone
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
M1888's avatar
M1888 committed
30
        // Lottokoneen pääolio
M1888's avatar
M1888 committed
31
        private Lotto kone;
M1888's avatar
M1888 committed
32

M1888's avatar
M1888 committed
33 34
        // Meidän pelaaja
        private Pelaaja pelaaja;
M1888's avatar
M1888 committed
35
        // Meidän voittohostoria, ja lukko-objekti jotta voidaan käyttää sitä threadeista
M1888's avatar
M1888 committed
36 37 38
        private ObservableCollection<string> voitot;
        private object voittolukko;

M1888's avatar
M1888 committed
39 40 41
        // tähän tallennetaan oletuksena imgLotto-kuvassa oleva kuva.
        // Se voidaan sitten helposti palauttaa, kun ollaan hetki näytetty jotain muuta kuvaa
        private ImageSource oletuskuva;
M1888's avatar
M1888 committed
42 43

        // eri voittoluokkien kuvat, ja laskuri joka kertoo missä kuvassa ollaan menossa.
M1888's avatar
M1888 committed
44 45 46 47 48 49 50 51
        private BitmapImage img5oikein;
        private BitmapImage img6oikein;
        private BitmapImage img7oikein;
        private short kuvanro;

        // Tällä katsotaan, joko kuva pitäisi vaihtaa takaisin oletukseen.
        private Stopwatch kuvakello;

M1888's avatar
M1888 committed
52 53 54 55 56 57 58 59 60 61 62 63
        // Tämä ajaa meidän pelilooppia kun starttia painetaan
        private Thread runner;
        private bool kaynnissa = false;

        // konstruktori
        public MainWindow()
        {
            InitializeComponent();
            InitializeLottokone();
        }

        // Tässä yllä mainittu pelilooppi.
M1888's avatar
M1888 committed
64 65
        // Tämä olisi ollut ehkä järkevä toteuttaa muualla kuin täällä MainWindow.xaml.cs:ssä,
        // mutta tällä nyt mennään....
M1888's avatar
M1888 committed
66 67 68
        //
        // Itse lottokone ja sen simulaatio toimii siis ilman tätäkin pelilooppia, vaikka toisessa ohjelmassa:
        // Tämä pitää vain huolen meidän pelaajasta, joka on simulaatiossa mukana.
M1888's avatar
M1888 committed
69 70 71 72 73 74 75 76 77
        private void GameLoop()
        {
            do
            {
                kone.Tick();
                // meidän pitää tarkistaa täällä käsin pelaajamme voitot uudestaan, jotta
                // saadaan niistä tieto myös toiseen listaikkunaan.
                foreach (Lottorivi r in pelaaja.Rivit)
                {
M1888's avatar
M1888 committed
78 79
                    // tähän stringiin tallennetaan pelaajan voittoikkunaan tuleva teksti, 
                    // jos sellaista on.
M1888's avatar
M1888 committed
80 81 82 83 84 85
                    string s = "";
                    switch (r.Oikein(kone.Voittorivi))
                    {
                        case 3:
                            if (r.Numerot.Contains(kone.Voittorivi.Lisanumero))
                            {
M1888's avatar
M1888 committed
86
                                s = $"Kierros {kone.Kierros}: 3+1 oikein ({kone.Voitot[5]:C0})";
M1888's avatar
M1888 committed
87 88 89
                            }
                            break;
                        case 4:
M1888's avatar
M1888 committed
90
                            s = $"Kierros {kone.Kierros}: 4 oikein ({kone.Voitot[4]:C0})";
M1888's avatar
M1888 committed
91 92
                            break;
                        case 5:
M1888's avatar
M1888 committed
93
                            s = $"Kierros {kone.Kierros}: 5 oikein ({kone.Voitot[3]:C0})";
M1888's avatar
M1888 committed
94 95 96 97 98 99 100 101 102 103 104 105 106
                            // 5 oikein ja suuremmat luokat, niin vaihdetaan ikkunan taustaa hetken ajaksi hienommaksi.
                            if (kuvanro <= 1)
                            {
                                this.Dispatcher.Invoke(() =>
                                {
                                    this.Background = new SolidColorBrush(Color.FromArgb(255, (byte)255, (byte)191, (byte)192));
                                    imgLotto.Source = img5oikein;
                                });
                                kuvanro = 1;
                                if (kuvakello.IsRunning)
                                    kuvakello.Reset();
                                kuvakello.Start();
                            }
M1888's avatar
M1888 committed
107 108
                            break;
                        case 6:
M1888's avatar
M1888 committed
109
                            if (kuvanro <= 2)
M1888's avatar
M1888 committed
110
                            {
M1888's avatar
M1888 committed
111 112 113 114 115 116 117 118 119 120
                                this.Dispatcher.Invoke(() =>
                                {
                                    this.Background = new SolidColorBrush(Color.FromArgb(255, (byte)35, (byte)40, (byte)4));
                                    imgLotto.Source = img6oikein;
                                });
                                kuvanro = 2;
                                if (kuvakello.IsRunning)
                                    kuvakello.Reset();
                                kuvakello.Start();
                            }
M1888's avatar
M1888 committed
121
                            s = $"Kierros {kone.Kierros}: ";
M1888's avatar
M1888 committed
122
                            //  lisänumeron tarkistus
M1888's avatar
M1888 committed
123
                            if (r.Numerot.Contains(kone.Voittorivi.Lisanumero))
M1888's avatar
M1888 committed
124
                                s += $"6+1 oikein!!! {kone.Voitot[1]:C0} - Melkein jo kannattaa?!";
M1888's avatar
M1888 committed
125
                            else
M1888's avatar
M1888 committed
126
                                s += $"6 oikein! ({kone.Voitot[2]:C0})";
M1888's avatar
M1888 committed
127 128
                            break;
                        case 7:
M1888's avatar
M1888 committed
129 130 131 132 133 134 135 136 137 138 139 140
                            // päävoitto, pysäytetään peli
                            kaynnissa = false;
                            this.Dispatcher.Invoke(() =>
                            {
                                this.Background = new SolidColorBrush(Color.FromArgb(255, (byte)251, (byte)212, (byte)1));
                                imgLotto.Source = img7oikein;
                            });
                            kuvanro = 3;
                            if (kuvakello.IsRunning)
                                kuvakello.Reset();
                            kuvakello.Start();

M1888's avatar
M1888 committed
141
                            s = $"Kierros {kone.Kierros}: PÄÄVOITTO!!!! ({kone.Voitot[0]:C0}) JUMANTSUIKKA! Kannattaa ehkä lotota oikeastikin?! " +
M1888's avatar
M1888 committed
142
                                "Ellet käyttänyt kaikkea onneasi tähän....";
M1888's avatar
M1888 committed
143 144 145 146 147 148 149 150 151 152 153 154

                            // asetetaan scoreboardille pisteet.
                            // Meidän saldossa on jo päävoitto, mutta me halutaan tietää kuinka paljon oltiin miinuksella ennen sitä.
                            // Vähennetään siis päävoitto pisteistä jotka tallennetaan scoreboardille.
                            try
                            {
                                ViewModel.Scoreboard.AsetaPisteet(pelaaja.Nimi, pelaaja.Saldo - kone.Voitot[0]);
                            }
                            catch (Exception ex)
                            {
                                s = $"Pisteiden talletus tietokantaan ei onnistunut: ${ex.Message}";
                            }
M1888's avatar
M1888 committed
155 156 157

                            // Avataan voitto-ikkuna
                            new Voitto().Show();
M1888's avatar
M1888 committed
158 159 160 161
                            break;
                        default:
                            break;
                    }
M1888's avatar
M1888 committed
162 163

                    // Asetetaan uusi teksti voitot-ikkunaan, jos tarve.
M1888's avatar
M1888 committed
164
                    if (s.Length > 0)
M1888's avatar
M1888 committed
165
                    {
M1888's avatar
M1888 committed
166
                        lock (voittolukko)
M1888's avatar
M1888 committed
167 168 169 170 171
                        {
                            voitot.Insert(0, s);
                        }
                    }
                }
M1888's avatar
M1888 committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

                // jos kuvakello on käynnissä, niin meillä on eri tausta ikkunassa kun oletus
                if (kuvakello.IsRunning)
                {
                    // jos viimeisestä isosta voitosta on yli 5 sek, niin vaihdetaan kuva takaisin vanhaan.
                    if (kuvakello.ElapsedMilliseconds > 5_000)
                    {
                        kuvakello.Reset();
                        this.Dispatcher.Invoke(() =>
                        {
                            this.Background = Brushes.Black;
                            imgLotto.Source = oletuskuva;
                        });
                    }
                }
M1888's avatar
M1888 committed
187 188 189
            } while (kaynnissa);
        }

M1888's avatar
M1888 committed
190

M1888's avatar
M1888 committed
191 192 193
        // Alustetaan lottokone ja pelaaja ja kaikki muu tarvittava.
        public void InitializeLottokone()
        {
M1888's avatar
M1888 committed
194 195 196 197 198 199 200 201 202 203 204
            // tällä saadaan käyttöliittymässä luvut ja rahamäärät näkymään oikein.
            // https://stackoverflow.com/questions/7454024/setting-culture-en-in-globally-in-wpf-app
            var culture = new CultureInfo("fi-FI");
            CultureInfo.DefaultThreadCurrentCulture = culture;
            CultureInfo.DefaultThreadCurrentUICulture = culture;
            FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new
                FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));


            // luodaan lottokone ja sidotaan se stackpanelin datacontekstiksi
            kone = new Lotto();
M1888's avatar
M1888 committed
205
            spLotto.DataContext = kone;
M1888's avatar
M1888 committed
206 207

            // status-ikkunaan skrollaava historia eventeistä
M1888's avatar
M1888 committed
208 209
            // EnableCollectionSynchronization() mahdollistaa listan käyttämisen muista 
            // threadeista, ja UI-thread saa siitä silti CollectionUpdated eventin.
M1888's avatar
M1888 committed
210 211
            // Lukko-objekti annetaan sitä varten, ettei UI thread mene sörkkimään listaa sillä aikaa
            // kun me lisätään sinne asioita toisesta threadista.
M1888's avatar
M1888 committed
212
            BindingOperations.EnableCollectionSynchronization(kone.StatusHistory, kone.StatusLock);
M1888's avatar
M1888 committed
213
            lstStatus.ItemsSource = kone.StatusHistory;
M1888's avatar
M1888 committed
214 215 216 217 218 219 220

            // voitoille samat kun ylempi
            voitot = new ObservableCollection<string>();
            voittolukko = new object();
            BindingOperations.EnableCollectionSynchronization(voitot, voittolukko);
            lstVoitot.ItemsSource = voitot;

M1888's avatar
M1888 committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
            // luodaan meidän pelaaja
            pelaaja = new Pelaaja(Properties.Settings.Default.Nimi);
            pelaaja.Riveja = Properties.Settings.Default.Arparivit + Properties.Settings.Default.Vakiorivit;
            pelaaja.RivitVoimassa = Properties.Settings.Default.ArparivitVoimassa;

            // ladataan vakiorivit tietokannasta
            if (Properties.Settings.Default.Vakiorivit > 0)
            {
                try
                {
                    pelaaja.Rivit = ViewModel.Riviapuri.Lataa(Properties.Settings.Default.Vakiorivit);
                }
                catch (Exception ex)
                {
                    kone.Status = $"Virhe ladattaessa vakiorivejä: {ex.Message}";
                }
            }

            // lisätään pelaaja lottoon.
            kone.Pelaajat.Add(pelaaja);

            // sidotaan meidät pelaajan tietoikkunaan
            spPlayer.DataContext = pelaaja;

            // loppuun vielä muut tarvittavien muuttujien alustukset.
M1888's avatar
M1888 committed
246
            btnStop.IsEnabled = false;
M1888's avatar
M1888 committed
247 248 249
            oletuskuva = imgLotto.Source;
            kuvanro = 0;
            kuvakello = new Stopwatch();
M1888's avatar
M1888 committed
250 251 252 253 254 255 256 257 258 259 260 261 262

            // ja tarvittavat lottovoittaja-kuvat
            try
            {
                img5oikein = new BitmapImage(new Uri(@"Resources/lotto1.png", UriKind.Relative));
                img6oikein = new BitmapImage(new Uri(@"Resources/lotto2.png", UriKind.Relative));
                img7oikein = new BitmapImage(new Uri(@"Resources/lotto3.png", UriKind.Relative));
            }
            catch (Exception ex)
            {

                kone.Status = $"Virhe ladattaessa kuvatiedostoja: {ex.Message}";
            }
M1888's avatar
M1888 committed
263 264 265 266
        }

        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
M1888's avatar
M1888 committed
267 268
            btnStart.IsEnabled = false;
            btnNext.IsEnabled = false;
M1888's avatar
M1888 committed
269
            btnRikkaimmat.IsEnabled = false;
M1888's avatar
M1888 committed
270

M1888's avatar
M1888 committed
271 272
            // ajetaan looppi kerran. kun kaynnissa = false, niin se palautuu heti.
            GameLoop();
M1888's avatar
M1888 committed
273

M1888's avatar
M1888 committed
274
            btnNext.IsEnabled = true;
M1888's avatar
M1888 committed
275
            btnRikkaimmat.IsEnabled = true;
M1888's avatar
M1888 committed
276
            btnStart.IsEnabled = true;
M1888's avatar
M1888 committed
277 278
        }

M1888's avatar
M1888 committed
279 280
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
M1888's avatar
M1888 committed
281 282 283 284
            btnStop.IsEnabled = true;
            btnStart.IsEnabled = false;
            btnNext.IsEnabled = false;
            btnSettings.IsEnabled = false;
M1888's avatar
M1888 committed
285
            btnRikkaimmat.IsEnabled = false;
M1888's avatar
M1888 committed
286 287 288 289 290

            kaynnissa = true;
            runner = new Thread(GameLoop);
            runner.IsBackground = true;
            runner.Start();
M1888's avatar
M1888 committed
291 292 293 294
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
M1888's avatar
M1888 committed
295 296 297 298 299 300 301 302
            kaynnissa = false;
            // odotetaan max 2sek
            runner.Join(2000);

            btnNext.IsEnabled = true;
            btnStart.IsEnabled = true;
            btnStop.IsEnabled = false;
            btnSettings.IsEnabled = true;
M1888's avatar
M1888 committed
303 304
            btnRikkaimmat.IsEnabled = true;

M1888's avatar
M1888 committed
305 306 307 308
        }

        private void btnSettings_Click(object sender, RoutedEventArgs e)
        {
M1888's avatar
M1888 committed
309
            new Asetukset().ShowDialog();
M1888's avatar
M1888 committed
310

M1888's avatar
M1888 committed
311
            // kun asetuksista palataan, voidaan ottaa uudet asetukset käyttöön.
M1888's avatar
M1888 committed
312

M1888's avatar
M1888 committed
313 314 315 316 317 318 319 320 321 322
            // Ensin otetaan "keskivertopelaaja" jostain meidän listan keskivälistä.
            // Kunhan tarvittavat pelaajat on sitten saatu lisättyä tai poistettua, saadaan
            // verrattua vanhojen pelaajien tietoja tähän keskivertojäbään. Jos muutoksia tarvitaan,
            // niin sitten tehdään ne.
            // ConcurrentBag ei sinänsä takaa elementtien järjestystä mitenkään, ja me ollaan lisätty
            // meidän pelaaja tänne luultavasti viimeisimpänä joten se voi olla ensimmäisenä tai viimeisenä.
            // Tuskin kuitenkaan keskellä.
            Pelaaja tmp = kone.Pelaajat.ElementAt(kone.Pelaajat.Count() / 2);

            // Tarkistetaan, onko pelaajamäärä muuttunut
M1888's avatar
M1888 committed
323
            int curr = kone.Pelaajat.Count();
M1888's avatar
M1888 committed
324
            // Asetusten pelaajiin pitää lisätä vielä 1 koska pelaajissa on myös meidän pelaajaolio
M1888's avatar
M1888 committed
325
            int uusi = Properties.Settings.Default.Pelaajia + 1;
M1888's avatar
M1888 committed
326

M1888's avatar
M1888 committed
327 328 329 330 331 332 333 334 335 336 337 338 339
            if (curr < uusi)
                kone.LisaaPelaajia(uusi - curr, Properties.Settings.Default.Riveja);
            else if (curr > uusi)
                kone.PoistaPelaajia(curr - uusi);

            if (tmp.RivitVoimassa != Properties.Settings.Default.Voimassa)
            {
                kone.Status = $"Rivit voimassa {tmp.RivitVoimassa} -> {Properties.Settings.Default.Voimassa} viikkoa";
                foreach (Pelaaja p in kone.Pelaajat)
                {
                    p.RivitVoimassa = Properties.Settings.Default.Voimassa;
                }
            }
M1888's avatar
M1888 committed
340
            if (tmp.Riveja != Properties.Settings.Default.Riveja)
M1888's avatar
M1888 committed
341
            {
M1888's avatar
M1888 committed
342 343
                kone.Status = $"Simuloitujen pelaajien rivit {tmp.Riveja} -> {Properties.Settings.Default.Riveja}";
                foreach (Pelaaja p in kone.Pelaajat)
M1888's avatar
M1888 committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
                {
                    p.Riveja = Properties.Settings.Default.Riveja;
                }
            }

            // saatettiin poistaa pelaajia, niin varmistetaan, että meidän pelaaja on
            // yhä lotossa mukana...
            if (!kone.Pelaajat.Contains(pelaaja))
                kone.Pelaajat.Add(pelaaja);

            if (pelaaja.Nimi != Properties.Settings.Default.Nimi)
                pelaaja.Nimi = Properties.Settings.Default.Nimi;

            if (pelaaja.Riveja != Properties.Settings.Default.Arparivit + Properties.Settings.Default.Vakiorivit)
                pelaaja.Riveja = Properties.Settings.Default.Arparivit + Properties.Settings.Default.Vakiorivit;

            if (pelaaja.RivitVoimassa != Properties.Settings.Default.ArparivitVoimassa)
                pelaaja.RivitVoimassa = Properties.Settings.Default.ArparivitVoimassa;

M1888's avatar
M1888 committed
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
            // ladataan vakiorivit uudelleen
            if (Properties.Settings.Default.Vakiorivit > 0)
            {
                try
                {
                    // voidaan tyhjentää rivit, mukaan lukien arparivit, kun ne luodaan uusiksi kuitenkin
                    pelaaja.Rivit = ViewModel.Riviapuri.Lataa(Properties.Settings.Default.Vakiorivit);
                }
                catch (Exception ex)
                {
                    kone.Status = $"Virhe ladattaessa vakiorivejä: {ex.Message}";
                }
            }
        }

        private void BtnRikkaimmat_Click(object sender, RoutedEventArgs e)
        {
            new Rikkaimmat(kone.Pelaajat).ShowDialog();
M1888's avatar
M1888 committed
381
        }
M1888's avatar
M1888 committed
382 383
    }
}