Commit e20e8b43 authored by M1888's avatar M1888

16.4.

parent fd6dcee5
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="Lottokone.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<userSettings>
<Lottokone.Properties.Settings>
<setting name="Pelaajia" serializeAs="String">
<value>100000</value>
</setting>
</Lottokone.Properties.Settings>
</userSettings>
</configuration>
\ No newline at end of file
<Window x:Class="Lottokone.Asetukset"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Lottokone"
mc:Ignorable="d"
Title="Asetukset" Height="450" Width="800">
<Grid>
<StackPanel Orientation="Horizontal">
<StackPanel Width="250" x:Name="spSettings">
<Label FontWeight="Bold">Simulaation asetukset</Label>
<StackPanel Margin="5" Orientation="Horizontal">
<Label>Pelaajia</Label>
<TextBox Margin="5" x:Name="txbPelaajia" Text="{Binding Pelaajia, Mode=TwoWay}" />
</StackPanel>
</StackPanel>
<StackPanel>
<Label FontWeight="Bold">Omat rivit</Label>
</StackPanel>
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Lottokone
{
/// <summary>
/// Interaction logic for Asetukset.xaml
/// </summary>
public partial class Asetukset : Window
{
public Asetukset()
{
InitializeComponent();
spSettings.DataContext = Properties.Settings.Default;
}
}
}
......@@ -54,6 +54,11 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Settings.cs" />
<Page Include="Asetukset.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
......@@ -62,6 +67,9 @@
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Asetukset.xaml.cs">
<DependentUpon>Asetukset.xaml</DependentUpon>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
......@@ -73,6 +81,7 @@
<Compile Include="Model\Pelaaja.cs" />
<Compile Include="Model\Rivi.cs" />
<Compile Include="Model\Voittorivi.cs" />
<Compile Include="ObservableCollectionEx.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
......
......@@ -8,14 +8,19 @@
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel Orientation="Horizontal">
<Button x:Name="btnNext" Content="Seuraava viikko..." Click="btnNext_Click"/>
<StackPanel>
<Button x:Name="btnNext" Content="Seuraava viikko" Click="btnNext_Click"/>
<Button x:Name="btnStart" Content="Käynnistä" Click="btnStart_Click"/>
<Button x:Name="btnStop" Content="Pysäytä" Click="btnStop_Click"/>
<Button x:Name="btnSettings" Content="Asetukset" Click="btnSettings_Click" Margin="0,50,0,0"/>
</StackPanel>
<StackPanel x:Name="spLotto" Width="250">
<Label Content="Vuosi:"/>
<Label Content="{Binding Vuosi}" />
<Label Content="Viikko:"/>
<Label Content="{Binding Viikko}" />
<Label Content="Pelaajia:"/>
<Label Content="{Binding Pelaajat.Length}"/>
<Label Content="{Binding Pelaajat.Count()}"/>
<Label Content="Potti:"/>
<Label Content="{Binding Potti}"/>
<Label Content="Voittorivi:"/>
......@@ -23,7 +28,7 @@
</StackPanel>
<StackPanel>
<Label Content="Status:"/>
<ListView Height="150" Width="300" x:Name="lstStatus" ItemsSource="{Binding Value, UpdateSourceTrigger=PropertyChanged}"/>
<ListView Height="350" Width="300" x:Name="lstStatus" ItemsSource="{Binding Value, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</StackPanel>
</Grid>
......
......@@ -23,12 +23,18 @@ namespace Lottokone
public partial class MainWindow : Window
{
// Lottokoneen pääolio
private Lotto kone;
public MainWindow()
{
InitializeComponent();
kone = new Lotto();
// sidotaan lottokone stackpanelin datacontekstiksi
spLotto.DataContext = kone;
// status-ikkunaan skrollaava historia eventeistä
lstStatus.ItemsSource = kone.StatusHistory;
((INotifyCollectionChanged)lstStatus.Items).CollectionChanged += lstStatus_CollectionChanged;
}
......@@ -42,10 +48,24 @@ namespace Lottokone
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
// scroll the new item into view
lstStatus.ScrollIntoView(e.NewItems[0]);
}
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
kone.Start();
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
kone.Stop();
}
private void btnSettings_Click(object sender, RoutedEventArgs e)
{
Asetukset a = new Asetukset();
a.Show();
}
}
}
using System;
using Custom.Collections; // ObservableCollectionEx
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
......@@ -7,6 +9,7 @@ using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Lottokone.Model
{
public class Lotto : INotifyPropertyChanged
......@@ -46,7 +49,17 @@ namespace Lottokone.Model
}
}
public List<Pelaaja> Pelaajat { get; set; }
public ConcurrentBag<Pelaaja> Pelaajat { get; set; }
// neljä listaa eri voittotasoille:
// 4 oikein, 5 oikein, 6 oikein ja 7 oikein
// nämä olisi voinut periaatteessa asettaa listaan, ja
// käyttää indeksin kautta (oikein[5] olisi lista viisi oikein -tuloksista jne.)
// mutta se aiheuttaisi threadingin kanssa ongelmia.
public ConcurrentBag<Pelaaja> Oikein4 { get; set; }
public ConcurrentBag<Pelaaja> Oikein5 { get; set; }
public ConcurrentBag<Pelaaja> Oikein6 { get; set; }
public ConcurrentBag<Pelaaja> Oikein7 { get; set; }
private long potti;
public long Potti
......@@ -78,16 +91,16 @@ namespace Lottokone.Model
}
}
public ObservableCollection<string> StatusHistory;
public ObservableCollectionEx<string> StatusHistory;
public string Status
{
get
{
return StatusHistory.Last();
return StatusHistory.FirstOrDefault();
}
set
{
StatusHistory.Add(value);
StatusHistory.Insert(0, value);
RaisePropertyChanged();
}
}
......@@ -97,10 +110,11 @@ namespace Lottokone.Model
{
viikko = 0;
vuosi = 1;
Pelaajat = new List<Pelaaja>();
StatusHistory = new ObservableCollection<string>();
Pelaajat = new ConcurrentBag<Pelaaja>();
Voittorivi = new Voittorivi();
StatusHistory = new ObservableCollectionEx<string>(new List<String>());
Status = "Alustetaan pelaajia...";
for (int i = 0; i < 10000; i++)
for (int i = 0; i < Properties.Settings.Default.Pelaajia; i++)
{
Pelaaja p = new Pelaaja();
for (int j = 0; j < 5; j++)
......@@ -134,25 +148,72 @@ namespace Lottokone.Model
public void Tick()
{
Status = "Seuraava viikko...";
Viikko++;
Oikein4 = new ConcurrentBag<Pelaaja>();
Oikein5 = new ConcurrentBag<Pelaaja>();
Oikein6 = new ConcurrentBag<Pelaaja>();
Oikein7 = new ConcurrentBag<Pelaaja>();
Voittorivi = new Voittorivi();
Voittorivi.ArvoRivi();
TarkistaVoitot();
EtsiVoittajat();
Status = $"-Viikko {Viikko}-";
if (!Oikein4.IsEmpty)
Status = $"4 oikein: {Oikein4.Count()}";
if (!Oikein5.IsEmpty)
Status = $"5 oikein: {Oikein5.Count()}";
if (!Oikein6.IsEmpty)
Status = $"6 oikein: {Oikein6.Count()}";
if (!Oikein7.IsEmpty)
Status = $"7 oikein: {Oikein7.Count()}";
JaaVoitot();
}
private void TarkistaVoitot()
private void EtsiVoittajat()
{
foreach(Pelaaja p in Pelaajat)
Parallel.ForEach(Pelaajat, (p) =>
{
foreach(Rivi r in p.Rivit)
foreach (Rivi r in p.Rivit)
{
if(Voittorivi.Oikein(r) >= 5)
int oikein = r.Oikein(Voittorivi);
switch(oikein)
{
Status = $">=5 oikein! {Voittorivi.ToString()} ja {r.ToString()}";
case 4:
Oikein4.Add(p);
break;
case 5:
Oikein5.Add(p);
break;
case 6:
Oikein6.Add(p);
break;
case 7:
Oikein7.Add(p);
break;
default:
break;
}
}
}
});
}
// https://fi.wikipedia.org/wiki/Lotto_(Veikkaus)#Voittoluokat_ja_voiton_todenn%C3%A4k%C3%B6isyys
// 4 oikein: 10 e
// 5 oikein: 3% potista voittajien kesken
// 6 oikein: 2,5% potista voittajien kesken
// 6+1: 3,8% potista voittajien kesken
// 7: päävoitto
private void JaaVoitot()
{
Task neljat = Task.Run(() =>
{
Pelaaja p;
while(Oikein4.TryTake(out p) != false)
{
}
});
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
......
......@@ -28,7 +28,7 @@ namespace Lottokone.Model
Numerot = r.Numerot;
}
public void ArvoRivi()
public virtual void ArvoRivi()
{
/*for(int i = 0; i < 7; i++)
......@@ -47,18 +47,15 @@ namespace Lottokone.Model
Array.Sort(Numerot);
}
public short Oikein(object obj)
// tämä metodi tarkistaa, kuinka monta numeroa rivissä on oikein
// annettuun riviin verrattuna
public int Oikein(object obj)
{
Rivi r = obj as Rivi;
short osumia = 0;
if (r == null)
return 0;
for(int i = 0; i < Numerot.Length; i++)
if (Numerot[i] == r.Numerot[i])
osumia++;
return osumia;
return Numerot.Intersect(r.Numerot).Count();
}
public override bool Equals(object obj)
......
......@@ -9,5 +9,11 @@ namespace Lottokone.Model
public class Voittorivi : Rivi
{
public short Lisanumero { get; set; }
public override void ArvoRivi()
{
base.ArvoRivi();
// todo: lisänumero
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Threading;
/* Kopioitu täältä:
* https://www.codeproject.com/Tips/414407/Thread-Safe-Improvement-for-ObservableCollection
*
* ObservableCollection, joka toimii threadeissa
*/
namespace Custom.Collections
{
public class ObservableCollectionEx<t> : ObservableCollection<t>
{
// Override the event so this class can access it
public override event NotifyCollectionChangedEventHandler CollectionChanged;
public ObservableCollectionEx(IEnumerable<t> collection) : base(collection) { }
public ObservableCollectionEx(List<t> collection) : base(collection) { }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// Be nice - use BlockReentrancy like MSDN said
using (BlockReentrancy())
{
var eventHandler = CollectionChanged;
if (eventHandler != null)
{
Delegate[] delegates = eventHandler.GetInvocationList();
// Walk thru invocation list
foreach (NotifyCollectionChangedEventHandler handler in delegates)
{
var dispatcherObject = handler.Target as DispatcherObject;
// If the subscriber is a DispatcherObject and different thread
if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
// Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind,
handler, this, e);
else // Execute handler as is
handler(this, e);
}
}
}
}
}
}
......@@ -8,23 +8,31 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace Lottokone.Properties
{
namespace Lottokone.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("100000")]
public int Pelaajia {
get {
return ((int)(this["Pelaajia"]));
}
set {
this["Pelaajia"] = value;
}
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Lottokone.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="Pelaajia" Type="System.Int32" Scope="User">
<Value Profile="(Default)">100000</Value>
</Setting>
</Settings>
</SettingsFile>
\ No newline at end of file
namespace Lottokone.Properties {
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Settings {
public Settings() {
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
// Add code to handle the SettingsSaving event here.
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment