I am trying to make a card game, and I made my own shuffle function in rTools, but every time I update the console (e.g. using a console.readline statement) it re-randomizes the list. For example, in a list<string> of 1,2,3,4,5 and I use rTools.shuffle on it, the first three would be something like 3, 5, and 2. But after I refresh it without restarting the code, it would be a completely different series. I'm using an online editor, dotnetfiddle.net, if that changes anything.
I have tried multiple different approaches- here is my code:
using System;
using System.Collections.Generic;
namespace elementCard
{
public class rTools {
public rTools() {
dddd = DateTime.Now;
llll = dddd.Ticks;
ssss = llll.ToString().Substring(llll.ToString().Length - 8, 8);//This is because the original long was not accepted by System.Random(int)
_seed = Int32.Parse(ssss);
}
private DateTime dddd
{ get; set; }
private long llll
{ get; set; }
private string ssss
{ get; set; }
private int _seed
{ get; set; }
public List<string> shuffle(List<string> l)
{
int count = l.Count-1;
List<string> ret = new List<string>();
int ind = 0;
Random rng = new Random(_seed);
string card = null;
while (count > -1)
{
ind = rng.Next(0, count);
card = l[ind];
l.RemoveAt(ind);
ret.Add(card);
card = null;
count--;
}
return ret;
}
}
public class Program
{
public static void Main()
{
rTools rtools = new rTools();
Console.WriteLine("Hello World");
List<List<string>> playerHands = new List<List<string>>();
//💧🔥🌀🌱
List<string> deck = new List<string> {"1💧", "2💧", "3💧", "4💧", "5💧", "6💧", "7💧", "8💧", "9💧", "1🔥", "2🔥", "3🔥", "4🔥", "5🔥", "6🔥", "7🔥", "8🔥", "9🔥", "1🌀", "2🌀", "3🌀", "4🌀", "5🌀", "6🌀", "7🌀", "8🌀", "9🌀", "1🌱", "2🌱", "3🌱", "4🌱", "5🌱", "6🌱", "7🌱", "8🌱", "9🌱"};
List<string> sDeck = new List<string> {"R🔄", "S❌", "D🔳", "X⛈", "+✨", "A🌕", "A🌑"};
List<string> vDeck = new List<string> {"V◆", "V◇", "V◈"};
deck = rtools.shuffle(deck);
Console.WriteLine(deck[0]);
Console.ReadLine();
Console.ReadLine();
}
}
}
Specify a seed when creating the dictionary:
Random rng = new Random(42);
Otherwise, it will automatically initialize it with a seed based on the current date/time.
You can create a new seed at every start of the program with:
public static class rTools {
// Creates a "random" seed at every start of the program.
private static readonly int _seed = (int)DateTime.Now.Ticks;
public static List<string> shuffle(List<string> l) //Shuffle function
{
...
Random rng = new Random(_seed);
...
}
}
You can also drop the readonly keyword if you want replace the seed later, or make the rTools class non static as well as all its members. Then a new seed will be created whenever you create a new instance of this class. This gives you the full control on when you want to create a completely different series.
Here is a complete solution:
The class
public class RTools
{
private readonly int _seed = (int)DateTime.Now.Ticks;
public List<string> Shuffle(List<string> l)
{
List<string> ret = new List<string>();
Random rng = new Random(_seed);
// Since you remove items, use the current count of the list.
while (l.Count > 0) {
int ind = rng.Next(0, l.Count);
string card = l[ind];
l.RemoveAt(ind);
ret.Add(card);
}
return ret;
}
}
Body of Main method
// Lets you write fancy Unicode characters.
Console.OutputEncoding = System.Text.Encoding.UTF8;
RTools rtools = new RTools();
string input;
do {
Console.WriteLine("Hello World");
List<List<string>> playerHands = new List<List<string>>();
//💧🔥🌀🌱
List<string> deck = new List<string> { "1💧", "2💧", "3💧", "4💧", "5💧", "6💧", "7💧", "8💧", "9💧", "1🔥", "2🔥", "3🔥", "4🔥", "5🔥", "6🔥", "7🔥", "8🔥", "9🔥", "1🌀", "2🌀", "3🌀", "4🌀", "5🌀", "6🌀", "7🌀", "8🌀", "9🌀", "1🌱", "2🌱", "3🌱", "4🌱", "5🌱", "6🌱", "7🌱", "8🌱", "9🌱" };
List<string> sDeck = new List<string> { "R🔄", "S❌", "D🔳", "X⛈", "+✨", "A🌕", "A🌑" };
List<string> vDeck = new List<string> { "V◆", "V◇", "V◈" };
deck = rtools.Shuffle(deck);
foreach (string card in deck) {
Console.WriteLine(card);
}
Console.WriteLine();
input = Console.ReadLine();
if (input == "new") { // Create a completely new card deck.
rtools = new RTools();
}
} while (input != "quit");
I'm writing a Console Application in C# that takes an array of videos and transcode it as long a new GPU is free to use.
The machine where the app will run has two GPUs. But I'm really having a hard time how to build this up.
The method that does the job is FireTranscode()
private void FireTranscode(int counter)
{
Random rand = new Random();
int gpu;
lock (thisLock)
{
gpu = PickGPU(0) == true ? 0 : 1;
GPU[gpu] = false;
if (gpu == 0) { gpuZero += 1; } else { gpuOne += 1; };
Thread.Sleep(rand.Next(1, 5));
videos -= 1;
}
Console.WriteLine($"Transconding on {gpu} using thread: {Thread.CurrentThread.ManagedThreadId} {transcodeArray[Convert.ToInt32(counter), 2]}");
GPU[gpu] = true;
}
and it's triggered by ManageTranscode()
private async void ManageTrancode()
{
for(counter=0; counter < videos; counter++)
{
if (GPU[0] == false & GPU[1] == false)
{
await Task.WhenAny(transcodeList);
}
else
{
transcodeList.Add(Task.Factory.StartNew(() => FireTranscode(counter)));
}
}
}
It suppose to call the FireTranscode followed by the parameter counter, 40 times async (value of videos variable), and in case both GPU (static Dictionary<int, bool> GPU = new Dictionary<int, bool> { { 0, true }, { 1, true } }; are in use (=false) it should wait until any task finishes and free for use (=true).
I'm trying to learn how to use it correctly and I would appreciate some tips and help how to achieve this.
Thank you.
You can simplify your logic and also make it more extensible in terms of available GPU by using below code. It uses SemaphoreSlim (also mentioned by #Poul Bak) which allows degree of parallelism by defined parameters.
Also, I've refactored your code to have GPU as class (you can use Struct too).
private object lockObj = new object();
private List<GPU> availableGPUs = List<GPU>() { /* initialize GPUs here */};
private int AvailableGPUCount { get { return availableGPUs.Count(); } }
private async void ManageTrancode()
{
int maxThread = AvailableGPUCount;
SemaphoreSlim lockSlim = new SemaphoreSlim(maxThread, maxThread);
for(int counter = 0; counter < videos; counter++)
{
await lockSlim.WaitAsync();
await Trancode();
lockSlim.Release();
}
}
private async Task Trancode()
{
GPU gpu = GetAndLockGPU();
// await <<Run actual trancode here>>
ReleaseGPU(gup.Id);
}
private GPU GetAndLockGPU()
{
GPU gpu = null;
lock (lockObj)
{
gpu = availableGPUs.First(g => g.IsAvailable);
gpu.IsAvailable = false;
}
return gpu;
}
private void ReleaseGPU(int gpuId)
{
lock (lockObj)
{
availableGPUs.First(g => g.Id == gpuId).IsAvailable = true;
}
}
private class GPU
{
public int Id {get; set;}
public bool IsAvailable {get; set;} = true;
}
This is my code
static void Main(string[] args)
{
List<Thing> collection = new List<Thing>
{
new Thing { IntProp = 1, BoolProp = true },
new Thing { IntProp = 1, BoolProp = true },
new Thing { IntProp = 2, BoolProp = true },
new Thing { IntProp = 1, BoolProp = false }
};
int number = 0;
var task = Task.Factory.StartNew<bool>(() =>
{
TaskFactory ts = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously);
foreach (var item in collection)
{
if (item.BoolProp)
{
ts.StartNew(() =>
number += GetNum1(item.IntProp));
}
else
{
ts.StartNew(() =>
number += GetNum2(item.IntProp));
}
}
return true;
});
task.Wait();
Console.WriteLine(number);
}
here is are definitions of GetNum1 and GetNum2
static int GetNum1(int num)
{
for (int i = 0; i < 1000000000; i++) { } // simulate some job
return 10;
}
static int GetNum2(int num)
{
for (int i = 0; i < 500000000; i++) { } // simulate some job
return 3;
}
and here is the Thing class
class Thing
{
public bool BoolProp { get; set; }
public int IntProp { get; set; }
}
basically what I am doing is just creating the collection of Thing objects. then I create a single parent task which will have several child task (which it should await, I guess).
there is a number variable which is incremented by child task by the amount returned from GetNum1 and GetNum2 method (10 or 3). the code above should output 33 (10 + 10 + 10 + 3) as I guess, but 10 is outputted instead, Because just the first child task is awaited. If I put the breakpoint in the code and go step by step than the output is correct. Why does this happen. does it have to do something with the foreach loop inside the parent task ? Please do not start asking question like "why you need this" and "there is no need for that", this is just an example code.
The parent task is in fact waiting for (not "awaiting") the child tasks. Your problem is that the code is accessing the number variable from multiple threads without synchronization:
var mutex = new object();
int number = 0;
var task = Task.Factory.StartNew<bool>(() =>
{
TaskFactory ts = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously);
foreach (var item in collection)
{
if (item.BoolProp)
{
ts.StartNew(() =>
{
var value = GetNum1(item.IntProp);
lock (mutex) number += value;
});
}
else
{
ts.StartNew(() =>
{
var value = GetNum2(item.IntProp);
lock (mutex) number += value;
});
}
}
return true;
});
task.Wait();
lock (mutex)
Console.WriteLine(number);
Recommended reading: Parallel Tasks and Dynamic Task Parallelism.
I have a single observable sequence of messages. There is a set of subscribers that can handle these messages. Each subscriber has an execution priority. Each message must be handled once by the highest priority subscriber chosen from the list of currently subscribed subscribers. Subscribers are constantly subscribed/unsubscribed from the sequence, so we don't know the number and priorities of subscribers when constructing the sequence. Is it a possible/viable solution using rx?
To illustrate:
public class Message
{
public string Value { get; set; }
public bool IsConsumed { get; set; }
}
var subject = new Subject<Message>();
var sequence = subject.Publish().RefCount();
Action<Message, int> subscriber = (m, priority) =>
{
if (!m.IsConsumed)
{
m.IsConsumed = true;
Trace.WriteLine(priority);
}
};
var s2 = sequence.Priority(2).Subscribe(m => subscriber(m, 2));
var s1 = sequence.Priority(1).Subscribe(m => subscriber(m, 1));
subject.OnNext(new Message()); // output: 1
s1.Dispose();
subject.OnNext(new Message()); // output: 2
The missing piece to make this solution work is the Priority method which do not exist in Rx library.
This was a very interesting problem...
So, first off: I am not aware of any intrinsic Rx operators that can achieve a "routing" effect similar to what you want in this Priority extension.
That said, I was playing around in LINQPad over lunch today, and came up with a (very) hacky proof of concept that appears to work:
First, your message class
public class Message
{
public string Value { get; set; }
public bool IsConsumed { get; set; }
}
Next, the extension method wrapper-class:
public static class Ext
{
public static PrioritizedObservable<T> Prioritize<T>(this IObservable<T> source)
{
return new PrioritizedObservable<T>(source);
}
}
And what is this PrioritizedObservable<T>?
public class PrioritizedObservable<T>
: IObservable<T>, IObserver<T>, IDisposable
{
private IObservable<T> _source;
private ISubject<T,T> _intermediary;
private IList<Tuple<int, Subject<T>>> _router;
public PrioritizedObservable(IObservable<T> source)
{
// Make sure we don't accidentally duplicate subscriptions
// to the underlying source
_source = source.Publish().RefCount();
// A proxy from the source to our internal router
_intermediary = Subject.Create(this, _source);
_source.Subscribe(_intermediary);
// Holds per-priority subjects
_router = new List<Tuple<int, Subject<T>>>();
}
public void Dispose()
{
_intermediary = null;
foreach(var entry in _router)
{
entry.Item2.Dispose();
}
_router.Clear();
}
private ISubject<T,T> GetFirstListener()
{
// Fetch the first subject in our router
// ordered by priority
return _router.OrderBy(tup => tup.Item1)
.Select(tup => tup.Item2)
.FirstOrDefault();
}
void IObserver<T>.OnNext(T value)
{
// pass along value to first in line
var nextListener = GetFirstListener();
if(nextListener != null)
nextListener.OnNext(value);
}
void IObserver<T>.OnError(Exception error)
{
// pass along error to first in line
var nextListener = GetFirstListener();
if(nextListener != null)
nextListener.OnError(error);
}
void IObserver<T>.OnCompleted()
{
var nextListener = GetFirstListener();
if(nextListener != null)
nextListener.OnCompleted();
}
public IDisposable Subscribe(IObserver<T> obs)
{
return PrioritySubscribe(1, obs);
}
public IDisposable PrioritySubscribe(int priority, IObserver<T> obs)
{
var sub = new Subject<T>();
var subscriber = sub.Subscribe(obs);
var entry = Tuple.Create(priority, sub);
_router.Add(entry);
_intermediary.Subscribe(sub);
return Disposable.Create(() =>
{
subscriber.Dispose();
_router.Remove(entry);
});
}
}
And a test harness:
void Main()
{
var subject = new Subject<Message>();
var sequence = subject.Publish().RefCount().Prioritize();
Action<Message, int> subscriber = (m, priority) =>
{
if (!m.IsConsumed)
{
m.IsConsumed = true;
Console.WriteLine(priority);
}
};
var s3 = sequence.PrioritySubscribe(3, Observer.Create<Message>(m => subscriber(m, 3)));
var s2 = sequence.PrioritySubscribe(2, Observer.Create<Message>(m => subscriber(m, 2)));
var s1 = sequence.PrioritySubscribe(1, Observer.Create<Message>(m => subscriber(m, 1)));
var s11 = sequence.PrioritySubscribe(1, Observer.Create<Message>(m => subscriber(m, 1)));
subject.OnNext(new Message()); // output: 1
s1.Dispose();
subject.OnNext(new Message()); // output: 1
s11.Dispose();
subject.OnNext(new Message()); // output: 2
s2.Dispose();
subject.OnNext(new Message()); // output: 3
sequence.Dispose();
}
I have an object 'ForValidation' that has List of int as a property,
and an object 'Validator' which has a Verify(IEnumerable ForValidation) method. Verify method adds numbers in ForValidation list property.
In main function, I have IEnumerable of Validator and IEnumerable of ForValidation
every time Verify(IEnumerable) exits, the list inside ForValidation is back at 0 count.
From my understanding, objects are reference types in C# and modifications from anywhere should reflect in the same object.
I tried running visual studio debugger line by line to check that list inside 'ForValidation' is in fact being added data and then disappears after Verify method.
public class ForValidation
{
private readonly object #lock = new object();
private readonly List<int> ExistenceChecks = new List<int>();
public IEnumerable<int> ExistsPlaces => ExistenceChecks;
public string CheckProperty { get; }
public ForValidation(string checkProperty )
{
CheckProperty = checkProperty ;
}
public void ConfirmExistence(int place)
{
lock (#lock)
{
ExistenceChecks.Add(place);
}
}
}
public class Validator
{
public int ValidatorNumber { get; }
private readonly Datasource somedatasource;
public Validator(int number, Datasource someds)
{
ValidatorNumber = number;
somedatasource = someds;
}
public void Verify(IEnumerable<ForValidation> forValidations)
{
ForValidation[] copy = forValidations.ToArray();
IEnumerable<string> checkProperties = from member in copy
select member.CheckProperty;
IEnumerable<CompareAgainst> existingMembers
= somedatasource.Filter(new CheckPropertiesFilter(checkProperties)).Execute();
foreach (ForValidation forValidation in copy)
{
if (existingMembers.FirstOrDefault(m => m.CheckProperty == forValidation.CheckProperty) != null)
{
forValidation.ConfirmExistence(ValidatorNumber);
}
}
int x = copy.Length;
//each forValidation.ExistsPlaces has items until this code block
}
}
main
{
private readonly IEnumerable<ForValidation> forValidations {...}
private readonly IEnumerable<Validator> validators {...}
foreach (Validator validator in validators)
{
validator.Verify(forValidations);
// each forValidation.ExistsPlaces count is 0 again in this block
}
}
IExpect every ForValidation items inside forValidations will have remembered items inside its IEnumerable ExistsPlaces property after each Verify method by validators but it becomes 0 count after each iteration of Verify method in the foreach loop
I cannot reproduce your problem. Here is my code.
public static void Main(string[] args)
{
var validators = new[] { new Validator(666), new Validator(667) };
var forValidations = new [] { new ForValidation("v1"), new ForValidation("v2") };
Console.WriteLine("Before Verify");
foreach (var fv in forValidations)
Console.WriteLine($"Object: {fv.CheckProperty} - count of places: {fv.ExistsPlaces.Count()}");
foreach (Validator validator in validators)
validator.Verify(forValidations);
Console.WriteLine("After Verify");
foreach (var fv in forValidations)
Console.WriteLine($"Object: {fv.CheckProperty} - count of places: {fv.ExistsPlaces.Count()}");
}
Result
Before Verify
Object: v1 - count of places: 0
Object: v2 - count of places: 0
After Verify
Object: v1 - count of places: 2
Object: v2 - count of places: 2
Classes:
public class ForValidation
{
private readonly object #lock = new object();
private readonly List<int> ExistenceChecks = new List<int>();
public IEnumerable<int> ExistsPlaces => ExistenceChecks;
public string CheckProperty { get; }
public ForValidation(string checkProperty)
{
CheckProperty = checkProperty;
}
public void ConfirmExistence(int place)
{
lock (#lock)
{
ExistenceChecks.Add(place);
}
}
}
public class Validator
{
public Validator(int validatorNumber)
{
ValidatorNumber = validatorNumber;
}
public int ValidatorNumber { get; }
public void Verify(IEnumerable<ForValidation> forValidations)
{
ForValidation[] copy = forValidations.ToArray();
IEnumerable<string> checkProperties = from member in copy
select member.CheckProperty;
foreach (ForValidation forValidation in copy)
{
//if (existingMembers.FirstOrDefault(m => m.CheckProperty == forValidation.CheckProperty) != null)
{
forValidation.ConfirmExistence(ValidatorNumber);
}
}
int x = copy.Length;
//each forValidation.ExistsPlaces has items until this code block
}
}