Logarithmic distribution of profits among game winners - c#
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
Related
Replace a Number with a Random Number
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
How to check column name already consists in table
I have the following two datatables: Table[2] +----+-----------+----------+ | id | FirstName | LastName | +----+-----------+----------+ | 10 | Fred | Ramirez | +----+-----------+----------+ | 20 | Willie | James | +----+-----------+----------+ | 30 | Daniel | Green | +----+-----------+----------+ | 40 | Matthew | Walker | +----+-----------+----------+ | 50 | Aaron | Wright | +----+-----------+----------+ | 60 | Richard | Huey | +----+-----------+----------+ | 80 | Matthew | Walker | +----+-----------+----------+ and Table[3] +----------+---------------+-----------------+------------------+-------------------+-----------------+-------------------+-------------------+ | Services | Fred ---10--- | Willie ---20--- | Daniel ---30--- | Matthew ---40--- | Aaron ---50--- | Richard ---60--- | Matthew ---80--- | +----------+---------------+-----------------+------------------+-------------------+-----------------+-------------------+-------------------+ | XXX | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +----------+---------------+-----------------+------------------+-------------------+-----------------+-------------------+-------------------+ | AAA | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +----------+---------------+-----------------+------------------+-------------------+-----------------+-------------------+-------------------+ | CCC | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +----------+---------------+-----------------+------------------+-------------------+-----------------+-------------------+-------------------+ | DDD | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +----------+---------------+-----------------+------------------+-------------------+-----------------+-------------------+-------------------+ | YYY | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +----------+---------------+-----------------+------------------+-------------------+-----------------+-------------------+-------------------+ I need to get LastName from the Table[2] and make assign to column name as FirstName + LastName My code as follows, int userID = 0; string[] columnNameParts; Result.GridViewDataTable = ds.Tables[3]; for (int currCol = 1; currCol < Result.GridViewDataTable.Columns.Count; currCol++) { columnNameParts = Result.GridViewDataTable.Columns[currCol].ColumnName.Split(new string[] { "---" }, StringSplitOptions.RemoveEmptyEntries); userID = int.Parse(columnNameParts[columnNameParts.Length - 1]); string columnName = ds.Tables[2].Select("Id = " + userID)[0]["FirstName"].ToString() + " " + ds.Tables[2].Select("Id = " + userID)[0]["LastName"].ToString().Substring(0, 1); Result.GridViewDataTable.Columns[currCol].ColumnName = columnName; } With the above two tables data, I'm getting the following error. A column named 'Matthew W' already belongs to this DataTable It happen because Datatable have this (Matthew | Walker) record two times. Once I setting a column name using this code, string columnName = ds.Tables[2].Select("Id = " + userID)[0]["FirstName"].ToString() + " " + ds.Tables[2].Select("Id = " + userID)[0]["LastName"].ToString().Substring(0, 1); I need to check wether Datatable already consists that column name and if it's already exists I need to set 1 to end of the LastName. If same column name consists multiple time I need to add 1,2,3 likewise end of the LastName. As an example (Matthew W,Matthew W1,Matthew W2,) - how can I do it?
To check the exists column, this should work for you. Result.GridViewDataTable.Columns.Contains(tmpColumnName) Then, if you need the number after the columnName, you just put index after it. By the way, this snippet is not the best solution but I hope it can give you an idea of how to solve it. Hope this helps. int userID = 0; string[] columnNameParts; Result.GridViewDataTable = ds.Tables[3]; for (int currCol = 1; currCol < Result.GridViewDataTable.Columns.Count; currCol++) { columnNameParts = Result.GridViewDataTable.Columns[currCol].ColumnName.Split(new string[] { "---" }, StringSplitOptions.RemoveEmptyEntries); userID = int.Parse(columnNameParts[columnNameParts.Length - 1]); string columnName = ds.Tables[2].Select("Id = " + userID)[0]["FirstName"].ToString() + " " + ds.Tables[2].Select("Id = " + userID)[0]["LastName"].ToString().Substring(0, 1); //index int n = 0; //Create new temporary columnName which will add to the Columns later string tmpColumnName = columnName; //Check if column name is duplicate. while (Result.GridViewDataTable.Columns.Contains(tmpColumnName)) { //Add 1 to index n++; //Create new name such as Matthew W1,Matthew W2,Daniel G1,Matthew W3,... tmpColumnName = columnName + n.ToString(); } //Add new unique column name to Columns Result.GridViewDataTable.Columns[currCol].ColumnName = columnName; }
What is the shortest way of repeating a character n times in the middle of a string in C#
I am currently Creating a ASCII table builder which is required for some automated database reports in a GXP environment. Given that I have table rows with a width of n such as: | this | is | an | example | row | |<-- width = 32 -->| I now want to add headers and spacers such as: #================================# | this | is | an | example | row | |--------------------------------| | 1 | 2 | 3 | 4 | 5 | | 3 | 9 | 77 | 327814 | 2 | |--------------------------------| of course I could do this in the following way: List<string> asciiTable = new List<string(); string topBorder = "#"; string otherBorder = "|"; for (int i = 1; i == n; i++) { topBorder += "="; otherBorder += "-"; } topBorder += "#"; otherBorder += "|"; asciiTable.Add(topBorder); but I hope there is something such as: List<string> asciiTable = new List<string>(); asciiTable.Add("#" + /* add("=",n) */ + "#");
You could use new String('=', n); which will create a string with the character '=' repeated n times.
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