Message Boards Message Boards


Re-evaluate a random generator to simulate a raquetball play?

Posted 8 days ago
19 Replies
3 Total Likes

Sorry - trying to learn the language...your playing racquetball , you only score when you serve. 60% chance of winning when you serve, 50% chance of winning when you don't serve

p5 := If[Random[] >=  .5, 1, 0]
p6 := If[Random[] >=  .6, 1, 0]
p := If[x < x + Evaluate[p6], x += 1, np];
np := If[Evaluate[p5] == 1, p, np];
score = Table[p, 10]
Do[Print[x]; p, 5]

the best I can do so far and it's not working, I want to see how far it will take to get to 21, I am not sure how Mathematica works as a programming language. Thanks for any help.

19 Replies
Posted 7 days ago

What is ratchball? It would help to know what the rules are. Do players alternate or does the winner serve again? Are there more than two players? Why is play asymmetric (p(winning if not serving)=0.5 vs p(winning if serving) =0.6). Who serves first?

Posted 7 days ago

Sorry -- raquetball -- yes there are two players, but I didn't want to complicated the problem so only looking just one side. You start serving but only win a point when you serve. you have a 60% chance of winning your serve and earning one point. If you lose your serve you only have a 50% chance of winning the serve back again. Wanted to create the simulation to see how long it would take to get to 21 points to win. Also trying to figure out how to do this mathematically equally without success. If you win the serve and then win the next play, only then do you earn a point and get to serve again, earning points until you lose your serve.

Posted 7 days ago

how would I count the number of times the ball was served???

x = 0;
p5 := If[Random[] <=   .5, 1, 0]
p6 := If[Random[] <=   .6, 1, 0]
Table[p5, 10]
Table[p6, 10]
p := If[0 < p6, x += 1, np]
np := If[p5 == 1, p, np]
score = Table[{p, x}, 10]

The score is going up one point at a time, as it should, but I don't know how many times the ball has been played between point (p) and no point (np), how would I count this????

Posted 7 days ago

I'm getting closer---

x = 0; s = 0;
p5 := If[Random[] <=   .5, 1, 0]
p6 := If[Random[] <=   .6, 1, 0]
p := If[0 < p6, {x += 1, s += 1}, {np, s += 1}]
np := If[p5 == 1, {p, s += 1}, {np, s += 1}]
score = Table[{p, s}, 10]

the output is

{{{{{{{{{1, 1}, 2}, 3}, 4}, 5}, 6}, 7}, 7}, {{2, 8}, 8}, {{3, 9}, 
  9}, {{{{4, 10}, 11}, 12}, 12}, {{5, 13}, 
  13}, {{{{{{6, 14}, 15}, 16}, 17}, 18}, 18}, {{{{7, 19}, 20}, 21}, 
  21}, {{{{{8, 22}, 23}, 24}, 25}, 25}, {{9, 26}, 26}, {{10, 27}, 27}}

to win 10 points the ball has been played 27 times -- I am not sure why the last number (s) prints twice????

Posted 7 days ago

I am having a difficult reading the lists in the output, would there be an easier way??

x = 0; s = 0;
p5 := If[Random[] <=   .5, 1, 0]
p6 := If[Random[] <=   .6, 1, 0]
p := If[0 < p6, {x += 1, s += 1}, {np, s += 1}]
np := If[p5 == 1, {p, s += 1}, {np, s += 1}]
score = Table[{s, Style[p, Bold, Red]}, 10]



sorry I can't get the red to appear in the post

I ran 100,000 games to 21. The maximum number of serves required was 104, the minimum number of serves was 24, and average number of serves was about 52.

Posted 6 days ago

Thanks Ed, if you used my code, I would love to know how you ran it 100,000 times. I have tried and "score" just repeats itself and doesn't re-evaluate. I also don't understand why Table stops when p = 21 and not when s reaches 21 or x, other than Mathematica knew that is what I wanted -- pretty good if Mathematica was intuitive like that... With all the crazy lists I am getting, how would extract the last s value? I have tried "Flatten" but it will not get rid of all the lists from the p value

x = 0; s = 0;
p5 := If[Random[] <=   .5, 1, 0]
p6 := If[Random[] <=   .6, 1, 0]
p := If[p6 == 1, {x += 1, s += 1}, {np, s += 1}]
np := If[p5 == 1, {p, s += 1}, {np, s += 1}]
score = Table[{s, Style[x, Bold, Red], Style[p, Green]}, 21]

Here’s how I did it. First, model a single game with a function. The players are numbered either 0 or 1, and a single game is represented as a pair {WINNER, LOSER}. So, if player 0 wins, the results is {0,1}, and {1,0} otherwise.

SingleStep[server_]:= Module[

Now, we want to play as many games as we need for player 0 to reach 21 wins.


Here we just play games until player 0 exceeds x wins. The function returns the number of games until x wins occurs. This is written in an imperative style where we use the wins and games counts to track results through the loops. This could alternatively be written in a slightly less clear (in my opinion) way using a functional style via NestLists and a stopping criterion based on Total.

If we want to run this 100 times, we might say:


The result, gamesToWin, will be a list of length 100 that contains the number of games that were required for player 0 to win 21 times in each independent trial. This can then be plotted using Histogram to look at the distribution of game counts for player 0 to reach 21 wins.

Correction to my original post. Ran 100,000 games counting all serves. The maximum number of total serves in a game was 64. The minimum was 21, and the average was about 35. These runs didn't stop the game if the other player scored 21 points first. Player with 0.6 probability served first.

Posted 6 days ago

okay not pretty, but this is what I got so far

t = Table[{
    x = 0; s = 0;
    p5 := If[Random[] <=   .5, 1, 0];
    p6 := If[Random[] <=   .6, 1, 0];
    p := If[p6 == 1, {x += 1, s += 1}, {np, s += 1}];
    np := If[p5 == 1, {p, s += 1}, {np, s += 1}];
    score = Table[{Style[p, Green], s, Style[x, Bold, Red]}, 21];
    s}, 100000];
Histogram[Flatten[t], 150]
Mean[t] // N

enter image description here

Max = 152, Min = 21, Mean = 63

Posted 6 days ago

Why not generate your list first: WLWWWLWLLL etc. Maybe 3.5 million if you expect 100,000 games. Look at EACH run WWW LLLLLL etc...and subtract 1 from the length (in this case, person 1 gets two points, then person 2 gets 5 points). Thats how many points that person gets. Reset the game at the point someone gets to 21. Once you have that, adjust code so winner has to win by 2. Think about end of game adjustments so there isnt a score like 17-25 for a large streak.

Posted 6 days ago

thanks Matthew, ran your program 100,000 times and your max,min,mean are about half of mine.

enter image description here

I am only guessing, but I don't see how your "server" could = 1 and thus only have a potential to win at 50%, though your graph is much more normalized and smoother than what my program produces.

Welcome to Wolfram Community! Please make sure you know the rules:

Please do NOT post code as images. Other members cannot copy it then.

The rules explain how to format your code properly. If you do not format code, it may become corrupted and useless to other members. Please EDIT your post and make sure code blocks start on a new paragraph and look framed and colored like this.

int = Integrate[1/(x^3 - 1), x];
Map[Framed, int, Infinity]

enter image description here

@ Raymond Low A game ends when one of the players, A or B, earns 21 points. I ran 100,000 games stopping each at 21 points. I show that player A with 0.6 probability of earning a point on a serve, wins about 82.5% of the games played. The total number of serves by both players has a mean value of about 58 serves when A wins. Player A serves about 34 times (mean value) to win 21 points and thus a game. When B player wins, the total number of serves during these games has a mean value of about 66 serves. B player’s mean number of serves for winning a game was about 35.

I failed to understand how Matthews code switched between players when a serve didn’t make a point. I just couldn’t visualize it. I suspect his code was counting the individual serves by the winner of each game.

You're right - I posted code that counts wrong. Modified code where players are either player 1 or 2:

SingleStep[cfg_] := If[Random[] < 0.6, cfg, Reverse[cfg]]

This is passed a pair: {server,other}. The server has a 60% chance of winning the round. If the server loses the round, the configuration is reversed so the next round the other player is the server.

The main loop then becomes:

CountGames[x_] := Module[{wins, curserve, newserve, games},
  wins = {0, 0};
  curserve = {1, 2};
  games = 0;
  While[wins[[1]] < x && wins[[2]] < x,
   newserve = SingleStep[curserve];
   If[newserve[[1]] == curserve[[1]], 
    wins[[newserve[[1]]]] = wins[[newserve[[1]]]] + 1];
   curserve = newserve;
   games = games + 1];

Start off with 0 wins for each player, 0 games played, and with player 1 being the first server. Loop while neither player has exceeded the target win count (x). Each step, given the current serving configuration, return the next serving configuration. If the configuration didn't change, then record a win for the server. Otherwise, just increment the game count and set the current configuration to the new one.

I'm not sure about the way the original problem was defined (0.6 and 0.5 probabilities), but this should be a less buggy attempt compared to my original code. Thanks Ed for pointing out the mistake - that's what I get for trying to code something up quickly and not thinking it through...

Posted 2 days ago

Thank you Matthew --
I was wondering how to time your program. I tried wrapping your code in "Timing" but it won't run. How would I time how long it takes your program to run?? Also would it be possible to extract "wins" out of the code?

Regarding timing, you should be able to use the timing function: for example, one run:

In[6]:= {time, count} = CountGames[21] // Timing

Out[6]= {0.000357, 51}

The time variable will hold the timing, and the count variable is the number of games played until one player reached 21. If you modify the CountGames function, you can have it return both the total game count as well as the per-player win count:

CountGames[x_] := Module[{wins, curserve, newserve, games},
  wins = {0, 0};
  curserve = {1, 2};
  games = 0;
  While[wins[[1]] < x && wins[[2]] < x,
   newserve = SingleStep[curserve];
   If[newserve[[1]] == curserve[[1]], 
    wins[[newserve[[1]]]] = wins[[newserve[[1]]]] + 1];
   curserve = newserve;
   games = games + 1];
  {wins, games}]

In this case the final expression in the body of the function is {wins, games}. For example:

In[10]:= {time, {wins, count}} = CountGames[21] // Timing

Out[10]= {0.000242, {{21, 5}, 44}}

Here we see that in 0.000242 seconds it found that player 1 won 21 points, player 2 won 5 points, and 44 total games were played where 18 of the games were rounds where the server did not win, so the serve changed players but the winner didn't pick up a point since they didn't serve in that round. If I run 100,000 games, I can get the timing and win count as:

In[12]:= {time, history} = 
  Table[CountGames[21], {i, 1, 100000}] // Timing;

In[13]:= time

Out[13]= 21.4189

In[18]:= numgames = #[[2]] & /@ history;

That last line just maps the function #[[2]]& over the elements of the history to get the second element of the pair returned by CountGames[] to get the total games played until someone reached 21. Similarly, if I map the function #[[1]]& over history, I would get a table of pairs {WinsA, WinsB} for each game to 21 if you wanted to look at those values as well.

Posted 2 days ago

Thanks Ed -- you got a lot of information, is it possible you could post your code, I would like to see how you did it....

@ Raymond Low Following not elegant but here is code I used.

game = 0; hitsAwin = {}; hitsBwin = {}; lAsrv = {}; lBsrv = {}; space
= "  ";
(Label[start]; pntA = 0; pntB = 0; srv = 0; srvA = 0; srvB = 0; 
 game = game + 1;
 Label[A]; srv = srv + 1; srvA = srvA + 1;(*Print[{srv,"  ",srvA}];*)

 If[RandomInteger[{1, 10}] <= 6, pntA = pntA + 1, Goto[B]]; 
 If[pntA >= 21, Goto[End], Goto[A]];
 Label[B]; srv = srv + 1; srvB = srvB + 1;
 If[RandomInteger[{1, 10}] <= 5, pntB++, Goto[A]];
 If[pntB >= 21, Goto[End], Goto[B]];
 If[pntA == 21, AppendTo[hitsAwin, srv], AppendTo[hitsBwin, srv]];
 If[pntA == 21, AppendTo[lAsrv, srvA], AppendTo[lBsrv, srvB]];
 If[game < 100000, Goto[start]]); Print[{Length[hitsAwin], space, 
  Max[hitsAwin], space, Min[hitsAwin], space, N[Mean[hitsAwin]], "  ",
Print[{Length[hitsBwin], space, Max[hitsBwin], space, Min[hitsBwin], 
  space, N[Mean[hitsBwin]], space, N[Mean[lBsrv]]}]
Histogram[{hitsAwin, hitsBwin}]
Histogram[{lAsrv, lBsrv}]
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract