From 103d89b8bcf3b49cab829c7bee8b9691ed7f8cca Mon Sep 17 00:00:00 2001 From: Jamal Carvalho Date: Wed, 27 Oct 2021 18:56:01 +0000 Subject: [PATCH] go.dev: fix go playground on homepage Copied the playground example files to the go.dev content directory to fix the homepage playground. This works locally because requests to /doc are passed to the golang.org content directory but breaks on app engine when requests go to go.dev/doc. Change-Id: I858b7fca905bbacd0acbf8ea33d1a5188fbd3773 Reviewed-on: https://go-review.googlesource.com/c/website/+/359214 Trust: Jamal Carvalho Run-TryBot: Jamal Carvalho Reviewed-by: Julie Qiu Reviewed-by: Dmitri Shuralyov TryBot-Result: Go Bot Website-Publish: DO NOT USE --- go.dev/_content/doc/play/fib.go | 19 +++++ go.dev/_content/doc/play/hello.go | 9 ++ go.dev/_content/doc/play/life.go | 113 +++++++++++++++++++++++++ go.dev/_content/doc/play/peano.go | 88 +++++++++++++++++++ go.dev/_content/doc/play/pi.go | 34 ++++++++ go.dev/_content/doc/play/sieve.go | 36 ++++++++ go.dev/_content/doc/play/solitaire.go | 117 ++++++++++++++++++++++++++ go.dev/_content/doc/play/tree.go | 100 ++++++++++++++++++++++ 8 files changed, 516 insertions(+) create mode 100644 go.dev/_content/doc/play/fib.go create mode 100644 go.dev/_content/doc/play/hello.go create mode 100644 go.dev/_content/doc/play/life.go create mode 100644 go.dev/_content/doc/play/peano.go create mode 100644 go.dev/_content/doc/play/pi.go create mode 100644 go.dev/_content/doc/play/sieve.go create mode 100644 go.dev/_content/doc/play/solitaire.go create mode 100644 go.dev/_content/doc/play/tree.go diff --git a/go.dev/_content/doc/play/fib.go b/go.dev/_content/doc/play/fib.go new file mode 100644 index 00000000..19e47210 --- /dev/null +++ b/go.dev/_content/doc/play/fib.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +// fib returns a function that returns +// successive Fibonacci numbers. +func fib() func() int { + a, b := 0, 1 + return func() int { + a, b = b, a+b + return a + } +} + +func main() { + f := fib() + // Function calls are evaluated left-to-right. + fmt.Println(f(), f(), f(), f(), f()) +} diff --git a/go.dev/_content/doc/play/hello.go b/go.dev/_content/doc/play/hello.go new file mode 100644 index 00000000..3badf125 --- /dev/null +++ b/go.dev/_content/doc/play/hello.go @@ -0,0 +1,9 @@ +// You can edit this code! +// Click here and start typing. +package main + +import "fmt" + +func main() { + fmt.Println("Hello, 世界") +} diff --git a/go.dev/_content/doc/play/life.go b/go.dev/_content/doc/play/life.go new file mode 100644 index 00000000..51afb61f --- /dev/null +++ b/go.dev/_content/doc/play/life.go @@ -0,0 +1,113 @@ +// An implementation of Conway's Game of Life. +package main + +import ( + "bytes" + "fmt" + "math/rand" + "time" +) + +// Field represents a two-dimensional field of cells. +type Field struct { + s [][]bool + w, h int +} + +// NewField returns an empty field of the specified width and height. +func NewField(w, h int) *Field { + s := make([][]bool, h) + for i := range s { + s[i] = make([]bool, w) + } + return &Field{s: s, w: w, h: h} +} + +// Set sets the state of the specified cell to the given value. +func (f *Field) Set(x, y int, b bool) { + f.s[y][x] = b +} + +// Alive reports whether the specified cell is alive. +// If the x or y coordinates are outside the field boundaries they are wrapped +// toroidally. For instance, an x value of -1 is treated as width-1. +func (f *Field) Alive(x, y int) bool { + x += f.w + x %= f.w + y += f.h + y %= f.h + return f.s[y][x] +} + +// Next returns the state of the specified cell at the next time step. +func (f *Field) Next(x, y int) bool { + // Count the adjacent cells that are alive. + alive := 0 + for i := -1; i <= 1; i++ { + for j := -1; j <= 1; j++ { + if (j != 0 || i != 0) && f.Alive(x+i, y+j) { + alive++ + } + } + } + // Return next state according to the game rules: + // exactly 3 neighbors: on, + // exactly 2 neighbors: maintain current state, + // otherwise: off. + return alive == 3 || alive == 2 && f.Alive(x, y) +} + +// Life stores the state of a round of Conway's Game of Life. +type Life struct { + a, b *Field + w, h int +} + +// NewLife returns a new Life game state with a random initial state. +func NewLife(w, h int) *Life { + a := NewField(w, h) + for i := 0; i < (w * h / 4); i++ { + a.Set(rand.Intn(w), rand.Intn(h), true) + } + return &Life{ + a: a, b: NewField(w, h), + w: w, h: h, + } +} + +// Step advances the game by one instant, recomputing and updating all cells. +func (l *Life) Step() { + // Update the state of the next field (b) from the current field (a). + for y := 0; y < l.h; y++ { + for x := 0; x < l.w; x++ { + l.b.Set(x, y, l.a.Next(x, y)) + } + } + // Swap fields a and b. + l.a, l.b = l.b, l.a +} + +// String returns the game board as a string. +func (l *Life) String() string { + var buf bytes.Buffer + for y := 0; y < l.h; y++ { + for x := 0; x < l.w; x++ { + b := byte(' ') + if l.a.Alive(x, y) { + b = '*' + } + buf.WriteByte(b) + } + buf.WriteByte('\n') + } + return buf.String() +} + +func main() { + l := NewLife(40, 15) + for i := 0; i < 300; i++ { + l.Step() + fmt.Print("\x0c", l) // Clear screen and print field. + time.Sleep(time.Second / 30) + } +} diff --git a/go.dev/_content/doc/play/peano.go b/go.dev/_content/doc/play/peano.go new file mode 100644 index 00000000..214fe1b6 --- /dev/null +++ b/go.dev/_content/doc/play/peano.go @@ -0,0 +1,88 @@ +// Peano integers are represented by a linked +// list whose nodes contain no data +// (the nodes are the data). +// http://en.wikipedia.org/wiki/Peano_axioms + +// This program demonstrates that Go's automatic +// stack management can handle heavily recursive +// computations. + +package main + +import "fmt" + +// Number is a pointer to a Number +type Number *Number + +// The arithmetic value of a Number is the +// count of the nodes comprising the list. +// (See the count function below.) + +// ------------------------------------- +// Peano primitives + +func zero() *Number { + return nil +} + +func isZero(x *Number) bool { + return x == nil +} + +func add1(x *Number) *Number { + e := new(Number) + *e = x + return e +} + +func sub1(x *Number) *Number { + return *x +} + +func add(x, y *Number) *Number { + if isZero(y) { + return x + } + return add(add1(x), sub1(y)) +} + +func mul(x, y *Number) *Number { + if isZero(x) || isZero(y) { + return zero() + } + return add(mul(x, sub1(y)), x) +} + +func fact(n *Number) *Number { + if isZero(n) { + return add1(zero()) + } + return mul(fact(sub1(n)), n) +} + +// ------------------------------------- +// Helpers to generate/count Peano integers + +func gen(n int) *Number { + if n > 0 { + return add1(gen(n - 1)) + } + return zero() +} + +func count(x *Number) int { + if isZero(x) { + return 0 + } + return count(sub1(x)) + 1 +} + +// ------------------------------------- +// Print i! for i in [0,9] + +func main() { + for i := 0; i <= 9; i++ { + f := count(fact(gen(i))) + fmt.Println(i, "! =", f) + } +} diff --git a/go.dev/_content/doc/play/pi.go b/go.dev/_content/doc/play/pi.go new file mode 100644 index 00000000..f3c3f358 --- /dev/null +++ b/go.dev/_content/doc/play/pi.go @@ -0,0 +1,34 @@ +// Concurrent computation of pi. +// See https://goo.gl/la6Kli. +// +// This demonstrates Go's ability to handle +// large numbers of concurrent processes. +// It is an unreasonable way to calculate pi. +package main + +import ( + "fmt" + "math" +) + +func main() { + fmt.Println(pi(5000)) +} + +// pi launches n goroutines to compute an +// approximation of pi. +func pi(n int) float64 { + ch := make(chan float64) + for k := 0; k < n; k++ { + go term(ch, float64(k)) + } + f := 0.0 + for k := 0; k < n; k++ { + f += <-ch + } + return f +} + +func term(ch chan float64, k float64) { + ch <- 4 * math.Pow(-1, k) / (2*k + 1) +} diff --git a/go.dev/_content/doc/play/sieve.go b/go.dev/_content/doc/play/sieve.go new file mode 100644 index 00000000..51909345 --- /dev/null +++ b/go.dev/_content/doc/play/sieve.go @@ -0,0 +1,36 @@ +// A concurrent prime sieve + +package main + +import "fmt" + +// Send the sequence 2, 3, 4, ... to channel 'ch'. +func Generate(ch chan<- int) { + for i := 2; ; i++ { + ch <- i // Send 'i' to channel 'ch'. + } +} + +// Copy the values from channel 'in' to channel 'out', +// removing those divisible by 'prime'. +func Filter(in <-chan int, out chan<- int, prime int) { + for { + i := <-in // Receive value from 'in'. + if i%prime != 0 { + out <- i // Send 'i' to 'out'. + } + } +} + +// The prime sieve: Daisy-chain Filter processes. +func main() { + ch := make(chan int) // Create a new channel. + go Generate(ch) // Launch Generate goroutine. + for i := 0; i < 10; i++ { + prime := <-ch + fmt.Println(prime) + ch1 := make(chan int) + go Filter(ch, ch1, prime) + ch = ch1 + } +} diff --git a/go.dev/_content/doc/play/solitaire.go b/go.dev/_content/doc/play/solitaire.go new file mode 100644 index 00000000..15022aa1 --- /dev/null +++ b/go.dev/_content/doc/play/solitaire.go @@ -0,0 +1,117 @@ +// This program solves the (English) peg +// solitaire board game. +// http://en.wikipedia.org/wiki/Peg_solitaire + +package main + +import "fmt" + +const N = 11 + 1 // length of a row (+1 for \n) + +// The board must be surrounded by 2 illegal +// fields in each direction so that move() +// doesn't need to check the board boundaries. +// Periods represent illegal fields, +// ● are pegs, and ○ are holes. + +var board = []rune( + `........... +........... +....●●●.... +....●●●.... +..●●●●●●●.. +..●●●○●●●.. +..●●●●●●●.. +....●●●.... +....●●●.... +........... +........... +`) + +// center is the position of the center hole if +// there is a single one; otherwise it is -1. +var center int + +func init() { + n := 0 + for pos, field := range board { + if field == '○' { + center = pos + n++ + } + } + if n != 1 { + center = -1 // no single hole + } +} + +var moves int // number of times move is called + +// move tests if there is a peg at position pos that +// can jump over another peg in direction dir. If the +// move is valid, it is executed and move returns true. +// Otherwise, move returns false. +func move(pos, dir int) bool { + moves++ + if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' { + board[pos] = '○' + board[pos+dir] = '○' + board[pos+2*dir] = '●' + return true + } + return false +} + +// unmove reverts a previously executed valid move. +func unmove(pos, dir int) { + board[pos] = '●' + board[pos+dir] = '●' + board[pos+2*dir] = '○' +} + +// solve tries to find a sequence of moves such that +// there is only one peg left at the end; if center is +// >= 0, that last peg must be in the center position. +// If a solution is found, solve prints the board after +// each move in a backward fashion (i.e., the last +// board position is printed first, all the way back to +// the starting board position). +func solve() bool { + var last, n int + for pos, field := range board { + // try each board position + if field == '●' { + // found a peg + for _, dir := range [...]int{-1, -N, +1, +N} { + // try each direction + if move(pos, dir) { + // a valid move was found and executed, + // see if this new board has a solution + if solve() { + unmove(pos, dir) + fmt.Println(string(board)) + return true + } + unmove(pos, dir) + } + } + last = pos + n++ + } + } + // tried each possible move + if n == 1 && (center < 0 || last == center) { + // there's only one peg left + fmt.Println(string(board)) + return true + } + // no solution found for this board + return false +} + +func main() { + if !solve() { + fmt.Println("no solution found") + } + fmt.Println(moves, "moves tried") +} diff --git a/go.dev/_content/doc/play/tree.go b/go.dev/_content/doc/play/tree.go new file mode 100644 index 00000000..3790e6cd --- /dev/null +++ b/go.dev/_content/doc/play/tree.go @@ -0,0 +1,100 @@ +// Go's concurrency primitives make it easy to +// express concurrent concepts, such as +// this binary tree comparison. +// +// Trees may be of different shapes, +// but have the same contents. For example: +// +// 4 6 +// 2 6 4 7 +// 1 3 5 7 2 5 +// 1 3 +// +// This program compares a pair of trees by +// walking each in its own goroutine, +// sending their contents through a channel +// to a third goroutine that compares them. + +package main + +import ( + "fmt" + "math/rand" +) + +// A Tree is a binary tree with integer values. +type Tree struct { + Left *Tree + Value int + Right *Tree +} + +// Walk traverses a tree depth-first, +// sending each Value on a channel. +func Walk(t *Tree, ch chan int) { + if t == nil { + return + } + Walk(t.Left, ch) + ch <- t.Value + Walk(t.Right, ch) +} + +// Walker launches Walk in a new goroutine, +// and returns a read-only channel of values. +func Walker(t *Tree) <-chan int { + ch := make(chan int) + go func() { + Walk(t, ch) + close(ch) + }() + return ch +} + +// Compare reads values from two Walkers +// that run simultaneously, and returns true +// if t1 and t2 have the same contents. +func Compare(t1, t2 *Tree) bool { + c1, c2 := Walker(t1), Walker(t2) + for { + v1, ok1 := <-c1 + v2, ok2 := <-c2 + if !ok1 || !ok2 { + return ok1 == ok2 + } + if v1 != v2 { + break + } + } + return false +} + +// New returns a new, random binary tree +// holding the values 1k, 2k, ..., nk. +func New(n, k int) *Tree { + var t *Tree + for _, v := range rand.Perm(n) { + t = insert(t, (1+v)*k) + } + return t +} + +func insert(t *Tree, v int) *Tree { + if t == nil { + return &Tree{nil, v, nil} + } + if v < t.Value { + t.Left = insert(t.Left, v) + return t + } + t.Right = insert(t.Right, v) + return t +} + +func main() { + t1 := New(100, 1) + fmt.Println(Compare(t1, New(100, 1)), "Same Contents") + fmt.Println(Compare(t1, New(99, 1)), "Differing Sizes") + fmt.Println(Compare(t1, New(100, 2)), "Differing Values") + fmt.Println(Compare(t1, New(101, 2)), "Dissimilar") +}