Skip to content

Commit 61b8763

Browse files
authored
data-generator example (#221)
Adds an example of training a model using a tf.data.Dataset built from a generator. This example competes at a simple game.
1 parent 77d802f commit 61b8763

File tree

7 files changed

+8008
-0
lines changed

7 files changed

+8008
-0
lines changed

data-generator/.babelrc

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"presets": [
3+
[
4+
"env",
5+
{
6+
"esmodules": false,
7+
"targets": {
8+
"browsers": [
9+
"> 3%"
10+
]
11+
}
12+
}
13+
]
14+
],
15+
"plugins": [
16+
"transform-runtime"
17+
]
18+
}

data-generator/game.js

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google LLC. All Rights Reserved.
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
* =============================================================================
16+
*/
17+
18+
/**
19+
* This file implements a two player card game similar to a much simplified game
20+
* of Poker. The cards range in value from 1 to GAME_STATE.max_card_value, and
21+
* each player receives three cards, drawn uniformly from the integers in the
22+
* range [1, GAME_STATE.max_card_value]. One player wins by having a better
23+
* hand.
24+
*
25+
* Any triple (three of the same card) beats any double.
26+
* Any double (two of the same card) beats any single.
27+
* If both players have a triple, the higher triple wins.
28+
* If both players have a double, the higher double wins.
29+
* If neither player has a double, the player with the highest
30+
* individual number wins.
31+
* Ties are settled randomly, 50/50.
32+
*/
33+
34+
// Global exported state tracking the rules of the game and how many games have
35+
// been played so far. Individual fields may be read / changed by external
36+
// control.
37+
export const GAME_STATE = {
38+
// The number of times the game has been played. Useful
39+
// for illustrating how many simulations it takes to train the model.
40+
num_simulations_so_far: 0,
41+
// Constants defining the range of card values.
42+
min_card_value: 1,
43+
max_card_value: 13,
44+
// Controls how many cards per hand. Controlable from a UI element.
45+
num_cards_per_hand: 3
46+
};
47+
48+
/**
49+
* Returns a random integer in the range [GAME_STATE.min_card_value,
50+
* GAME_STATE.max_card_value]
51+
*/
52+
export function getRandomDigit() {
53+
return Math.floor(
54+
GAME_STATE.min_card_value + Math.random() * GAME_STATE.max_card_value);
55+
}
56+
57+
/**
58+
* Yields a randomly generated array of three elements. Each element
59+
* is an integer randomly selected within the range [1, 9]. Hands are returned
60+
* in sorted order.
61+
*/
62+
export function randomHand() {
63+
const hand = [];
64+
for (let i = 0; i < GAME_STATE.num_cards_per_hand; i++) {
65+
hand.push(getRandomDigit());
66+
}
67+
return hand.sort((a, b) => a - b);
68+
}
69+
70+
/**
71+
* This function produces an array indicating the largest face value for
72+
* every possible group size (1 card, 1 pair, 3-of-a-kind, 4-of-a-kind, etc.),
73+
* in the hand. Zeros indicate there are no groups of that size.
74+
*
75+
* E.g., if this function returns [9, 3, 0, 0, 0, 0] it indicates that
76+
* - The highest card is a 9
77+
* - The highest double is of a 3
78+
* - There are no triples etc.
79+
*
80+
* This could result if the hand were, e.g, [1, 2, 2, 3, 3, 9]
81+
*
82+
* @param {number[]} hand A sorted integer array of length
83+
* GAME_STATE.num_cards_per_hand
84+
* @returns {number[]} An array of the face value of the largest value for each
85+
* group size. Zero indicates there are no examples of that group size in
86+
* the hand, if, for instance, there are no triples.
87+
*/
88+
export function handScoringHelper(hand) {
89+
// Create an array of all zeros of the appropriate size.
90+
const faceValOfEachGroup = [];
91+
for (let i = 0; i < GAME_STATE.num_cards_per_hand; i++) {
92+
faceValOfEachGroup.push(0);
93+
}
94+
let runLength = 0;
95+
let prevVal = 0;
96+
for (let i = 0; i < GAME_STATE.num_cards_per_hand; i++) {
97+
const card = hand[i];
98+
if (card == prevVal) {
99+
runLength += 1;
100+
} else {
101+
prevVal = card;
102+
runLength = 1;
103+
}
104+
faceValOfEachGroup[runLength - 1] = card;
105+
}
106+
return faceValOfEachGroup;
107+
}
108+
109+
/**
110+
* Returns 1 if hand1 beats hand2, in terms of hand value.
111+
* Returns 0 if hand1 is less than hand2.
112+
* In the event of a tie, return 0 or 1 randomly with even odds.
113+
* @param {number[]} hand1 ordered list of numbers representing Player 1's hand.
114+
* @param {number[]} hand2 ordered list of numbers representing Player 2's hand.
115+
* @returns {number} 1 or 0 indicating Player 1's win or loss, respectively.
116+
*/
117+
export function compareHands(hand1, hand2) {
118+
const handScore1 = handScoringHelper(hand1);
119+
const handScore2 = handScoringHelper(hand2);
120+
// In descending order of group size, decide if one hand is better.
121+
for (let group = GAME_STATE.num_cards_per_hand - 1; group >= 0; group--) {
122+
if (handScore1[group] > handScore2[group]) {
123+
return 1;
124+
}
125+
if (handScore1[group] < handScore2[group]) {
126+
return 0;
127+
}
128+
}
129+
// Break a tie by flipping a fair coin.
130+
if (Math.random() > 0.5) {
131+
return 1;
132+
}
133+
return 0;
134+
}
135+
136+
/**
137+
* Returns an object representing one complete play of the game.
138+
* Generates two random hands, and the value of the hand comparison.
139+
* Returns [hand1, hand2, whetherHand1Wins.
140+
*/
141+
export function generateOnePlay() {
142+
const player1Hand = randomHand();
143+
const player2Hand = randomHand();
144+
const player1Win = compareHands(player1Hand, player2Hand);
145+
GAME_STATE.num_simulations_so_far++;
146+
return {player1Hand, player2Hand, player1Win};
147+
}

0 commit comments

Comments
 (0)