Commit e20e8b43 authored by M1888's avatar M1888

16.4.

parent fd6dcee5
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<configuration> <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> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup> </startup>
<userSettings>
<Lottokone.Properties.Settings>
<setting name="Pelaajia" serializeAs="String">
<value>100000</value>
</setting>
</Lottokone.Properties.Settings>
</userSettings>
</configuration> </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 @@ ...@@ -54,6 +54,11 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Settings.cs" />
<Page Include="Asetukset.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
...@@ -62,6 +67,9 @@ ...@@ -62,6 +67,9 @@
<DependentUpon>App.xaml</DependentUpon> <DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Asetukset.xaml.cs">
<DependentUpon>Asetukset.xaml</DependentUpon>
</Compile>
<Compile Include="MainWindow.xaml.cs"> <Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon> <DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
...@@ -73,6 +81,7 @@ ...@@ -73,6 +81,7 @@
<Compile Include="Model\Pelaaja.cs" /> <Compile Include="Model\Pelaaja.cs" />
<Compile Include="Model\Rivi.cs" /> <Compile Include="Model\Rivi.cs" />
<Compile Include="Model\Voittorivi.cs" /> <Compile Include="Model\Voittorivi.cs" />
<Compile Include="ObservableCollectionEx.cs" />
<Compile Include="Properties\AssemblyInfo.cs"> <Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
......
...@@ -8,14 +8,19 @@ ...@@ -8,14 +8,19 @@
Title="MainWindow" Height="450" Width="800"> Title="MainWindow" Height="450" Width="800">
<Grid> <Grid>
<StackPanel Orientation="Horizontal"> <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"> <StackPanel x:Name="spLotto" Width="250">
<Label Content="Vuosi:"/> <Label Content="Vuosi:"/>
<Label Content="{Binding Vuosi}" /> <Label Content="{Binding Vuosi}" />
<Label Content="Viikko:"/> <Label Content="Viikko:"/>
<Label Content="{Binding Viikko}" /> <Label Content="{Binding Viikko}" />
<Label Content="Pelaajia:"/> <Label Content="Pelaajia:"/>
<Label Content="{Binding Pelaajat.Length}"/> <Label Content="{Binding Pelaajat.Count()}"/>
<Label Content="Potti:"/> <Label Content="Potti:"/>
<Label Content="{Binding Potti}"/> <Label Content="{Binding Potti}"/>
<Label Content="Voittorivi:"/> <Label Content="Voittorivi:"/>
...@@ -23,7 +28,7 @@ ...@@ -23,7 +28,7 @@
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<Label Content="Status:"/> <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>
</StackPanel> </StackPanel>
</Grid> </Grid>
......
...@@ -23,12 +23,18 @@ namespace Lottokone ...@@ -23,12 +23,18 @@ namespace Lottokone
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
// Lottokoneen pääolio
private Lotto kone; private Lotto kone;
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
kone = new Lotto(); kone = new Lotto();
// sidotaan lottokone stackpanelin datacontekstiksi
spLotto.DataContext = kone; spLotto.DataContext = kone;
// status-ikkunaan skrollaava historia eventeistä
lstStatus.ItemsSource = kone.StatusHistory; lstStatus.ItemsSource = kone.StatusHistory;
((INotifyCollectionChanged)lstStatus.Items).CollectionChanged += lstStatus_CollectionChanged; ((INotifyCollectionChanged)lstStatus.Items).CollectionChanged += lstStatus_CollectionChanged;
} }
...@@ -42,10 +48,24 @@ namespace Lottokone ...@@ -42,10 +48,24 @@ namespace Lottokone
{ {
if (e.Action == NotifyCollectionChangedAction.Add) 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.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
...@@ -7,6 +9,7 @@ using System.Runtime.CompilerServices; ...@@ -7,6 +9,7 @@ using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Lottokone.Model namespace Lottokone.Model
{ {
public class Lotto : INotifyPropertyChanged public class Lotto : INotifyPropertyChanged
...@@ -46,7 +49,17 @@ namespace Lottokone.Model ...@@ -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; private long potti;
public long Potti public long Potti
...@@ -78,16 +91,16 @@ namespace Lottokone.Model ...@@ -78,16 +91,16 @@ namespace Lottokone.Model
} }
} }
public ObservableCollection<string> StatusHistory; public ObservableCollectionEx<string> StatusHistory;
public string Status public string Status
{ {
get get
{ {
return StatusHistory.Last(); return StatusHistory.FirstOrDefault();
} }
set set
{ {
StatusHistory.Add(value); StatusHistory.Insert(0, value);
RaisePropertyChanged(); RaisePropertyChanged();
} }
} }
...@@ -97,10 +110,11 @@ namespace Lottokone.Model ...@@ -97,10 +110,11 @@ namespace Lottokone.Model
{ {
viikko = 0; viikko = 0;
vuosi = 1; vuosi = 1;
Pelaajat = new List<Pelaaja>(); Pelaajat = new ConcurrentBag<Pelaaja>();
StatusHistory = new ObservableCollection<string>(); Voittorivi = new Voittorivi();
StatusHistory = new ObservableCollectionEx<string>(new List<String>());
Status = "Alustetaan pelaajia..."; Status = "Alustetaan pelaajia...";
for (int i = 0; i < 10000; i++) for (int i = 0; i < Properties.Settings.Default.Pelaajia; i++)
{ {
Pelaaja p = new Pelaaja(); Pelaaja p = new Pelaaja();
for (int j = 0; j < 5; j++) for (int j = 0; j < 5; j++)
...@@ -134,25 +148,72 @@ namespace Lottokone.Model ...@@ -134,25 +148,72 @@ namespace Lottokone.Model
public void Tick() public void Tick()
{ {
Status = "Seuraava viikko...";
Viikko++; Viikko++;
Oikein4 = new ConcurrentBag<Pelaaja>();
Oikein5 = new ConcurrentBag<Pelaaja>();
Oikein6 = new ConcurrentBag<Pelaaja>();
Oikein7 = new ConcurrentBag<Pelaaja>();
Voittorivi = new Voittorivi(); Voittorivi = new Voittorivi();
Voittorivi.ArvoRivi(); 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) protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
......
...@@ -28,7 +28,7 @@ namespace Lottokone.Model ...@@ -28,7 +28,7 @@ namespace Lottokone.Model
Numerot = r.Numerot; Numerot = r.Numerot;
} }
public void ArvoRivi() public virtual void ArvoRivi()
{ {
/*for(int i = 0; i < 7; i++) /*for(int i = 0; i < 7; i++)
...@@ -47,18 +47,15 @@ namespace Lottokone.Model ...@@ -47,18 +47,15 @@ namespace Lottokone.Model
Array.Sort(Numerot); 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; Rivi r = obj as Rivi;
short osumia = 0;
if (r == null) if (r == null)
return 0; return 0;
for(int i = 0; i < Numerot.Length; i++) return Numerot.Intersect(r.Numerot).Count();
if (Numerot[i] == r.Numerot[i])
osumia++;
return osumia;
} }
public override bool Equals(object obj) public override bool Equals(object obj)
......
...@@ -9,5 +9,11 @@ namespace Lottokone.Model ...@@ -9,5 +9,11 @@ namespace Lottokone.Model
public class Voittorivi : Rivi public class Voittorivi : Rivi
{ {
public short Lisanumero { get; set; } 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 @@ ...@@ -8,23 +8,31 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace Lottokone.Properties namespace Lottokone.Properties {
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default public static Settings Default {
{ get {
get
{
return defaultInstance; 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'?> <?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Lottokone.Properties" GeneratedClassName="Settings">
<Profiles> <Profiles />
<Profile Name="(Default)" /> <Settings>
</Profiles> <Setting Name="Pelaajia" Type="System.Int32" Scope="User">
<Settings /> <Value Profile="(Default)">100000</Value>
</Setting>
</Settings>
</SettingsFile> </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