Menu

  • Home
  • Archives
  • Tags
  • RSS
January 8, 2015

rock

I've been having some fun with the idea of simple text-based games in Go1. The original BASIC games book2 was not hard to find, and it was interesting to revisit it again.

The first thing that stared me in the face was just how bad (and by "bad" I mean incomprehensible) most of the code was. In my nostalgia I had completely lost sight of this.

The second thing was how nicely self-contained each game was, focussed on one simple idea, and implicitly pedagogical. Indeed, the games can be divided into a few distinct families3.

So I came up with a hypothetical organization for my hypothetical book – it would need some simple stuff to start out with (with for loops, conditionals, functions, and so on), and slowly introduce more stuff. An explicit non-goal would be teaching the language in its complete form (a link to Effective Go4 should suffice for the motivated reader).

In terms of Games, the rough plan I came up with was: start with some simple guessing game, then maybe a slightly more involved version, then a card game, then the classic Battleship around the mid-point, followed by a sort of "dungeon RPG" with some optional discussion at each point (e.g. should the computer in "Battleship" be dumb and random, or learn?)

To get an idea of what this might look like, I wrote the first four of these. Here is what might pass for the very first one, a modified version of "Rock, Paper, Scissors".


package main



import (

	"fmt"

	"math/rand"

	"strings"

	"time"

)



const (

	rock = iota

	paper

	scissors

	lizard

	spock

	maxOptions

)



var handOptions = []string{"rock", "paper", "scissors", "lizard", "spock"}



type precedence struct {

	hand1  int

	reason string

	hand2  int

}



var precedences = []precedence{

	{spock, "smashes", scissors},

	{spock, "vaporises", rock},

	{lizard, "posions", spock},

	{lizard, "eats", paper},

	{rock, "crushes", lizard},

	{rock, "cruses", scissors},

	{paper, "covers", rock},

	{paper, "disproves", spock},

	{scissors, "cuts", paper},

	{scissors, "decapitates", lizard},

}



func showUsage() {

	fmt.Println("\n     Welcome to ROCK - PAPER - SCISSORS - LIZARD - SPOCK  ")

	fmt.Println("----------------------------------------------------------\n")

	fmt.Println("We each pick one of the following : \n")

	for i := 0; i < maxOptions; i++ {

		fmt.Printf("-->  %s  <--\n", handOptions[i])

	}

	fmt.Println()

}



func getPlayerChoice() int {

	for {

		fmt.Printf("\nEnter your choice : ")

		var choice string

		fmt.Scan(&choice)



		choice = strings.ToLower(choice)



		for i := 0; i < maxOptions; i++ {

			if handOptions[i] == choice {

				return i

			}

		}

	}

}



func getComputerChoice() (choice int) {

	choice = rand.Intn(maxOptions)

	fmt.Printf("I chose ")

	for i := 0; i < 3; i++ {

		fmt.Printf(".")

		time.Sleep(200 * time.Millisecond)

	}

	fmt.Printf(" %s\n\n", handOptions[choice])

	return

}



func main() {

	showUsage()



	rand.Seed(time.Now().Unix())

	var playerWins, computerWins int



	for {

		fmt.Printf("\nThe score is: Me %d, You %d\n", computerWins, playerWins)

		playerChoice := getPlayerChoice()

		computerChoice := getComputerChoice()



		playerWon := false

		computerWon := false

		for _, p := range precedences {

			if p.hand1 == playerChoice && p.hand2 == computerChoice {

				fmt.Printf("Alas! %s %s %s! You Win! :(\n",

					handOptions[p.hand1], p.reason, handOptions[p.hand2])

				playerWon = true

			}

			if p.hand1 == computerChoice && p.hand2 == playerChoice {

				fmt.Printf("Aha! %s %s %s! I win! :)\n",

					handOptions[p.hand1], p.reason, handOptions[p.hand2])

				computerWon = true

			}

		}



		if playerWon {

			playerWins++

		} else if computerWon {

			computerWins++

		} else {

			fmt.Println("Hey, look, it was a draw!\n\n")

		}



		fmt.Printf("\nPlay another round ?  (enter 'y' or 'n') : ")

		var another string

		fmt.Scan(&another)

		if strings.ToLower(another) == "y" {

			continue

		} else {

			break

		}

	}

	fmt.Println("\nOh well, until next time then ... \n")

}

Try it out! It's meant to be simple and straightforward – but wait! Before you pass judgement, I present to you the original version:


10 PRINT TAB(21);"GAME OF ROCK, SCISSORS, PAPER"

20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"

25 PRINT:PRINT:PRINT

30 INPUT "HOW MANY GAMES";Q

40 IF Q<11 THEN 60

50 PRINT "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.": GOTO 30

60 FOR G=1 TO Q

70 PRINT: PRINT "GAME NUMBER";G

80 X=INT(RND(1)*3+1)

90 PRINT "3=ROCK...2=SCISSORS...1=PAPER"

100 INPUT "1...2...3...WHAT'S YOUR CHOICE";K

110 IF (K-1)*(K-2)*(K-3)<>0 THEN PRINT "INVALID.": GOTO 90

120 PRINT "THIS IS MY CHOICE..."

130 ON X GOTO 140,150,160

140 PRINT "...PAPER": GOTO 170

150 PRINT "...SCISSORS": GOTO 170

160 PRINT "...ROCK"

170 IF X=K THEN 250

180 IF X>K THEN 230

190 IF X=1 THEN 210

200 PRINT "YOU WIN!!!":H=H+1: GOTO 260

210 IF K<>3 THEN 200

220 PRINT "WOW!  I WIN!!!":C=C+1:GOTO 260

230 IF K<>1 OR X<>3 THEN 220

240 GOTO 200

250 PRINT "TIE GAME.  NO WINNER."

260 NEXT G

270 PRINT: PRINT "HERE IS THE FINAL GAME SCORE:"

280 PRINT "I HAVE WON";C;"GAME(S)."

290 PRINT "YOU HAVE WON";H;"GAME(S)."

300 PRINT "AND";Q-(C+H);"GAME(S) ENDED IN A TIE."

310 PRINT: PRINT "THANKS FOR PLAYING!!"

320 END

Yes, folks, that is the kind of stuff I cannot believe I squinted over and read again and again :(

  1. First mentioned here a month ago↩
  2. "Basic Computer Games", originally for the Atari↩
  3. As in this version with commentary; see Appendix A (pg 247)↩
  4. "Effective Go"↩

Tags: old-post

« these pretzels are making me thirsty lisp performance check up »

Copyright © 2020 Agam Brahma

Powered by Cryogen