mirror of
https://github.com/golang/go
synced 2024-11-18 02:44:48 -07:00
8d504c4e97
Fixes #6102. LGTM=gri R=ken, r, gri CC=golang-codereviews https://golang.org/cl/113120043
181 lines
5.1 KiB
Go
181 lines
5.1 KiB
Go
/*
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
|
name of "The Computer Language Shootout Benchmarks" nor the names of
|
|
its contributors may be used to endorse or promote products derived
|
|
from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* The Computer Language Benchmarks Game
|
|
* http://shootout.alioth.debian.org/
|
|
*
|
|
* contributed by The Go Authors.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
blue = iota
|
|
red
|
|
yellow
|
|
ncol
|
|
)
|
|
|
|
var complement = [...]int{
|
|
red | red<<2: red,
|
|
red | yellow<<2: blue,
|
|
red | blue<<2: yellow,
|
|
yellow | red<<2: blue,
|
|
yellow | yellow<<2: yellow,
|
|
yellow | blue<<2: red,
|
|
blue | red<<2: yellow,
|
|
blue | yellow<<2: red,
|
|
blue | blue<<2: blue,
|
|
}
|
|
|
|
var colname = [...]string{
|
|
blue: "blue",
|
|
red: "red",
|
|
yellow: "yellow",
|
|
}
|
|
|
|
// information about the current state of a creature.
|
|
type info struct {
|
|
colour int // creature's current colour.
|
|
name int // creature's name.
|
|
}
|
|
|
|
// exclusive access data-structure kept inside meetingplace.
|
|
// if mate is nil, it indicates there's no creature currently waiting;
|
|
// otherwise the creature's info is stored in info, and
|
|
// it is waiting to receive its mate's information on the mate channel.
|
|
type rendez struct {
|
|
n int // current number of encounters.
|
|
mate chan<- info // creature waiting when non-nil.
|
|
info info // info about creature waiting.
|
|
}
|
|
|
|
// result sent by each creature at the end of processing.
|
|
type result struct {
|
|
met int
|
|
same int
|
|
}
|
|
|
|
var n = 600
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
if flag.NArg() > 0 {
|
|
n, _ = strconv.Atoi(flag.Arg(0))
|
|
}
|
|
|
|
for c0 := 0; c0 < ncol; c0++ {
|
|
for c1 := 0; c1 < ncol; c1++ {
|
|
fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
|
|
}
|
|
}
|
|
fmt.Print("\n")
|
|
|
|
pallmall([]int{blue, red, yellow})
|
|
pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue})
|
|
}
|
|
|
|
func pallmall(cols []int) {
|
|
|
|
// invariant: meetingplace always contains a value unless a creature
|
|
// is currently dealing with it (whereupon it must put it back).
|
|
meetingplace := make(chan rendez, 1)
|
|
meetingplace <- rendez{n: 0}
|
|
|
|
ended := make(chan result)
|
|
msg := ""
|
|
for i, col := range cols {
|
|
go creature(info{col, i}, meetingplace, ended)
|
|
msg += " " + colname[col]
|
|
}
|
|
fmt.Println(msg)
|
|
tot := 0
|
|
// wait for all results
|
|
for range cols {
|
|
result := <-ended
|
|
tot += result.met
|
|
fmt.Printf("%v%v\n", result.met, spell(result.same, true))
|
|
}
|
|
fmt.Printf("%v\n\n", spell(tot, true))
|
|
}
|
|
|
|
// in this function, variables ending in 0 refer to the local creature,
|
|
// variables ending in 1 to the creature we've met.
|
|
func creature(info0 info, meetingplace chan rendez, ended chan result) {
|
|
c0 := make(chan info)
|
|
met := 0
|
|
same := 0
|
|
for {
|
|
var othername int
|
|
// get access to rendez data and decide what to do.
|
|
switch r := <-meetingplace; {
|
|
case r.n >= n:
|
|
// if no more meetings left, then send our result data and exit.
|
|
meetingplace <- rendez{n: r.n}
|
|
ended <- result{met, same}
|
|
return
|
|
case r.mate == nil:
|
|
// no creature waiting; wait for someone to meet us,
|
|
// get their info and send our info in reply.
|
|
meetingplace <- rendez{n: r.n, info: info0, mate: c0}
|
|
info1 := <-c0
|
|
othername = info1.name
|
|
info0.colour = complement[info0.colour|info1.colour<<2]
|
|
default:
|
|
// another creature is waiting for us with its info;
|
|
// increment meeting count,
|
|
// send them our info in reply.
|
|
r.n++
|
|
meetingplace <- rendez{n: r.n, mate: nil}
|
|
r.mate <- info0
|
|
othername = r.info.name
|
|
info0.colour = complement[info0.colour|r.info.colour<<2]
|
|
}
|
|
if othername == info0.name {
|
|
same++
|
|
}
|
|
met++
|
|
}
|
|
}
|
|
|
|
var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
|
|
|
|
func spell(n int, required bool) string {
|
|
if n == 0 && !required {
|
|
return ""
|
|
}
|
|
return spell(n/10, false) + " " + digits[n%10]
|
|
}
|