Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to create some sort of algorithm to make a computer win more than it loses at a modified game of blackjack.
Red cards will be negative, black cards were positive.
I will write it in pseudo code I want sure about the probability part in making the computer win more games (last line).
Here is my attempt:
//Hand out 2 random cards for each person selection of 2,3,4,5,6,7,8,9,J,Q,K,A.
//Store these in an array with their equivalent value.
Card =[2,3,4,5,6,7,8,9,J,Q,K,A]
Also, colour of card is random red or black.
Value_AI=0
Value_Human=0
Bust_Human=0
Bust_ AI=0
All of the below is in a big loop that loops each time a player is bust
Do this for both players, until Value_AI or Value_Human>21
If colour==red then
Value=value – card
Else
Value=value+card
If Value_AI >21 then
Bust_ AI+=1
Print “Computer has bust”
Break
If Value_Human >21
Bust_ human+=1
Print “You have bust”
Break
Else
Hand out another card for both
If Bust_ AI> Bust_ human then
**//Increase the probability of getting an ace and a card with a value of 10 for the computer**
You can make the human go before the computer. Then when they both would have busted, it will be a computer win by default because the computer won't need to go. That should change a fair game into one favoring the computer.
Right now, your pseudocode doesn't seem to include an option for either player to choose to stop receiving cards, which is the central choice to be made in Blackjack. After the newest card is received, you need to have the AI make a choice as to whether it wants another. This is probably the best point in the algorithm at which to build actual intelligence into your AI, so you can increase its probability of winning without just hard-coding wins like you suggest in your pseudocode. The simplest option is to have your AI calculate the probability that the next card will send its value over 21. Here's some pseudocode for that (it doesn't look like you remove cards from the deck after you draw them, so I'm not taking that into account):
highest_safe = 21 - value_AI
n_safe_cards = highest_safe - 1 + 13 //the second 13 is for all of the red cards and the - 1 is because 1 is not a card
prob_safe = n_safe_cards/26 //since there are 28 possible cards (I'm assuming you didn't mean to leave 10 off your list)
if prob_safe < .5:
stop taking cards
This should result in your AI winning more often than not, as it will result in it playing optimally. If you want it to be a little easier to beat, you can add some noise to the threshold at which it decides to stop taking cards.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
The game 2048 has exploded in popularity since its release in February 2014. For a description of the game and discussion of optimal algorithms, see What is the optimal algorithm for the game 2048?. Here is the source code.
A blind algorithm for 2048 is one that cannot see the board; the only feedback the algorithm receives is whether or not an attempted slide occurred (we may suppose a blocked slide produces an audible beep). A blind algorithm is practically useful for getting started in 2048 without having to give the game your undivided attention.
Here is my specific question: is there a blind algorithm for 2048 that consistently does better than a mean score of 3500 in 10^6 trials? (only post an answer you have validated)
This is the performance of the LADDER algorithm, which may be notated as (LD* RD*)* (+U). That is, one loops over "left, down repeatedly until stuck, right, down repeated until stuck" and presses up iff left, right, and down are all blocked, which occurs iff the top row(s) are completely empty and the bottom row(s) are completely full. I call this algorithm LADDER because of the letters LDDR, and because I imagine climbing down ladders like Mario in Donkey Kong. The motivation for the algorithm is to maintain an increasing gradient from top to bottom of the board, similar to many of the non-blind algorithms.
Here is a histogram for 10^6 trials of LADDER colored by top tile on the final board with bin width 32 and mean 3478.1. I generated this data by simulating the game and algorithm in Python, using probability .9 that each new tile is a 2, as in the original game. You can't see the 1024 games at this vertical scale but they are sparsely distributed between 8000 and 16000. The fractal structure relates to the number of occurrences of the top tile, second-from-top tile, and so on. By comparison, random button mashing gave a mean of about 800 in 10^4 trials.
The most important in the 2048 game is to concentrate the high numbers along the borders and not in the middle. So a very good strategy is to put everything along the bottom as long as possible. Your LADDER algorithm does this, but I'd like to concentrate more on the left side and not switch to the right side completely. This is the algorithm in pseudo code:
while(true)
{
if (down)
continue;
elseif(left)
continue;
elseif (right)
continue;
else
{
up;
down; //if forced to go up; go back down immediately
}
}
Using your convention this would be:
((D*L)*R)U
in words: go down as long as you can; if you cannot; go left; if you cannot go left; go right. You will rarely need to go up.
Since I won't have time shortly to implement this to use it 10⁶ times; I hope someone else can give the correct statisctics for this, but my guess is this will outperform your LADDER algorithm
Edit: This question is not a duplicate of What is the optimal algorithm for the game 2048?
That question asks 'what is the best way to win the game?'
This question asks 'how can we work out the complexity of the game?'
They are completely different questions. I'm not interested in which steps are required to move towards a 'win' state - I'm interested in in finding out whether the total number of possible steps can be calculated.
I've been reading this question about the game 2048 which discusses strategies for creating an algorithm that will perform well playing the game.
The accepted answer mentions that:
the game is a discrete state space, perfect information, turn-based game like chess
which got me thinking about its complexity. For deterministic games like chess, its possible (in theory) to work out all the possible moves that lead to a win state and work backwards, selecting the best moves that keep leading towards that outcome. I know this leads to a large number of possible moves (something in the range of the number of atoms in the universe).. but is 2048 more or less complex?
Psudocode:
for the current arrangement of tiles
- work out the possible moves
- work out what the board will look like if the program adds a 2 to the board
- work out what the board will look like if the program adds a 4 to the board
- move on to working out the possible moves for the new state
At this point I'm thinking I will be here a while waiting on this to run...
So my question is - how would I begin to write this algorithm - what strategy is best for calculating the complexity of the game?
The big difference I see between 2048 and chess is that the program can select randomly between 2 and 4 when adding new tiles - which seems add a massive number of additional possible moves.
Ultimately I'd like the program to output a single figure showing the number of possible permutations in the game. Is this possible?!
Let's determine how many possible board configurations there are.
Each tile can be either empty, or contain a 2, 4, 8, ..., 512 or 1024 tile.
That's 12 possibilities per tile. There are 16 tiles, so we get 1612 = 248 possible board states - and this most likely includes a few unreachable ones.
Assuming we could store all of these in memory, we could work backwards from all board states that would generate a 2048 tile in the next move, doing a constant amount of work to link reachable board states to each other, which should give us a probabilistic best move for each state.
To store all bits in memory, let's say we'd need 4 bits per tile, i.e. 64 bits = 8 bytes per board state.
248 board states would then require 8*248 = 2251799813685248 bytes = 2048 TB (not to mention added overhead to keep track of the best boards). That's a bit beyond what a desktop computer these days has, although it might be possible to cleverly limit the number of boards required at any given time as to get down to something that will fit on, say, a 3 TB hard drive, or perhaps even in RAM.
For reference, chess has an upper bound of 2155 possible positions.
If we were to actually calculate, from the start, every possible move (in a breadth-first search-like manner), we'd get a massive number.
This isn't the exact number, but rather a rough estimate of the upper bound.
Let's make a few assumptions: (which definitely aren't always true, but, for the sake of simplicity)
There are always 15 open squares
You always have 4 moves (left, right, up, down)
Once the total sum of all tiles on the board reaches 2048, it will take the minimum number of combinations to get a single 2048 (so, if placing a 2 makes the sum 2048, the combinations will be 2 -> 4 -> 8 -> 16 -> ... -> 2048, i.e. taking 10 moves)
A 2 will always get placed, never a 4 - the algorithm won't assume this, but, for the sake of calculating the upper bound, we will.
We won't consider the fact that there may be duplicate boards generated during this process.
To reach 2048, there needs to be 2048 / 2 = 1024 tiles placed.
You start with 2 randomly placed tiles, then repeatedly make a move and another tile gets placed, so there's about 1022 'turns' (a turn consisting of making a move and a tile getting placed) until we get a sum of 2048, then there's another 10 turns to get a 2048 tile.
In each turn, we have 4 moves, and there can be one of two tiles placed in one of 15 positions (30 possibilities), so that's 4*30 = 120 possibilities.
This would, in total, give us 1201032 possible states.
If we instead assume a 4 will always get placed, we get 120519 states.
Calculating the exact number will likely involve working our way through all these states, which won't really be viable.
I don't know if this is the right section... but here goes:
Last weeks contest on interviewstreet (Code Sprint 3) had a problem called bowling. (10 pin bowling, N frames). The point is to count the number of ways to score M points by playing N frames.
Problem Statement is here: http://pastebin.com/cyeLML8U
I'm pretty sure I've solved the problem using 2 dimensional DP. However, I get the 3rd sample data wrong (1 Frame, 25 points). The sample answer is 1, however I get 6.
This is their explanation of the sample answer:
For the third case, there is only 1 way. Score a strike in the first frame, score another strike with the first extra ball, and an additional 5 with the second extra ball.
However, can't you score a strike in the first (and only) frame, then score any of the following in the subsequent extra frames?
10 5
9 6
8 7
7 8
6 9
5 10
I can't wrap my head around why "1" is the right answer.... I've looked on wikipedia for the rules too.
Their answer is probably right, and I'm probably overlooking something REALLY obvious. Can anyone tell me what's wrong with my answer?
You cannot get 9 pins with the first extra ball and then 6 pins with the second extra ball because there is only 1 pin left standing when you bowl the second extra ball.
But if you don't get a strike on the second ball, you only have the opportunity to "pick up the spare." That is, you only get 10 pins. So if you get a strike on the first ball and then 9 pins on the second ball, the most you can get on the third ball is 1.
The way I read it, your answer is technically correct, but I don't think the question was asked correctly.
Within the constraints as set out in the link in your question, I can't see what's wrong with your solution. In real life, the pins won't actually be reset unless you've knocked them all down or have bowled twice (or both), so - as others have said - the only way you can score 25 from a 1 ball frame in real life is strike, strike, 5.
Basically, the question didn't give you the correct constraints. I don't think it's valid to say you got the answer wrong, because the question was poorly phrased.
I have this problem: I want to know how often a player holding a portfolio of poker hands beats another player holding a different portfolio of poker hands.
Each hand in a portfolio is given a weight (i.e. a likelihood). Each hand in a portfolio also knows it's own "strength". This effectively means all cards have been dealt. So please assume no more cards need to be dealt.
The reason this problem is annoying is because of duplicate card problems. For example, if I pick a random holding from each player's portfolio I must check that these holdings don't share a card -- obviously both plays can't be dealt the same card.
I want to do this quickly so that I can make many different RangeA vs RangeB comparisions per second. I have a solution, but I won't talk about it yet because I don't want to taint any responces.
-- For an Example --
Given a 5 card board of "Ah 3c 8c Td Jh":
HandRangeA = {{"As Ac", 2.5%}, {"As Ad", 2.5%}, {"Ac Kc", 5%}....}
HandRangeB = {{"As Ac", 7.5%}, {"As Ad", 7.5%}, {"Ac Kc", 5%}....}
(Each HandRange contains all possible holding that don't use a "board card")
Goal :: compute the probaility HandRangeA beats HandRangeB
I wrote some software that did this via monte carlo. That means I ran both hands to completion, 1000 times with random boards that could arrive given the situation, and counted wins and losses. It was surprisingly accurate.
Since I was doing it for texas holdem, I would do the same thing after the (1) deal, (2) flop, 3 (turn) so the player could see how their percentages changed given the board.
I really should have finished that software. But I stopped playing poker online....
I think Andrew Prock is considered the expert here; check out the discussion here, and links therein.
I think you want something like this:
probWin = 0
For Each HandA in RangeA
probA = getProbability(HandA)
For Each HandB in RangeB
probB = getConditionalProbability(HandB, HandA)
probWin += probA * probB * getProbabilityADefeatsB(HandA, HandB)
You need to consider conditional probability, because given HandA is As Ac, there is no longer a 7.5% chance that HandB is As Ac (in fact, there is a 0% chance of that). So you are taking the probability of A having a particular hand multiplied by the probability of B having a particular hand, given what A has, multiplied by the probability of A's hand beating B's hand. That should give you the probability of A having that hand against that particular hand of B's and winning. Iterating over all such pairs should give the desired result I think.
Since the approach is exhaustive, there is no need for any sort of Monte Carlo simulation. Of course this will be O(n^2) where n is the number of possible hands, but n here is relatively small.
EDIT:
I should note that since you are referring to the case where all cards have been dealt, the getProbabilityADefeatsB() function would return either 1 or 0. Also, getConditionalProbability() will either be exactly 0 (because the hands share a card) or simply what your regular weight was. It would be more complicated if the hands were less specific (if HandA is AA then HandB could be a different flavor of AA, but it is less likely).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last year.
Improve this question
Most online games arbitrarily form teams. Often times its up to the user, and they'll choose a fast server with a free slot. This behavior produces unfair teams and people rage quit. By tracking a player's statics (or any statics that can be gathered) how can you choose teams that are as fair as possible?
One of the more well-known systems now is Microsoft's TrueSkill algorithm.
People have also attempted to adapt the Elo system for team matchmaking, though it's more designed for 1-v-1 pairings.
After my previous answer, I realized that if you wanted to get really fancy you could use a really simple but powerful idea: Markov Chains.
The intuitive idea behind using a Markov Chain goes something like this:
Create a graph G=(V,E)
Let each vertex in V represent an entity
Let each edge in E represent a transitioning probability between entities. This means that the sum of the out degrees of each vertex must be 1.
At the start (time t=0) assign each entity a unit value of 1
At each time step, transition form entity i, j by the transition probability defined in 3.
Let t->infinity then the value of each entity at t=infinity is the equilibrium (that is the chance of a transition into an entity is the same as the total chance of a transition out of an entity.)
This idea has for example been used successfully to implement Google's page rank algorithm. To describe how you can use it consider the following:
V = players E = probability of transitioning form player to player based on relative win/loss ratios
Each player is a vertex.
An edge from player A to B (B is not equal to A) has probability X/N where N is the total number of games played by A and X is the total games lost to B. Add an edge from A to A with probability M/N where M is the total number of games won by A.
Assign a skill level of 1 to each player at the start.
Use the Power Method to find the dominant eigenvector of the link matrix constructed from the probabilities defined in 3.
The dominant eigenvector is the amount of skill each player has at t=infinity, that is
the amount of skill each player has once the markov chain has come to equilibrium. This is a very robust measure of each players skill using the topology of the win/loss space.
Some caveats: there are several problems when applying this directly, the biggest problem will be seperated webs (that is your markov chain will not be irreducible and so the power method will not be guaranteed to converge.) Lucky for you, google has dealt with all these problems and more when implementing their page rank algorithm and all that remains for you is to look up how they circumvent these problems if you are so inclined.
One way would be to simply create a list of players looking for matches at any given time, sorted by player rank. Once you've reached enough people to start a new match (or perhaps, two less than the required), group them as such:
Remove best and worst player and put them on team 1
Remove now-best and now-worst player (really second-best and second worst) and put them on team 2
If there are only two players left, place each one on different teams, depending on who has the lowest combined score. Otherwise, repeat:
Remove now-best and now-worst and put them on team 1
Remove now-best and now-worst and put them on team 2
etc. etc. etc. until your teams are filled.
If you decided to start a new match with less than the required, then here it is time to let the players wait for new people to join. As soon as a new person joins, you're going to want to put them on the open team with the least combined score.
Alternatively, if you wanted to avoid games that combined good and bad players on the same team, you could split up everyone into tiers, (groups based on their ranking) and only match people within the same tier. This would require a new open/sorted list for each extra tier.
Example
Game is 4v4
A - 1000 pnts
B - 800 pnts
C - 600 pnts
D - 400 pnts
E - 200 pnts
F - 100 pnts
As soon as you get these six, group them into teams as such:
Team 1: A, F, D (combined score 1500)
Team 2: B, E, C (combined score 1600)
Now, we wait for two more players to join.
First, player E comes along with 500 pnts. He goes to Team 1, because they have a lower combined score.
Then, player F comes with 800 pnts. He goes to Team 2, because are the only open team left.
Total teams:
Team 1: A, F, D, E (combined score 2000)
Team 2: B, E, C, F (combined score 2400)
Note that the teams were actually pretty fair until the last two came in. To be honest, the best way would be to only create the match when you have enough players to start it. But then the wait times might be too long for the player.
Adjust with how much you need before forming the match. Lower = less wait time, more possibly unfair. Higher = more wait time, less possibly unfair.
If you have a pre-game screen, lower would also offer more time for people to chat and talk with their to-be teammates while waiting.
It is difficult to estimate the skill of any one player by a single metric and such a method is prone to abuse. However, if you only care about implementing something simple that will work well try the following:
keep track of wins and losses
use the percentage of wins vs losses as the statistic to match players ( in some sense of the word match, i.e. group players with similar percentages)
This has the obvious downfall of the case where a player may have a win-loss ratio of 5-0 and another of 50-20, the first has an infinite percentage while the other has a more reasonable percentage. It makes sense for the matching system to acknowledge this and be far more confident that the latter player has actual more skill because of the consistency required; however, pitting the two players against each other would probably be a good thing because the 5-0 player is probably trying to work the system by playing versus weaker players so pitting him against a consistently good player would do everyone good.
Note, I speak from experience from playing only strategy games such as Warcraft 3 where this is the typical match making behaviour. It seems to me like the percentage of wins over losses is a great metric by which to match players.
Match based on multiple attributes. I've implemented a simple matchmaking system using AWS Cloudsearch (based on Apache Solr). For example matching based on the a combination of following fields is possible
{
"fields": {
"elo_rating": 3121.44,
"points": 404,
"randomizer": 35,
"last_login": "2014-10-09T22:57:57Z",
"weapons": [
"CANNON",
"GUN"
]
}
It is now possible to run queries inclusive of multiple fields like the following.
(and (or weapons:'GUN' weapons:'CANNON' weapons:'DRONE')(and last_login:['2013-05-25T00:00:00Z','2014-10-25T00:00:00Z'])(and points:[100, 200])(and elo_rating:[1000, 2000]))}