mirror of
https://github.com/golang/go
synced 2024-11-11 20:01:37 -07:00
cmd/godoc: add toys, tour button to playground
Fixes #3241. R=golang-dev, r CC=golang-dev https://golang.org/cl/5835043
This commit is contained in:
parent
4b872d61fe
commit
d528f52d87
17
doc/play/fib.go
Normal file
17
doc/play/fib.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
// 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.
|
||||
println(f(), f(), f(), f(), f())
|
||||
}
|
7
doc/play/hello.go
Normal file
7
doc/play/hello.go
Normal file
@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, 世界")
|
||||
}
|
88
doc/play/peano.go
Normal file
88
doc/play/peano.go
Normal file
@ -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 the power of Go's
|
||||
// segmented stacks when doing massively
|
||||
// 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)
|
||||
}
|
||||
}
|
34
doc/play/pi.go
Normal file
34
doc/play/pi.go
Normal file
@ -0,0 +1,34 @@
|
||||
// Concurrent computation of pi.
|
||||
// See http://goo.gl/ZuTZM.
|
||||
//
|
||||
// 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)
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
// preCompile - callback to mutate request data before compiling
|
||||
// postCompile - callback to read response data after compiling
|
||||
// simple - use plain textarea instead of CodeMirror.
|
||||
// toysEl - select element with a list of toys.
|
||||
function playground(opts) {
|
||||
var simple = opts['simple'];
|
||||
var code = $(opts['codeEl']);
|
||||
@ -109,6 +110,16 @@ function playground(opts) {
|
||||
}
|
||||
return $(opts['codeEl']).val();
|
||||
}
|
||||
function setBody(text) {
|
||||
if (editor) {
|
||||
editor.setValue(text);
|
||||
return;
|
||||
}
|
||||
$(opts['codeEl']).val(text);
|
||||
}
|
||||
function origin(href) {
|
||||
return (""+href).split("/").slice(0, 3).join("/");
|
||||
}
|
||||
|
||||
var seq = 0;
|
||||
function run() {
|
||||
@ -164,43 +175,53 @@ function playground(opts) {
|
||||
}
|
||||
$(opts['runEl']).click(run);
|
||||
|
||||
if (opts['shareEl'] == null || (opts['shareURLEl'] == null && opts['shareRedirect'] == null)) {
|
||||
return editor;
|
||||
}
|
||||
|
||||
function origin(href) {
|
||||
return (""+href).split("/").slice(0, 3).join("/");
|
||||
}
|
||||
|
||||
var shareURL;
|
||||
if (opts['shareURLEl']) {
|
||||
shareURL = $(opts['shareURLEl']).hide();
|
||||
}
|
||||
var sharing = false;
|
||||
$(opts['shareEl']).click(function() {
|
||||
if (sharing) return;
|
||||
sharing = true;
|
||||
$.ajax("/share", {
|
||||
processData: false,
|
||||
data: body(),
|
||||
type: "POST",
|
||||
complete: function(xhr) {
|
||||
sharing = false;
|
||||
if (xhr.status != 200) {
|
||||
alert("Server error; try again.");
|
||||
return;
|
||||
if (opts['shareEl'] != null && (opts['shareURLEl'] != null || opts['shareRedirect'] != null)) {
|
||||
var shareURL;
|
||||
if (opts['shareURLEl']) {
|
||||
shareURL = $(opts['shareURLEl']).hide();
|
||||
}
|
||||
var sharing = false;
|
||||
$(opts['shareEl']).click(function() {
|
||||
if (sharing) return;
|
||||
sharing = true;
|
||||
$.ajax("/share", {
|
||||
processData: false,
|
||||
data: body(),
|
||||
type: "POST",
|
||||
complete: function(xhr) {
|
||||
sharing = false;
|
||||
if (xhr.status != 200) {
|
||||
alert("Server error; try again.");
|
||||
return;
|
||||
}
|
||||
if (opts['shareRedirect']) {
|
||||
window.location = opts['shareRedirect'] + xhr.responseText;
|
||||
}
|
||||
if (shareURL) {
|
||||
var url = origin(window.location) + "/p/" + xhr.responseText;
|
||||
shareURL.show().val(url).focus().select();
|
||||
}
|
||||
}
|
||||
if (opts['shareRedirect']) {
|
||||
window.location = opts['shareRedirect'] + xhr.responseText;
|
||||
}
|
||||
if (shareURL) {
|
||||
var url = origin(window.location) + "/p/" +
|
||||
xhr.responseText;
|
||||
shareURL.show().val(url).focus().select();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (opts['toysEl'] != null) {
|
||||
$(opts['toysEl']).bind('change', function() {
|
||||
var toy = $(this).val();
|
||||
$.ajax("/doc/play/"+toy, {
|
||||
processData: false,
|
||||
type: "GET",
|
||||
complete: function(xhr) {
|
||||
if (xhr.status != 200) {
|
||||
alert("Server error; try again.")
|
||||
return;
|
||||
}
|
||||
setBody(xhr.responseText);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
34
doc/play/sieve.go
Normal file
34
doc/play/sieve.go
Normal file
@ -0,0 +1,34 @@
|
||||
// A concurrent prime sieve
|
||||
|
||||
package main
|
||||
|
||||
// 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
|
||||
print(prime, "\n")
|
||||
ch1 := make(chan int)
|
||||
go Filter(ch, ch1, prime)
|
||||
ch = ch1
|
||||
}
|
||||
}
|
117
doc/play/solitaire.go
Normal file
117
doc/play/solitaire.go
Normal file
@ -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 = []int(
|
||||
`...........
|
||||
...........
|
||||
....●●●....
|
||||
....●●●....
|
||||
..●●●●●●●..
|
||||
..●●●○●●●..
|
||||
..●●●●●●●..
|
||||
....●●●....
|
||||
....●●●....
|
||||
...........
|
||||
...........
|
||||
`)
|
||||
|
||||
// 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)
|
||||
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
|
||||
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")
|
||||
}
|
100
doc/play/tree.go
Normal file
100
doc/play/tree.go
Normal file
@ -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")
|
||||
}
|
@ -24,8 +24,20 @@ Hello, 世界
|
||||
</pre>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a class="run" href="#">Run</a>
|
||||
<a class="share" href="#">Share</a>
|
||||
<a class="run" href="#" title="Run this code [shift-enter]">Run</a>
|
||||
<a class="share" href="#" title="Share this code">Share</a>
|
||||
<a class="tour" href="http://tour.golang.org/" title="Learn Go from your browser">Tour</a>
|
||||
</div>
|
||||
<div class="toys">
|
||||
<select>
|
||||
<option value="hello.go">Hello, World!</option>
|
||||
<option value="fib.go">Fibonacci Closure</option>
|
||||
<option value="peano.go">Peano Integers</option>
|
||||
<option value="pi.go">Concurrent pi</option>
|
||||
<option value="sieve.go">Concurrent Prime Sieve</option>
|
||||
<option value="solitaire.go">Peg Solitaire Solver</option>
|
||||
<option value="tree.go">Tree Comparison</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -117,7 +129,8 @@ function init() {
|
||||
"outputEl": "#learn .output",
|
||||
"runEl": "#learn .run",
|
||||
"shareEl": "#learn .share",
|
||||
"shareRedirect": "http://play.golang.org/p/"
|
||||
"shareRedirect": "http://play.golang.org/p/",
|
||||
"toysEl": "#learn .toys select"
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -322,21 +322,21 @@ div#learn .output {
|
||||
border: 1px solid #375EAB;
|
||||
}
|
||||
div#learn .buttons {
|
||||
float: right;
|
||||
padding: 20px 0 10px 0;
|
||||
text-align: right;
|
||||
}
|
||||
div#learn .buttons a {
|
||||
height: 16px;
|
||||
margin-left: 5px;
|
||||
|
||||
padding: 10px;
|
||||
}
|
||||
div#learn .buttons .tour {
|
||||
float: right;
|
||||
div#learn .toys {
|
||||
margin-top: 8px;
|
||||
}
|
||||
div#learn .buttons .tour a {
|
||||
margin-right: 0;
|
||||
font-weight: bold;
|
||||
div#learn .toys select {
|
||||
border: 1px solid #375EAB;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div#blog,
|
||||
|
@ -67,7 +67,7 @@ var (
|
||||
// search index
|
||||
indexEnabled = flag.Bool("index", false, "enable search index")
|
||||
indexFiles = flag.String("index_files", "", "glob pattern specifying index files;"+
|
||||
"if not empty, the index is read from these files in sorted order")
|
||||
"if not empty, the index is read from these files in sorted order")
|
||||
maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
|
||||
indexThrottle = flag.Float64("index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle")
|
||||
|
||||
@ -102,6 +102,7 @@ func registerPublicHandlers(mux *http.ServeMux) {
|
||||
mux.Handle(cmdHandler.pattern, &cmdHandler)
|
||||
mux.Handle(pkgHandler.pattern, &pkgHandler)
|
||||
mux.HandleFunc("/doc/codewalk/", codewalk)
|
||||
mux.Handle("/doc/play/", fileServer)
|
||||
mux.HandleFunc("/search", search)
|
||||
mux.Handle("/robots.txt", fileServer)
|
||||
mux.HandleFunc("/opensearch.xml", serveSearchDesc)
|
||||
|
Loading…
Reference in New Issue
Block a user