Replace a Number with a Random Number - c#

I want to make my own little encryption (it not must be secure).
I thought it would be a good idea, if the entered password would be converted to binary and then I want to change all the 1 to (2 | 3 | 9 | 7) so if we had
1101 = 2907 | 9703 ... and so on
So if we would enter 9703 we could decrypt it to 1101 again.
But I can’t find a Method to Replace these.
The Replace() Method would only do this:
1101 -> 2202 | 1101 -> 9909
And yes, i know that is not a good Method to encrypt something but I just want to code a very simple encryption on my own.
int[] replace_Ones = { 2, 3, 9, 7 };
int ServerEncryption = 1101010000111001;
ServerEncryption.Replace(1, 2);

Starting from this:
int[] replace_Ones = { 2, 3, 9, 7 }; // I removed the 0 ;)
long ServerEncryption = 1101010000111001;
You can make a method that does the following:
long FunnyEncrypt( long pseudobinary )
{
long result = 0;
long scope = 1;
while( pseudobinary > 0 )
{
// place 2 or 3 or 7 or 9 0 or 1
result += scope * GetRandomReplacement() * ( pseudobinary % 10 );
scope *= 10;
pseudobinary = pseudobinary / 10; // decimal right shift 110 / 10 -> 11
}
return result;
}
Disclaimer: untested! Corrections welcome.
GetRandomReplacement is left for practice :D - but it basically is "pick a random int out of [0..3] and use it as index into the array of [2,3,7,9]".
Example:
example input: 1101
| iteration | input | result | scope | -> | input | result | scope | GetRandomRepl |
| 1 | 1101 | 0 | 1 | -> | 110 | 7 | 10 | 7 |
| 2 | 110 | 7 | 10 | -> | 11 | 7 | 100 | - |
| 3 | 11 | 7 | 100 | -> | 1 | 307 | 1000 | 3 |
| 4 | 1 | 307 | 1000 | -> | 0 | 2307 | 10000 | 2 |
=> Result = 2307
EDIT: changed to long after testing, did not see the number is too big for int: https://dotnetfiddle.net/5X4lZu

If the problem is to replace '1' value of a binary string to a random value in { 2, 3, 9, 7 } you could do like this:
char[] replace_Ones = { '2', '3', '9', '7' };
StringBuilder ServerEncryption =new StringBuilder("1101010000111001");
Random r = new Random();
for (int i=0 ; i < ServerEncryption.Length ; i++)
{
if (ServerEncryption[i] != '0')
ServerEncryption[i] = replace_Ones[r.Next(replace_Ones.Length)];
}
Console.WriteLine(ServerEncryption);
dotnetFiddle

Related

C# logic to find offset and fetch values

I get the below resultset from a SQL query and I store it in var.
+-----------+--------+
| Rownumber | Data |
+-----------+--------+
| 0 | 9 |
| 1 | 0 |
| 2 | 4 |
| 3 | 9 |
| 4 | 15 |
| 5 | 2 |
| 6 | 1 |
| 7 | 6 |
| 8 | 0 |
| 9 | 4 |
| 10 | 1 |
| 11 | 1 |
| 12 | 1 |
| 13 | 1 |
| 14 | 1 |
| 15 | 1 |
| 16 | 1 |
| 17 | 1 |
| 18 | 1 |
| 19 | 1 |
| 20 | 1 |
| 21 | 1 |
| 22 | 1 |
+-----------+--------+
I want to write a logic in c# :
I want to add the Data column sequentially.
If the summed Data column value is more than or equal to 15, then I want to store the following value in two variables:
offset = The starting point of rownumber
Fetch = Num of rows taken to achieve the sum 15
E.g:
Iteration 1:
+-----------+--------+
| Rownumber | Data |
+-----------+--------+
| 0 | 9 |
| 1 | 0 |
| 2 | 4 |
| 3 | 9 |
+-----------+--------+
Expected variable values:
offset = 0
Fetch = 4 (num of rows taken to achieve the value of 15. Sum of value should be >= 15)
Iteration 2 :
+-----------+--------+
| Rownumber | Data |
+-----------+--------+
| 4 | 15 |
+-----------+--------+
Expected values:
offset = 4
Fetch = 1 (num of rows taken to achieve the value of 15)
Iteration 3:
+-----------+--------+
| Rownumber | Data |
+-----------+--------+
| 5 | 2 |
| 6 | 1 |
| 7 | 6 |
| 8 | 0 |
| 9 | 4 |
| 10 | 1 |
| 11 | 1 |
+-----------+--------+
Expected values:
offset = 5
Fetch = 7 (num of rows taken to achieve the value of 15)
The iteration will go on until the last value.
I supposed your model look like the following
public class Data
{
public int Rownumber { get; set; }
public int data { get; set; }
}
public class Result
{
public int offset { get; set; }
public int fetsh { get; set; }
}
and you need the following code
public List<Result> GetResults(List<Data> data)
{
var sum = 0;
var start_taking_index = 0;
List<Result> results = new List<Result>();
for (int i = 0; i < data.Count; i++)
{
sum += data[i].data;
if(sum >= 15 || i == data.Count-1)
{
// if the sum exceed 15 create new result
results.Add(new Result
{
offset = start_taking_index,
fetsh = i - start_taking_index +1,
});
// then reset the tracking variables
start_taking_index = i+1;
sum = 0;
}
}
return results;
}
here is xUnit test the scenario in the question
[Fact]
public void GetResults_test()
{
List<Data> datas = new List<Data>()
{
new Data{Rownumber = 0,data= 9},
new Data{Rownumber = 1,data= 0},
new Data{Rownumber = 2,data= 4},
new Data{Rownumber = 3,data= 9},
new Data{Rownumber = 4,data=15},
new Data{Rownumber = 5,data= 2},
new Data{Rownumber = 6,data= 1},
new Data{Rownumber = 7,data= 6},
new Data{Rownumber = 8,data= 0},
new Data{Rownumber = 9,data= 4},
new Data{Rownumber = 10,data= 1},
new Data{Rownumber = 11,data= 1},
new Data{Rownumber = 12,data= 1},
new Data{Rownumber = 13,data= 1},
new Data{Rownumber = 14,data= 1},
new Data{Rownumber = 15,data= 1},
new Data{Rownumber = 16,data= 1},
new Data{Rownumber = 17,data= 1},
new Data{Rownumber = 18,data= 1},
new Data{Rownumber = 19,data= 1},
new Data{Rownumber = 20,data= 1},
new Data{Rownumber = 21,data= 1},
new Data{Rownumber = 22,data= 1},
};
var result = GetResults(datas);
Assert.NotEmpty(result);
// first
Assert.Equal(0,result[0].offset);
Assert.Equal(4,result[0].fetsh);
// second
Assert.Equal(4, result[1].offset);
Assert.Equal(1, result[1].fetsh);
//
Assert.Equal(5, result[2].offset);
Assert.Equal(7, result[2].fetsh);
//
Assert.Equal(12, result[3].offset);
Assert.Equal(11, result[3].fetsh);
// total count count
Assert.Equal(4, result.Count);
}
I would go with:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<Data> datas = new List<Data>()
{
new Data{Rownumber = 0,data= 9},
new Data{Rownumber = 1,data= 0},
new Data{Rownumber = 2,data= 4},
new Data{Rownumber = 3,data= 9},
new Data{Rownumber = 4,data=15},
new Data{Rownumber = 5,data= 2},
new Data{Rownumber = 6,data= 1},
new Data{Rownumber = 7,data= 6},
new Data{Rownumber = 8,data= 0},
new Data{Rownumber = 9,data= 4},
new Data{Rownumber = 10,data= 1},
new Data{Rownumber = 11,data= 1},
new Data{Rownumber = 12,data= 1},
new Data{Rownumber = 13,data= 1},
new Data{Rownumber = 14,data= 1},
new Data{Rownumber = 15,data= 1},
new Data{Rownumber = 16,data= 1},
new Data{Rownumber = 17,data= 1},
new Data{Rownumber = 18,data= 1},
new Data{Rownumber = 19,data= 1},
new Data{Rownumber = 20,data= 1},
new Data{Rownumber = 21,data= 1},
new Data{Rownumber = 22,data= 1},
};
foreach(var entry in Calculate(datas))
{
Console.WriteLine("Offset: " + entry.Key + " | Fetch: " + entry.Value);
}
}
public static List<KeyValuePair<int, int>> Calculate(List<Data> data)
{
var result = new List<KeyValuePair<int, int>>();
int offset = 0, lastOffset = 0;
int sum = 0;
foreach(var entry in data)
{
sum += entry.data;
if(sum >= 15)
{
result.Add(new KeyValuePair<int, int>(lastOffset, offset - lastOffset + 1));
sum = 0;
lastOffset = offset + 1;
}
offset++;
}
return result;
}
public class Data
{
public int Rownumber { get; set; }
public int data { get; set; }
}
}
Mind that it does not have any guards - it's up to you.
System.Linq may do trick for you with Skip and TakeWhile extension methods:
static void Main()
{
// Fill source info
var source = new List<(int, int)>();
for (int i = 0; i <= 22; i++)
source.Add((i, i switch
{
0 => 9,
1 or 8 => 0,
2 or 9 => 4,
3 => 9,
4 => 15,
5 => 2,
7 => 6,
_ => 1,
}));
// Fetching result
foreach (var (offset, fetch) in GetResult(source))
Console.WriteLine($"Offset: {offset} | Fetch: {fetch}");
// Output:
// Offset: 0 | Fetch: 4
// Offset: 4 | Fetch: 1
// Offset: 5 | Fetch: 7
// Offset: 12 | Fetch: 11
Console.ReadKey();
}
static List<(int, int)> GetResult(List<(int, int)> source)
{
var result = new List<(int, int)>();
var proceededRecords = 0;
while (proceededRecords < source.Count)
{
var offset = proceededRecords;
var dataSum = 0;
var fetch = source.Skip(proceededRecords).TakeWhile((data, _) =>
{
if (dataSum >= 15)
return false;
dataSum += data.Item2;
return true;
}).Count();
proceededRecords += fetch;
result.Add((offset, fetch));
}
return result;
}
Remarks.
I used tuples to simplify example and avoid creating some Model class with RowNumber and Data properties or Result class with Offset and Fetch properties.
The idea was to loop over source collection with taking some unknown amount of tuples until sum of 2nd value in tuple is less than 15. TakeWhile help me with that. Skip was used to... skip amount of already fetched records.
While your example shows that your data indexes are sequential and start at zero, it was not stated explicitely that it will be always the case.
This solution works even if the index of the data from your database is not starting from 0, or is not sequencial (or both). Or if instead of an index you had any other kind of identifier, such as a timestamp for instance.
i.e. if your data is like
+-----------+--------+
| Rownumber | Data |
+-----------+--------
| 6 | 1 |
| 7 | 6 |
| 8 | 0 |
| 9 | 4 |
etc...
+-----------+--------+
or
+-----------+--------+
| Rownumber | Data |
+-----------+--------
| 16 | 1 |
| 7 | 6 |
| 108 | 0 |
| 9 | 4 |
| 1910 | 1 |
| 121 | 1 |
etc..
+-----------+--------+
or even
+-----------------------+--------+
| Timestamp | Data |
+-----------------------+--------+
| 2021/03/02 - 10:06:24 | 1 |
| 2021/03/02 - 12:13:03 | 6 |
| 2021/03/04 - 02:48:57 | 0 |
| 2021/05/23 - 23:38:17 | 4 |
etc...
+-----------------------+--------+
Here is the part of the code actually doing the work. It does not really add complexity compared to a solution that would work only on zero starting sequencial indexes:
var Results = new List<Result>();
var Group = new List<Data>();
var Sum = 0;
var CurrentIndex = 0;
while (Source.Any())
{
CurrentIndex = 0;
Sum = 0;
while (Sum < 15 && CurrentIndex < Source.Count)
{
Sum += Source[CurrentIndex].Value;
CurrentIndex++;
}
Group = Source.Take(CurrentIndex).ToList();
Source = Source.Skip(CurrentIndex).ToList();
Results.Add(new Result
{
Root = Group.First().Index,
Fetch = Group.Count
});
}
What it does is rather simple:
It enumerates the first elements of your collection (source) while their sum is inferior to 15 (and there is still some elements to enumerate).
It counts the number of elements just enumerated (the fetch) and get the index of the first element (the root).
It then constructs a new collection by removing the elements that were just enumerated, and starts again, using that new collection until there is no more elements to enumerate.
That is all.
The Group variable could be avoided alltogether. It would give the following code. I prefered keeping it in my example as it shows that the group itself could be used to perform any kind of operation on its content if needed.
while (Source.Any())
{
CurrentIndex = 0;
Sum = 0;
while (Sum < 15 && CurrentIndex < Source.Count)
{
Sum += Source[CurrentIndex].Value;
CurrentIndex++;
}
Results.Add(new Result
{
Root = Source.First().Index,
Fetch = CurrentIndex
});
Source = Source.Skip(CurrentIndex).ToList();
}
By the way, the second nested while loop could be avoided by using Linq, see below. However this Linq query is particular and should be used with caution.
The TakeWhile method is using an unpure lambda, i.e. the lambda relies on external data: the captured variable Sum.
While this works perfectly fine, be aware that generally this kind of Linq query could lead to problems further down the road. For instance adding .AsParallel() to such kind of query would not work at all.
while (Source.Any())
{
Sum = 0;
Group = Source.TakeWhile(e =>
{
if (Sum < 15)
{
Sum += e.Value;
return true;
}
return false;
}).ToList();
Results.Add(new Result
{
Root = Group.First().Index,
Fetch = Group.Count
});
Source = Source.Skip(Group.Count).ToList();
}
Here is the complete code, as a full runnable Linqpad query, with randomly generated data:
void Main()
{
// Random data set preparation.
var Rnd = new Random();
var NonSequencialIndexes = Enumerable
.Range(100, 300)
.Where(i => Rnd.Next(2) == 1)
.OrderBy(i => Guid.NewGuid())
.Take(30)
.ToArray();
var Source = Enumerable
.Range(0, 30)
.Select(i => new Data
{
Index = NonSequencialIndexes[i],
Value = Rnd.Next(16)
})
.ToList()
.Dump("Random data set");
// Actual code
var Results = new List<Result>();
var Group = new List<Data>();
var Sum = 0;
var CurrentIndex = 0;
while (Source.Any())
{
CurrentIndex = 0;
Sum = 0;
while (Sum < 15 && CurrentIndex < Source.Count)
{
Sum += Source[CurrentIndex].Value;
CurrentIndex++;
}
Group = Source.Take(CurrentIndex).ToList();
Source = Source.Skip(CurrentIndex).ToList();
Results.Add(new Result
{
Root = Group.First().Index,
Fetch = Group.Count
});
}
// Display results
Results.Dump("Results");
}
// You can define other methods, fields, classes and namespaces here
public class Data
{
public int Index { get; set; }
public int Value { get; set; }
}
public class Result
{
public int Root { get; set; }
public int Fetch { get; set; }
}
An example of result:
+------+-------+
| Root | Fetch |
+------+-------+
| 346 | 3 |
+------+-------+
| 121 | 3 |
+------+-------+
| 381 | 2 |
+------+-------+
| 110 | 2 |
+------+-------+
| 334 | 2 |
+------+-------+
| 226 | 2 |
+------+-------+
| 148 | 2 |
+------+-------+
| 114 | 3 |
+------+-------+
| 397 | 3 |
+------+-------+
| 274 | 3 |
+------+-------+
| 135 | 3 |
+------+-------+
| 386 | 2 |
+------+-------+
for this data collection
+-------+------+
| Index | Value|
+-------+------+
| 346 | 0|
+-------+------+
| 294 | 14|
+-------+------+
| 152 | 11|
+-------+------+
| 121 | 3|
+-------+------+
| 234 | 6|
+-------+------+
| 393 | 13|
+-------+------+
| 381 | 8|
+-------+------+
| 305 | 15|
+-------+------+
| 110 | 13|
+-------+------+
| 357 | 9|
+-------+------+
| 334 | 8|
+-------+------+
| 214 | 13|
+-------+------+
| 226 | 6|
+-------+------+
| 248 | 15|
+-------+------+
| 148 | 12|
+-------+------+
| 131 | 9|
+-------+------+
| 114 | 3|
+-------+------+
| 250 | 4|
+-------+------+
| 217 | 11|
+-------+------+
| 397 | 3|
+-------+------+
| 312 | 7|
+-------+------+
| 191 | 7|
+-------+------+
| 274 | 7|
+-------+------+
| 292 | 6|
+-------+------+
| 277 | 14|
+-------+------+
| 135 | 2|
+-------+------+
| 240 | 12|
+-------+------+
| 163 | 12|
+-------+------+
| 386 | 12|
+-------+------+
| 330 | 5|
+-------+------+

Bug in minimax for tic_tac_toe AI

I have been trying to implement an AI for the computer using minimax with alpha-beta pruning, but I m facing an unidentifiable bug. The algorithm should calculate all the possible moves of its own and the other player too, but it isn't playing back the way it should.
Here is my minimax code :
public int minimax(int[] board, char symbol, int alpha, int beta, int depth = 2)
{
int win = util.checkwin(board);
int nsymbol = (symbol == 'X' ? 1 : 2);
int mult = (symbol == compside ? 1 : -1);
if (win != -1)
{
if (win == nsymbol)
return mult;
else if (win != 0)
return (mult * -1);
else
return 0;
}
if (depth == 0)
return 0;
int[] newboard = new int[9];
Array.Copy(board, newboard, 9);
int score, i, pos = -1;
ArrayList emptyboard = new ArrayList();
emptyboard = util.filterboard(newboard);
for (i = 0; i < emptyboard.Count; i++)
{
if (i > 0)
newboard[(int)emptyboard[i - 1]] = 0;
newboard[(int)emptyboard[i]] = nsymbol;
score = minimax(newboard, util.changeside(symbol), alpha, beta, depth - 1);
if (mult == 1)
{
if (score > alpha)
{
alpha = score;
pos = (int)emptyboard[i];
}
if (alpha >= beta)
break;
}
else
{
if (score < beta)
beta = score;
if (alpha >= beta)
break;
}
}
if (depth == origdepth)
return pos;
if (mult == 1)
return alpha;
else
return beta;
}
The details of undefined functions:
util.checkwin(int[] board) = checks the board for a possible won or drawn outboard or an incomplete board, and returns the winner as 1 or 2 (player X or O), 0 for a draw, and -1 for an incomplete board.
util.filterboard(int[] newboard) = returns an arraylist containing all the positions of empty locations in board given.
util.changeside(char symbol) = simply flips X to O and O to X and returns the result.
I have tried with the depth as 2 which means it will calculate the next 2 moves (if it is winning and if the opponent can win). But the results weren't what I expected. and it is also trying to play on a filled location occasionally.
Here is an output(depth = 2):
Turn: X
| |
1 | 2 | 3
__|___|__
| |
4 | 5 | 6
__|___|__
| |
7 | 8 | 9
| |
Enter Your Choice:
Turn: O
| |
1 | 2 | 3
__|___|__
| |
X | 5 | 6
__|___|__
| |
7 | 8 | 9
| |
Enter Your Choice: 5
Turn: X
| |
1 | 2 | 3
__|___|__
| |
X | O | 6
__|___|__
| |
7 | 8 | 9
| |
Enter Your Choice:
Turn: O
| |
1 | X | 3
__|___|__
| |
X | O | 6
__|___|__
| |
7 | 8 | 9
| |
Enter Your Choice: 1
Turn: X
| |
O | X | 3
__|___|__
| |
X | O | 6
__|___|__
| |
7 | 8 | 9
| |
Enter Your Choice:
Turn: O
| |
O | X | 3
__|___|__
| |
X | O | 6
__|___|__
| |
7 | X | 9
| |
Enter Your Choice: 9
| |
O | X | 3
__|___|__
| |
X | O | 6
__|___|__
| |
7 | X | O
| |
O Wins
But it still fails to recognize my winning move.
All the other functions have been tested when played user against a user and they are all working fine. I would appreciate some help.
I am happy to provide my full code, if necessary and anything else required.
A couple of observations.
1) The if (depth == 0) return 0; should be changed to something like
if (depth == 0) return EvaluatePosition();,
because currently your algorithm will return 0 (score, corresponding to a draw) whenever it reaches depth zero (while the actual position at zero depth might not be equal - for instance, one of the sides can have huge advantage). EvaluatePosition() function should reflect the current board position (it should say something like "X has an advantage", "O is losing", "The position is more or less equal" etc, represented as a number). Note, that this will matter only if depth == 0 condition is triggered, otherwise it is irrelevant.
2) Do you really need this emptyboard stuff? You can iterate over all squares of the newboard and once you find an empty square, copy the original board, make the move on this empty square and call minimax with the copied and updated board. In pseudocode it will look something like this:
for square in board.squares:
if square is empty:
board_copy = Copy(board)
board_copy.MakeMove(square)
score = minimax(board_copy, /*other arguments*/)
/*the rest of minimax function*/
3) The if (alpha >= beta) break; piece is present in both branches (for mult == 1 and mult != 1), so you can put it after the if-else block to reduce code repetition.
4) Check if your algorithm is correct without alpha-beta pruning. The outcomes of plain minimax and alpha-beta pruning minimax should be the same, but plain minimax is easier to understand, code and debug. After your plain minimax is working properly, add enhancements like alpha-beta pruning and others.

How to efficiently get unique combinations of a list of objects

I have a single list of objects that I want to make unique combinations from.
The objects that I have are (CityObj);
public string City_Name;
public int Population;
double xcord;
double ycord;
double zcord;
The result would be a list that contains a new object (CityComboObj)
public string City_NameA;
public int PopulationA;
double xcordA;
double ycordA;
double zcordA;
public string City_NameB;
public int PopulationB;
double xcordB;
double ycordB;
double zcordB;
A sample of the dataset is as follows;
City1 | 3840 | 42 | -12 | 5
City2 | 39402 | 1 | 59 | -5
City3 | 5934 | 99 | -55 | 3
City4 | 12394 | -56 | 9 | 16
The resultant list of objects would look like;
City1 | 3840 | 42 | -12 | 5 City2 | 39402 | 1 | 59 | -5
City1 | 3840 | 42 | -12 | 5 City3 | 5934 | 99 | -55 | 3
City1 | 3840 | 42 | -12 | 5 City4 | 12394 | -56 | 9 | 16
City2 | 39402 | 1 | 59 | -5 City3 | 5934 | 99 | -55 | 3
City2 | 39402 | 1 | 59 | -5 City4 | 12394 | -56 | 9 | 16
City3 | 5934 | 99 | -55 | 3 City4 | 12394 | -56 | 9 | 16
As you can see its only the unique results returned.
Currently I am using a horribly inefficient apporach to do going this;
foreach (var element in CityListA)
{
if (!CityListB.Any(o => o.City_NameA == element.City_NameA && o.City_NameB == element.City_NameB))
{
if (!CityListB.Any(o => o.City_NameA == element.City_NameB && o.City_NameB == element.City_NameA))
{
CityListB.add(element)
}
}
}
In a nutshell the approach is to take two lists one full and one empty, compare each element of the full list with the empty list to see if it exists or the transpose exists and if it doesn't add it.
It works but it is slow, is there a better way of doing this?
Thanks
Your code needs some reengineering, for example:
internal class CityObjs : List<CityObj>
{
}
internal class CityObj
{
public string City_Name;
public int Population;
double xcord;
double ycord;
double zcord;
}
internal class CityComboObj
{
internal CityObj CityA ;
internal CityObj CityB ;
internal CityComboObj(CityObj A,CityObj B) { CityA=A ; CityB=B;}
}
internal class CityComboObjs: List<CityComboObj>
{
}
Assuming that the list CityObjs is initialized:
CityComboObjs = new CityComboObjs() ;
for (int i=0;i<CityObjs.Count-1;i++) for (int j=i+1;j<CityObjs.Count;j++)
CityComboObjs.Add(new CityComboObj(CityObjs[i],CityObjs[j]) ;
This actually works. Just replace simple integers with real objects. The idea of this code is to do it more efficiently, as you asked, without checking if the pair already exists. In your case myList[i] will return a CITY object
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var myList = (new []{1 , 2, 3, 4}).ToList();
var newList = new List<ListObject>();
var count = myList.Count;
for (int i = 0; i < count - 1; i++)
{
for(int j = i + 1; j < count; j++)
{
newList.Add(new ListObject(){ I = myList[i], J = myList[j]});
}
}
newList.ForEach(x => Console.WriteLine(x));
}
class ListObject
{
public int I {get; set;}
public int J {get; set;}
public override string ToString()
{
return I + " - " + J;
}
}
}
Output
1 - 2
1 - 3
1 - 4
2 - 3
2 - 4
3 - 4

RNGCryptoServiceProvider Normalized values distribution

I am using C# RNGCryptoServiceProvider inside a using block
byte[] values = new byte[ammountToCreate];
using (RNGCryptoServiceProvider randomizer = new RNGCryptoServiceProvider())
{
randomizer.GetBytes(values);
}
The result values are then normalized to interval [0:15], therefore no modulo bias should affect the output.
Normalization is done in this way:
byte n = (byte)(this.maxRandomValue + 1);
// loop all element in the input value, an apply modulo.
for (int i = 0; i < values.Length; i++)
{
values[i] = (byte)(values[i] % n);
}
Where maxRandomValue is equal to 15.
However, from the first test, the output seems to be not uniform.
I have generated 2916 numbers, and this is the values distribution:
+-------+--------------+
| Value | % On Total |
+-------+--------------+
| 0 | 6.52% |
| 1 | 5.90% |
| 2 | 6.10% |
| 3 | 6.34% |
| 4 | 5.73% |
| 5 | 6.89% |
| 6 | 5.49% |
| 7 | 6.86% |
| 8 | 5.66% |
| 9 | 5.97% |
| 10 | 6.58% |
| 11 | 6.04% |
| 12 | 6.48% |
| 13 | 5.97% |
| 14 | 7.17% |
| 15 | 6.31% |
+-------+--------------+
As you can see:
6 --> 5.49% of generated numbers
14 --> 7.17% of generated numbers
My fear is that maybe I have generated just few numbers and with bigger volumes the distribution becomes uniform.
Or, RNGCryptoServiceProvider inside a using is not working as expected.
Do you have any idea?

Logarithmic distribution of profits among game winners

I have a gave, which, when it's finished, has a table of players and their scores.
On the other hand i have a virtual pot of money that i want to distribute among these winners. I'm looking for a SQL query or piece of C# code to do so.
The descending sorted table looks like this:
UserId | Name | Score | Position | % of winnings | abs. winnings $
00579 | John | 754 | 1 | ? | 500 $
98983 | Sam | 733 | 2 | ? | ?
29837 | Rick | 654 | 3 | ? | ? <- there are 2 3rd places
21123 | Hank | 654 | 3 | ? | ? <- there are 2 3rd places
99821 | Buck | 521 | 5 | ? | ? <- there is no 4th, because of the 2 3rd places
92831 | Joe | 439 | 6 | ? | ? <- there are 2 6rd places
99281 | Jack | 439 | 6 | ? | ? <- there are 2 6rd places
12345 | Hal | 412 | 8 | ? | ?
98112 | Mick | 381 | 9 | ? | ?
and so on, until position 50
98484 | Sue | 142 | 50 | ? | 5 $
Be aware of the double 3rd and 6th places.
Now i want to distribute the total amount of (virtual) money ($ 10,000) among the first 50 positions. (It would be nice if the positions to distribute among (which is now 50) can be a variable).
The max and min amount (for nr 1 and nr 50) are fixed at 500 and 5.
Does anyone have a good idea for a SQL query or piece of C# code to fill the columns with % of winnings and absolute winnings $ correctly?
I prefer to have a distribution that looks a bit logarithmic like this: (which makes that the higher positions get relatively more than the lower ones).
.
|.
| .
| .
| .
| .
| .
| .
| .
| .
I haven't done SQL since 1994, but I like C# :-). The following might suit, adjust parameters of DistributeWinPot.DistributeWinPot(...) as required:
private class DistributeWinPot {
private static double[] GetWinAmounts(int[] psns, double TotWinAmounts, double HighWeight, double LowWeight) {
double[] retval = new double[psns.Length];
double fac = -Math.Log(HighWeight / LowWeight) / (psns.Length - 1), sum = 0;
for (int i = 0; i < psns.Length; i++) {
sum += retval[i] = (i == 0 || psns[i] > psns[i - 1] ? HighWeight * Math.Exp(fac * (i - 1)) : retval[i - 1]);
}
double scaling = TotWinAmounts / sum;
for (int i = 0; i < psns.Length; i++) {
retval[i] *= scaling;
}
return retval;
}
public static void main(string[] args) {
// set up dummy data, positions in an int array
int[] psns = new int[50];
for (int i = 0; i < psns.Length; i++) {
psns[i] = i+1;
}
psns[3] = 3;
psns[6] = 6;
double[] WinAmounts = GetWinAmounts(psns, 10000, 500, 5);
for (int i = 0; i < psns.Length; i++) {
System.Diagnostics.Trace.WriteLine((i + 1) + "," + psns[i] + "," + string.Format("{0:F2}", WinAmounts[i]));
}
}
}
Output from that code was:
1,1,894.70
2,2,814.44
3,3,741.38
4,3,741.38
5,5,614.34
6,6,559.24
7,6,559.24
8,8,463.41
9,9,421.84
10,10,384.00
11,11,349.55
12,12,318.20
13,13,289.65
14,14,263.67
15,15,240.02
16,16,218.49
17,17,198.89
18,18,181.05
19,19,164.81
20,20,150.03
21,21,136.57
22,22,124.32
23,23,113.17
24,24,103.02
25,25,93.77
26,26,85.36
27,27,77.71
28,28,70.74
29,29,64.39
30,30,58.61
31,31,53.36
32,32,48.57
33,33,44.21
34,34,40.25
35,35,36.64
36,36,33.35
37,37,30.36
38,38,27.64
39,39,25.16
40,40,22.90
41,41,20.85
42,42,18.98
43,43,17.27
44,44,15.72
45,45,14.31
46,46,13.03
47,47,11.86
48,48,10.80
49,49,9.83
50,50,8.95
Then how about this?
Select userid, log(score),
10000 * log(score) /
(Select Sum(log(score))
From TableName
Where score >=
(Select Min(score)
from (Select top 50 score
From TableName
Order By score desc) z))
From TableName
Order By score desc

Categories

Resources