Complex permutations without repetition - c#

I am trying to create a tool for a game called Monster Hunter (for personal-use)). I have worked with permutations before, but nothing this complex so i am totally stuck.
In the game you wear 5 pieces of armor. Each piece has skill points for one of many different skills. If you have 10+ skill points in a particular skill after calculating the whole set, you earn that skill.
Example:
Foo Head: Attack +2, Guard + 2
Foo Chest: Defense + 5
Foo Body: Guard + 2, Attack + 5, Defense +2
Foo Arm: Attack + 3, Speed + 4
Foo Legs: Attack + 5, Guard + 6, Defense + 3
The above set would result in 10+ in Attack, Defense, and Guard (not speed).
I would like to figure out how to find all combinations of armor pieces given 2-3 user-specified skills. So if you selected "Attack" and "Speed", it would give you all possible combinations of 5 pieces of armor that will result in +10 in both "Attack" and "Speed". There are about 60 different items for each of the 5 categories.
I know I can use LINQ to filter each of the 5 categories of armor parts so that I only get back a list of all the items that include one of the 2 specified skills, but I am lost on how to do the permutations since I am juggling 2-3 user-specified skills...
I wish I had working code to show, but I am so lost at this point I don't know where to start. I am not looking for the answer, per se, but advice on how to get there. Thanks.

1) I would try to find just for 1 skill, then filter that item set for the second / third
2) to avoid taking too much time/memory/recursion : i would sort the 5 * 60 items based on that only skill. Then i would create combinations by seeking the ones that add up to more than 10, starting from the upper skills, and stopping either when 10 is reached, or when it won't be reached.
The function that builds all combinations would look like :
1 : if we have total item skill >10 : all combination with other items are ok . stop.
2 : if current item skill is count <10 seek in the array for next biggest item for a not weared piece.
if in the array we reached 0 OR we reached a value such that (current count + value*number of piece type left ) <10 then its time to stop :-)
Otherwise add its skill count, note piece of armor type as used, then call your function for all items that might match.
well i may not be precise enough but you see the idea : use condition for the call to avoid exploding recursivity. Because 60*60*60*60*60 is a lot. and (quick)sorting 5*60=300 items is nothing.
To store your combinations, you might want to add the 'anything goes' case, to avoid storing / computing too many combination for nothing. (ex : if you have Carmak's Magical Hat, you have +100 in Coding, and you can dress any way you want, the bugs will dye ! :-) )

Related

Best way to search/filter (potentially several billion) combinations of items from multiple lists or arrays

I'm trying to write a program to optimize equipment configurations for a game. The problem is as follows:
There are six different equipment slots for a character to place an item. This is represented by 6 lists of individual items for each slot in the code containing all of the equipment owned by the player altogether.
The program will calculate the total stats of the character for each possible combination of equipment (1 from each list). These calculated stats can be filtered by specific stat min/max values and then also sorted by a specific stat to pinpoint a certain target set of stats for their character.
The program should be able to perform these queries without running out of memory or taking hours, and of course, the main problem is sifting through several billion possible combinations.
I'm not sure what the name of any supporting data structures or search algorithms to accomplish this would be called (in order to do more research towards a solution). I have come up with the following idea but I'm not sure if i'm on the right track or if someone can point me in a more effective direction.
The idea i'm pursuing is to use recursion, where each list (for each possible equipment slot) is set into a tree structure, with each progressive list acting as a child of the last. E.G.:
Weapons List
|
-----Armor List
|
------Helm List... etc
Each layer of the tree would keep a dictionary of every child path it can take containing the IDs of 1 item from each list and progressively calculating the stats given to the character (simple addition of stats from weapon + armor + helm as it traverses the tree and so on...)
When any stat with a min/max filter being applied hits it's boundary for that stat (namely, if the stat goes over the maximum before it reaches the bottom layer of the tree, it eliminates that "path" from the dictionary thus removing that entire leg of possible results from being traversed).
The main goal here is to reduce the possible tree paths to be traversed by the search algorithm and remove as many invalid results before the tree needs to calculate them to make the search as fast as possible and avoid any wasteful cycles. This seems pretty straightforward when removing items based on a "maximum" filter since when adding each item's stats progressively we can quickly tell when a stat has crossed it's expected maximum -- however when it comes to stopping paths based on a minimum total stat, I can't wrap my head around how to predict and remove these paths that won't end up above the minimum by the sixth item.
To simplify the idea, think of it like this:
I have 3 arrays of numbers
[X][0][1][2]
[0] 5 3 2
[1] 1 0 8
[2] 3 2 7
[3] 2 1 0
I want to find all combinations from the 3 arrays (sums) that are minimum of 9 and maximum of 11 total.
Each array must select at least but no more than 1 item and the sum of those selected values is what is being searched. This would need to be able to scale up to search 6+ arrays of 40+ values each essentially. Is the above approach on the right track or what is the best way to go about this (mainly using c#)
You should be able to filter out a lot of items by using a lower and upper bound for each slot:
var minimum = slots.Sum(slot => slot.Minimum);
var maximum = slots.Sum(slot => slot.Maximum);
foreach (var slot in slots)
{
var maxAvailable = maximum - slot.Maximum;
var minAvailable = minimum - slot.Minimum;
var filtered = slot.Items
// If we choose the strongest item in all the other slots and it's still below the minimum
.Where(item => item.Value + maxAvailable >= request.MinimumValue)
// If we choose the weakest item in all the other slots and its still above the maximum
.Where(item => item.Value + minAvailable <= request.MaximumValue);
}
After doing this, you can guarantee that all your combinations will be above the requested minimum, however some combinations may also be above the requested maximum, so combine this with the logic you have so far and I think you should get pretty optimal performance.

How to improve my team creation logic?

I had one day to create a program that, when given a .csv file with the columns: [Name] | [Elo Rating], would output another .csv file with balanced teams. The user can choose how many players they want per team.
This is probably the programming project I enjoyed the most, but it is highly inefficient given the rushed time frame and my limited knowledge of how best to implement such a task. It is similar to this question, but I would prefer not to simplify the process into just placing the players into teams based on the rating order (faster, but less accurate than what I already have). Can you give suggestions on how I could make this run faster without sacrificing accuracy?
The logic I went with is this:
Find all the possible team combinations.
Find the average rating of all the team combinations & find the closest team rating to that average
Select the first team that has the average rating from step 2.
Remove all the teams that have any of these players in them.
Repeat #2, #3, and #4 until all the teams are made.
Step 1 was accomplished by this answer and works excellently.
Step 2 might be more of a math question. I'm not sure if the average of the player's ratings is equal to the average ratings of all the teams. I'm using a slightly modified version of this answer because I am using a dictionary to hold the name & rating. I wouldn't need this dictionary if just averaging the player's ratings was just as accurate.
float average = teamScoreDict.Average(s => s.Value);
var closestScoreToAvg = teamScoreDict.Values.Aggregate((x, y) =>
Math.Abs(x - average) < Math.Abs(y - average) ? x : y);
Step 3
static Team FindTeam(float targetScore)
{
var selectedTeam = new Team();
//grabbing the first team with the proper score and adding it to final teams (not perfect since there could be multiple teams with the same score)
for (int i = 0; i < teams.Count; i++)
{
if (teams[i].TeamRating == targetScore)
{
selectedTeam = teams[i];
//add these players to the list of players who have already been selected
foreach (var player in teams[i].Player)
if (!usedPlayers.Contains(player.Key))
usedPlayers.Add(player.Key);
//remove the score and team then break
teamScoreDict.Remove(teams[i].Id);
teams.Remove(teams[i]);
break;
}
}
return selectedTeam;
}
Step 4 is what I believe to be the slowest part of this task. I thought removing the teams each iteration would make the subsequent team searches faster, which it does, but the removal process is slow.
static void RemoveTeamsWithUsedPlayers()
{
for (int i = teams.Count - 1; i >= 0; i--)
{
if (teams[i].Player.Any(kvp => usedPlayers.Contains(kvp.Key)))
{
teamScoreDict.Remove(teams[i].Id);
teams.Remove(teams[i]);
}
}
}
The results are excellent (My last run with 40 players into 5 man teams with elo ratings from 1300-2200 gave me 8 teams with only 19 point difference between the highest and lowest team's total score [8498 vs 8517]).
My problem is that it is extremely slow for larger team sizes. 12 players with 3 man teams is instant. 32 players in 4 man teams takes a few seconds. 40 players in 5 man teams takes many minutes because the possible K-combinations grow drastically and I'm looping through them so many times.
I hope this question is not too broad, and thank you for any suggestions.
EDIT: I went ahead and used the stopwatch class to get the times for each step as suggested. For 12 players with 3 per team (220 k-combinations).
00:00:00.0014493
00:00:00.0083637
00:00:00.0015608
00:00:00.0015930
There is also another step that I forgot. Between step 1 and step 2 I take the IEnumerable of all possible team combinations and put it into a class that I made, and calculate the total team score. This step takes 00:00:00.0042700
foreach (var team in teamList)
{
Team teamClass = new Team();
teamScore = 0.0F;
foreach (var player in team)
{
if (participants.TryGetValue(player, out tempInt))
{
teamScore += tempInt;
teamClass.Player.Add(player, tempInt);
}
}
teamClass.TeamRating = teamScore;
teamClass.Id = count;
teamScoreDict.Add(count, teamScore);
teams.Add(teamClass);
count++;
}
EDIT 2 (Improved Logic): I'm certain I could still improve this a lot, but based on the answer I marked and the comments I was able to drastically speed things up while still maintaining accuracy. The 3 person teams with 12 players take about the same time, but 4 person teams with 32 players went from 4.5229176s to 0.4067160s. Here are the adjustments I made:
I use the average of just the players. It is the same as the average of all team combinations
I remove the highest rated player and then find the combinations with one less player than I normally would.
While I am placing all these teams into the class I will use, I simultaneously check for the (closest team rating + highest player rating) to the (overall average * players per team)
Then I add the highest player back to that team and remove all the players from the list
Repeat step 2 & 3 until everyone is used up
For your average of averages side question, the answer is that you don't need your dictionary.
As for the algorithm, the easiest speedup is to say that the person with the highest rating will have to be on SOME team. So build only teams with that person, take the best. Then build teams again with some other person. And repeat. The result will be different than what you are doing currently because the person with the highest rating is not always on the team with closest to average rating, but the result is no less accurate. This will make your current O(n^m) algorithm for building a list of all possible teams into a O(n^(m-1)) algorithm.
But for a real speedup, what you need to do is follow the strategy in https://en.wikipedia.org/wiki/Subset_sum_problem#Pseudo-polynomial_time_dynamic_programming_solution and use dynamic programming to eliminate looking at teams whose scores will come out to be the same. That is, you build a data structure by number of players on the partial team so far, by total rating, the last player added. Now the second time you find, for instance, a combined score of 3500 for 3 players, you know that the teams that it leads to will have duplicate scores with what you already did, so you throw it out.
Throwing away all of those duplicates in the team generation process will reduce finding the next team from O(n^m) to O(n*m*k) where k is the range between the lowest and highest rating. And doing that n/m times will therefore take time O(n^2*k). Which should be acceptable with 5 person teams up to several hundred people.
So you build up this data structure, then sort the scores for a full team, and take the best one. Now walk the data structure backwards and you can find the selected team. Then throw it away and do this again.

Can I search memory for a specific object structure?

Last night I took CheatEngine for a ride, and I found a structure in the game i currently play. The game has 4 characters, each with "health" and "mana", both of these are 4 bytes (int). Is there a way I can scan the application to find the first occurrence?
What I found was that health of player 1 was located at 2DC2E72C, and I'm going to short it to "72C" since the other players health comes very exact after that.
Player 1 health: 72C
Player 2 health: 81C
Player 3 health: 90C
Player 4 health: 9FC
After some handywork with my trusted microsoft calculator, I found that it is 240 bytes between each players health. Players mana is 4 bytes, placed right after health, so the structure is:
000 Player 1 health
004 Player 1 mana
240 Player 2 health
244 Player 2 mana
and so on.
So my question is, could I search for this pattern in the applications memory? The pattern would be something along the line of: 2x4 bytes, 240 bytes, 2x4 bytes, 240 bytes....
If you have a text file containing the memory contents you could use regular expressions to search for the pattern you want. Boost has a good library for regular expressions.
I think there won't be a managed way to do that.
However, CheatEngine is an open source program, that does the same
http://www.cheatengine.org/
Maybe you could check out the source code and figure out which API calls you need to achive the same with C#
Update: I see, you already mentioned CheatEngine, overlooked it the first time.
I found this article on CodeProject http://www.codeproject.com/Articles/15680/How-to-write-a-Memory-Scanner-using-C
Looks simple
There was a cheat program back in the day called FreeCheese if I remember correctly. The way it worked was something like this :
Take search value from user input
Scan game's process memory for any values that match users input and
store found addresses
Ask user to change the value ingame and take
new value as input
Rescan addresses from step 2 and discard those that don't match the new value
Repeat steps 3 and 4 until an address (number of addresses) is found that always reflect the changes specified by the user
Ask the user for a new value and write that value to the addresses found
Step 6 is tricky since you will need to do type / size checks to make sure you can actually apply the new value.
Happy cheating :)

C# Sorting Based on Rating [Updated to Clarify]

I'm doing some machine learning stuff and I want to take some random samples and determine if a human agrees with the computer. To do this a user just votes up or down on a given item. Then I want to be able to sort by the items with the highest rating. I want to use something more complicated than simply up-down to get good results.
I've looked into the Wilson Interval Score and it seems like a decent solution, but I'm wondering if there are other alternatives.
I'm going to be using C# 4.0 if that matters.
Edit: Added below example;
Lets suppose I have 3 items and multiple people have voted on them according to the table:
Item Up Down
1 6 1
2 60 11
3 100 40
In this example I would like Item 3 to be listed first, item 2 second and 3 third. This is a rough approximation of my expectations.
Item 3 has the most responses and highest relative approval. Item 2 has more responses than Item 1 despite having a lower percentage approval.
I'm trying to list the items in terms of some sort of relative metric and algrotithm without using something like percent approval or net score; something more complicated.
You can impliment the IComparable interface for you class. Impliment the CompareTo(T other) method. Create a case where this obj is less than the other obj and return -1. If they are the same, return 0. If this obj is greater than the other obj return 1.
When you sort a collection using the .Sort() method, it will use your rules.
Is this what you are looking for?

Using RegEx to get Poker Hand score

I'm developing a poker game in C#. At the moment I'm trying to get the players hand score using RegEx. I search the string (composed of the cards suit and number) and look for suits or numbers to match the RegEx. If i get 2 matches then the player has a pair, 3 matches he has 3 of a kind.
I have 3 classes at the moment, a Card class (with number and suit), a Deck class (that contains 52 Cards) and a Hand class that gets five cards from the shuffled deck.
Deck class has a shuffleDeck();
Hand class has the functions to calculate the score (is in these functions that I am using RegEx).
I generate the string on which I use RegEx by adding the 5 suits and numbers that the hand has.
Is this a good idea or should I do it another way, if so, how?
Thank you for your help
PS. I am one of the unexperienced programmers that want to use a newly learned tool for everything
I do not think that a regex is the appropriate way to deal with this. You probably should be using a more sophisticated representation of a hand than a string.
You have not provided much detail, but what from what I have read, I assume you're not pushing the OOP very far...
I would have a Card class that has a Rank and Suit class instances. I would then have a deck class that handles shuffling / dealing...
I would then have a Hand class that would contain your poker hand of n Card objects...
In this way you can build up rules to evaluate each hand object, thus being more flexible and more extensible in the future...say if you want to make another card game / add support for another variant of poker...
Using Regular expressions to do all of this seems to be a pretty poor choice.
I would agree with the others, that Regex seems like a bad choice. It might work with pairs, 3 of a kind, 4 of a kind. However, it might get kind of tricky (or impossible) once you start looking at hands like flushes, straights, and 2 pair.
I think the best solution would be to evaluate the cards from best hand to worst hand, as shown here, and as soon as your find a match, then that is your hand. This ensures that you don't mistake 4 of a kind for 2 pair. Or a straight flush for just a straight, or just a flush. I would go with mmattax and create an object for the card, and an object for the hand, then you can evaluate the cards in each hand to see if they meet the required criteria for each hand.
I think prime numbers are a good solution for that.
consider :
// D H S C
colors = [7,5,3,2]
// A Q K J T 9 8 7 6 5 4 3 2
ranks = [61,59,53,43,41,37,31,29,23,19,17,13,11,61]
a unique card is identified by a color prime number * a rank prime number.
(for example, As of Diamonds : prime = 7 * 61)
so an entiere unique deck or combinaison are identified by prime * prime * prime * prime * prime
if there is a flush of Diamonds, the 5 cards deck's primes ID must by divisble ( mod = 0 ) by the flush of diamonds ID ( 7 ^ 5 because diamonds color prime is 7 )
Using a string to represent the hand seems like a poor decision. My recommendation would be to use an Enum to represent the Suit and another to represent the numeric value of the card.

Categories