Contestants in the example programming contest create their solutions, called players, as web services that make one move at a time. Each move is requested by an external entity sending the service a request with a JSON body specifying the state of the game, and the player responds with the JSON representation of a single move.
Since the point of this tutorial is learning how to create and deploy a serverless solution rather than game-playing strategy, the game to be played is as simple as possible: guess a number. The player is given a minimum and maximum integer and guesses an integer in that range. The player is provided with a history of its prior guesses as well, so it does not need to keep track of them itself.
The same concepts used here can be applied to more sophisticated single or many-player games such as Battleship, hangman, or checkers.
The input to the player is an HTTP request sent to a URL chosen by the player, with a JSON body representing the state of the game prior to the move. The JSON object has properties minimum (an integer greater than or equal to zero), maximum (an integer greater than or equal to minimum), and history (an array of guesses, in the order they were made). Each guess is an object with properties guess (an integer between minimum and maximum, inclusive), and result (the string "higher" or "lower"). Example:
{ "minimum": 1, "maximum": 10, "history": [ {"guess": 5, "result": "higher"}, {"guess": 8, "result": "lower"} ] }
The output represents the game player's move as an HTTP response with a JSON body containing a single integer, the player's guess. Example:
6
A judging system will invoke the player repeatedly, each time with a history that incorporates previous guesses, until the correct guess is returned or some maximum number of guesses or amount of time is exceeded. There may be several "judges" each with a different range to guess from operating.
In this tutorial, you're going to build a player implemented as a Cloud Function that responds to HTTP requests. It will play the contest game by making a single move in response to a request describing the prior state of the game. Your app will:
All software deployed on GCP will be part of a GCP Project. If this is the first part of the game playing system you're working on, create a new project for it at console.cloud.google.com.
You will do some work in the Cloud Shell command line environment. Start by opening that environment and fetching the sample code to it.
Open the Cloud Console at console.cloud.google.com and select your project. If this is the first time you've used the Cloud Shell, you can read the explanation and click the appropriate button to continue to the shell.
All commands in this codelab will use the console UI or be executed within a Cloud Shell. Open the Cloud Shell by clicking the Activate Cloud Shell icon found at the right side of the console page header. The lower half of the page will allow you to enter and run commands. The commands could be run from your own PC, but you would have to install and configure needed development software first. The Cloud Shell already has all the software tools you need. |
You can use the following command from the Cloud Shell command line to get the source code to examine. This is not a required step for this codelab, however.
git clone https://github.com/GoogleCloudPlatform/serverless-game-contest.git
You can explore the code in the built-in code editor by clicking the editor icon to launch it. |
You will create, test, and invoke a cloud function that plays the guessing game.
Navigate to the console at console.cloud.google.com. Select or create a project to work in. Create the new function as follows:
Use the displayed Create function page to specify your new Cloud Function.
Use the inline editor to replace the code skeleton with one that plays the game, shown below. You can edit the function body in main.py and the list of required non-standard libraries in requirements.txt. Our example does not use any non-standard libraries, so the requirements.txt file will remain empty.
This function will be sent an HTTP POST request whose body is a JSON object with the smallest and largest possible guesses and a list of prior guesses. The function code will make a guess based on that input and return the guess in JSON format. The function code to enter is in the file player/badplayer.py in the repository, and is shown below.
import json
def make_guess(request):
game = request.get_json()
guess = game['minimum']
return json.dumps(guess)
Key steps in this function code are:
minimum
property of the JSON request object, uses it as the guess, and returns that guess as a JSON object. (The JSON version of a number is simply that number.) This is a very bad game player because it ignores the list of previous moves that is sent to it and thus does not learn or improve on subsequent moves.Fill in the name of the Entry point as make_guess and click the Deploy button. A spinner icon will appear next to the function name near the top of the page. After a few minutes, it should change to a green check mark. Hovering over the check mark will show the message Function is active.
If something goes wrong: the spinner icon will show a red exclamation point. Click the function name and look at the details of the Deployment failure messages in the General tab to figure out how to fix it and try again.
We are now ready to test the function. Click the function name to open the Function details page, and then click the Testing tab to start.
{ "minimum": 1, "maximum": 10, "history": [] }
You can also test with a history of previous guesses to the request, as below.
{ "minimum": 1, "maximum": 10, "history": [ {"guess": 5, "result": "higher"}, {"guess": 8, "result": "lower"} ] }
Since this is not a very smart game player, it will not learn from the history of prior guesses and will always return 1, even though the history shows the right answer at this point must be 6 or 7.
The function seems to be working as designed.
Perform one last check to make sure the function works properly when invoked via an HTTP POST request using the URL assigned to it. Simply using a web browser to view that URL will result in an error response because the browser's request will not contain a valid JSON body. Instead, you will use the curl command line tool installed in the Cloud Shell. You could use Postman instead if you are more familiar with that tool and have previously installed it.
curl -X POST -H "Content-type: application/json" --data-binary @game.json <url>
This command sends an HTTP POST
request to the given url. The request has a header that specifies the request body is in application/json
form, and the body itself is the contents of the game.json
file you created.
1
at the beginning of the following line. Because the function does not return an end-of-line marker after the response, the prompt for the next command will be displayed immediately after the 1 instead of beginning a new line, such as shown below:1user@host$
You have created, deployed, tested, and called a Cloud Function that is a valid player for the competition.
Instead of using the cloud console, you can create and deploy a cloud function from a command line. You will need to have the gcloud command installed and configured to do this; in this example you will work from the Cloud Shell which already has that in place.
cd ~/serverless-game-contest/player
cp okayplayer.py main.py
gcloud functions deploy okayplayer \ --runtime=python37 --trigger-http \ --source=. --entry-point=make_guess \ --allow-unauthenticated
The response to the command will start with:
Deploying function (may take a while - up to 2 minutes)...done.
This will be followed by details of the deployed function.
You can now test and invoke this function within the console just as you did for the one deployed there.