Robot Concentration

Two robots play Concentration as follows:

  1. Pairs of matching cards are laid face down in random positions on the table.

  2. On each turn, a robot may flip over two cards (one at a time) to try to get a match. If it is a match, the robot collects those cards and goes again. If it is not a match, the cards are laid face down again and it is the other robot's turn.

  3. Both robots have perfect memory, so a match will be made whenever possible with cards that have already been revealed.

  4. To move the game along, both robots have been programmed to turn over a new unrevealed card when no matches can be made.

  5. The robot with the most collected cards wins the game.

If the robots play with the least number of cards needed so that the probability of either robot winning is less than half, and if the probability that the robot who went first wins the game is p q \frac{p}{q} where p p and q q are co-prime positive integers, then find p + q p + q .

(Note: a computer is probably required to find the solution.)


The answer is 590932.

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

2 solutions

Mark Hennings
Oct 11, 2019

Suppose that A a , b , m , n A_{a,b,m,n} is the probability that player A wins, given that he goes first, that the score is a : b a\,:\,b (A has found a a pairs, while B has found b b ), that there are still m m pairs to be identified, and that n n singleton cards ( n m n \le m ) have already been uncovered. Suppose also that B a , b , n , m B_{a,b,n,m} is the probability that player A wins, given that B goes first, the score is a : b a\,:\,b , that m m pairs remain and n n singletons have been uncovered. There are 2 m n 2m-n cards from which A can choose; call the n n cards that match a previously uncovered singleton "old", and the other 2 m 2 n 2m-2n cards "new". At A A 's turn, he might:

  • turn over two different new cards, scoring nothing, with the play passing to B,
  • turn over a new card and then an old card. The play would then pass to B, who would take the now declared pair, and retain the play.
  • turn over a new card and its pair,
  • turn over an old card, and then its pair.

Thus we obtain the recurrence relation A a , b , m , n = 4 ( m n ) ( m n 1 ) ( 2 m n ) ( 2 m n 1 ) B a , b , m , n + 2 + 2 ( m n ) n ( 2 m n ) ( 2 m n 1 ) B a , b + 1 , m 1 , n + 2 ( m n ) ( 2 m n ) ( 2 m n 1 ) A a + 1 , b , m 1 , n + n 2 m n A a + 1 , b , m 1 , n 1 A_{a,b,m,n} \; = \; \frac{4(m-n)(m-n-1)}{(2m-n)(2m-n-1)}B_{a,b,m,n+2} + \frac{2(m-n)n}{(2m-n)(2m-n-1)}B_{a,b+1,m-1,n} + \frac{2(m-n)}{(2m-n)(2m-n-1)}A_{a+1,b,m-1,n} + \frac{n}{2m-n}A_{a+1,b,m-1,n-1} Similar arguments apply to when it is B's turn to play, and we obtain the recurrence relation B a , b , m , n = 4 ( m n ) ( m n 1 ) ( 2 m n ) ( 2 m n 1 ) A a , b , m , n + 2 + 2 ( m n ) n ( 2 m n ) ( 2 m n 1 ) A a + 1 , b , m 1 , n + 2 ( m n ) ( 2 m n ) ( 2 m n 1 ) B a , b + 1 , m 1 , n + n 2 m n B a , b + 1 , m 1 , n 1 B_{a,b,m,n} \; = \; \frac{4(m-n)(m-n-1)}{(2m-n)(2m-n-1)}A_{a,b,m,n+2} + \frac{2(m-n)n}{(2m-n)(2m-n-1)}A_{a+1,b,m-1,n} + \frac{2(m-n)}{(2m-n)(2m-n-1)}B_{a,b+1,m-1,n} + \frac{n}{2m-n}B_{a,b+1,m-1,n-1} and we have the initial conditions A a , b , 0 , 0 = B a , b , 0 , 0 = { 1 a > b 0 o . w . A_{a,b,0,0} \; = \; B_{a,b,0,0} \; = \; \left\{ \begin{array}{lll} 1 & \hspace{1cm} & a > b \\ 0 & & \mathrm{o.w.} \end{array}\right. We also have the probabilities D a , b , n , m A D^A_{a,b,n,m} and D a , b , n , m B D^B_{a,b,n,m} of a draw where (respectively) A and B play first and a , b , n , m a,b,n,m have the same meaning as above. These probabilities have the recurrence relations D a , b , m , n A = 4 ( m n ) ( m n 1 ) ( 2 m n ) ( 2 m n 1 ) D a , b , m , n + 2 B + 2 ( m n ) n ( 2 m n ) ( 2 m n 1 ) D a , b + 1 , m 1 , n B + 2 ( m n ) ( 2 m n ) ( 2 m n 1 ) D a + 1 , b , m 1 , n A + n 2 m n D a + 1 , b , m 1 , n 1 A D a , b , m , n B = 4 ( m n ) ( m n 1 ) ( 2 m n ) ( 2 m n 1 ) D a , b , m , n + 2 A + 2 ( m n ) n ( 2 m n ) ( 2 m n 1 ) D a + 1 , b , m 1 , n A + 2 ( m n ) ( 2 m n ) ( 2 m n 1 ) D a , b + 1 , m 1 , n B + n 2 m n D a , b + 1 , m 1 , n 1 B \begin{aligned} D^A_{a,b,m,n} & = \; \frac{4(m-n)(m-n-1)}{(2m-n)(2m-n-1)}D^B_{a,b,m,n+2} + \frac{2(m-n)n}{(2m-n)(2m-n-1)}D^B_{a,b+1,m-1,n} + \frac{2(m-n)}{(2m-n)(2m-n-1)}D^A_{a+1,b,m-1,n} + \frac{n}{2m-n}D^A_{a+1,b,m-1,n-1} \\ D^B_{a,b,m,n} & = \; \frac{4(m-n)(m-n-1)}{(2m-n)(2m-n-1)}D^A_{a,b,m,n+2} + \frac{2(m-n)n}{(2m-n)(2m-n-1)}D^A_{a+1,b,m-1,n} + \frac{2(m-n)}{(2m-n)(2m-n-1)}D^B_{a,b+1,m-1,n} + \frac{n}{2m-n}D^B_{a,b+1,m-1,n-1} \end{aligned} together with the initial conditions D a , b , 0 , 0 A = D a , b , 0 , 0 B = { 1 a = b 0 o . w . D^A_{a,b,0,0} \; = \; D^B_{a,b,0,0} \; = \; \left\{ \begin{array}{lll} 1 & \hspace{1cm} & a = b \\ 0 & & \mathrm{o.w.} \end{array}\right. The probability that A wins a game with n n pairs of cards, given that A goes first, is thus p A ( n ) = A 0 , 0 , n , 0 p_A(n) \; = \; A_{0,0,n,0} while the probability that B wins a game with n n pairs of cards, given that A goes first, is p B ( n ) = 1 A 0 , 0 , n , 0 D 0 , 0 , n , 0 A p_B(n) \; = \; 1 - A_{0,0,n,0} - D^A_{0,0,n,0} Careful inspection shows that these recurrence relations are sufficient to evaluate all these probabilities. Computer checking gives that the smallest value of n n for which both of p A ( n ) p_A(n) and p B ( n ) p_B(n) are less than 1 2 \tfrac12 is n = 8 n=8 , with p A ( 8 ) = 185527 405405 p B ( 8 ) = 870778 2027025 p_A(8) \; =\; \frac{185527}{405405} \hspace{2cm} p_B(8) \; =\; \frac{870778}{2027025} making the answer 185527 + 405405 = 590932 185527 + 405405 = \boxed{590932} .

This got too complicated for me so I had to use a computer program (earlier) to test the possibilities. I'm very impressed by your solution!

David Vreken - 1 year, 8 months ago
David Vreken
Oct 11, 2019

The following Python Code shows that the least number of cards needed for the probability of either robot winning to be less than half is 8 8 cards, so that Player 1 1 wins at a 185527 405405 0.4576 \frac{185527}{405405} \approx 0.4576 probability, Player 2 2 wins at a 870778 2027025 0.4296 \frac{870778}{2027025} \approx 0.4296 probability, and a tie happens at a 76204 675675 0.1128 \frac{76204}{675675} \approx 0.1128 probability.

Therefore p = 185527 p = 185527 , q = 405405 q = 405405 , and p + q = 590932 p + q = \boxed{590932} .

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# Robot Concentration
# Python 2.7.3

from fractions import Fraction

# function that takes a sequence of cards (denoted by A's, B's, C's, etc.)
#   and determines the winner
def find_winner(seq):
    winner = ""
    revealed = []
    pturn = 1
    flip = 1
    flip1card = ""
    index = 0
    pmatches = []
    for a in range(0, 3):
        pmatches.append(0)
    # go through each card in order of seq
    while True:
        if flip == 1:
            # first card flip
            flip1card = seq[index]
            if seq[index] in revealed:
                # if it matches a card that has been revealed on a previous
                #   turn, then match those cards and start again
                revealed.remove(seq[index])
                pmatches[pturn] += 1
                index += 1
                flip = 1
            else:
                # if it doesn't match a card that has been revealed on a
                #   previous turn, then move on to a second card flip
                revealed.append(seq[index])
                flip = 2
                index += 1
        elif flip == 2:
            # second card flip
            if flip1card == seq[index]:
                # if it matches the first card flip, then match those
                #   cards and start again
                revealed.remove(seq[index])
                pmatches[pturn] += 1
                index += 1
                flip = 1
            else:
                # if it doesn't match the first card flip, then the turn
                #   is over
                if pturn == 1:
                    pturn = 2
                elif pturn == 2:
                    pturn = 1
                if seq[index] in revealed:
                    revealed.remove(seq[index])
                    pmatches[pturn] += 1
                else:
                    revealed.append(seq[index])
                index += 1
                flip = 1
        if index == len(seq):
            # at the end of the sequence of cards, finish the game
            break
    # determine the winner by the number of matches made by each player
    if pmatches[1] > pmatches[2]:
        winner = "p1"
    elif pmatches[2] > pmatches[1]:
        winner = "p2"
    else:
        winner = "tied"
    return winner

# function that subtracts a letter one at a time from another string
#   (needed for the game_data function)
def str_subtract(str1, str2):
    for a in range(0, len(str2)):
        str1 = str1.replace(str2[a], "", 1)
    return str1

# function that finds all the unique sequences given the number of pairs,
#   and calculates the probability of winning
def game_data(pairs):
    letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    # find unique sequences, for example, for two pairs the unique
    #   sequences are AABB, ABAB, and ABBA (BBAA, BABA, and BAAB are
    #   not counted because if A and B are swapped the sequence is
    #   already given)
    bank = ""
    for a in range(0, pairs):
        bank += letters[a]
        bank += letters[a]
    seqposs = ["A"]
    seqpossnext = []
    for a in range(1, len(bank)):
        for b in range(0, len(seqposs)):
            rem = str_subtract(bank, seqposs[b])
            for c in range(0, letters.find(max(seqposs[b])) + 2):
                if letters[c] in rem:
                    seqpossnext.append(seqposs[b] + letters[c])
        seqposs = []
        seqposs = seqpossnext
        seqpossnext = []
    # run find_winner function with each possible unique sequence
    #   and tally up the winners
    p1count = 0
    p2count = 0
    tiedcount = 0
    for a in range(0, len(seqposs)):
        winner = find_winner(seqposs[a])
        if winner == "p1":
            p1count += 1
        elif winner == "p2":
            p2count += 1
        elif winner == "tied":
            tiedcount += 1
    # display the results
    print "For", n, "pair(s):"
    print "  Player 1 Wins:", format(1.0 * p1count / len(seqposs), '.4f'), "or", Fraction(1.0 * p1count / len(seqposs)).limit_denominator()
    print "  Player 2 Wins:", format(1.0 * p2count / len(seqposs), '.4f'), "or", Fraction(1.0 * p2count / len(seqposs)).limit_denominator()
    print "  Tied Games:   ", format(1.0 * tiedcount / len(seqposs), '.4f'), "or", Fraction(1.0 * tiedcount / len(seqposs)).limit_denominator()

# find and display probabilities for 1-8 pairs
for n in range(1, 9):
    game_data(n)

Very nice, and a fiendish problem! One question, though: there seems to be something strange happening with the probability of the second robot winning. I went about this a different way again (not elegant or compact enough to provide as a solution). I agree with @Mark Hennings that this probability should be 870778 2027025 \frac{870778}{2027025} . If you look at the denominator of the fraction you found - 445717 445717 - you'll see it doesn't actually divide 2027025 2027025 (the total number of distinct games). However, the numerical values of the probabilities first differ in something like the 1 2 t h 12^{th} decimal place so there's something more going on here than a typo. Could this be a Python rounding issue?

Also, do you happen to know if this code should work in the coding environment on Brilliant? I don't seem to be able to get it working but perhaps I'm doing something wrong.

Chris Lewis - 1 year, 7 months ago

Log in to reply

Good catch! I edited my solution. Python did display the fraction incorrectly despite having the correct value, so it must be a Python rounding issue (maybe just with the Fraction function). Good thing I asked for the Player 1's probabilty and not Player 2's!

I'm not familiar with testing code on Brilliant. However, you can download Python for free from https://www.python.org/downloads/ and then test it by running it on your PC.

David Vreken - 1 year, 7 months ago

Log in to reply

Thanks! Seems the issue I had was a change in syntax for the PRINT statement/function between Python versions.

I'm still pottering around with this - the oscillation of the probabilities of the various outcomes against the number of pairs of cards in the game seems quite curious (for example, with five or six pairs of cards, the second robot is the most likely winner; with seven or eight pairs, it's the first robot). Do you have any intuition about what should happen as the number of pairs of cards increases? The benefit (or otherwise) of going first would seem to decrease, but I suspect that leads to each robot having a similar probability of winning rather than draws becoming the most likely outcome.

Chris Lewis - 1 year, 7 months ago

Log in to reply

@Chris Lewis It is strange that the probability of which robot wins (seemingly) randomly goes back and forth. I'm not sure why nor do I know what would happen as the pairs of cards increase.

David Vreken - 1 year, 7 months ago

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...