1
0
mirror of https://github.com/golang/go synced 2024-11-25 13:17:56 -07:00

chameneosredux test modified, bug fixed, faster

based on suggestion from arvindht@gmail.com

R=r, rsc, r1
https://golang.org/cl/157091
This commit is contained in:
Roger Peppe 2009-11-24 11:45:30 -08:00 committed by Russ Cox
parent 541eeb8dbc
commit 9f17353250

View File

@ -35,169 +35,142 @@ POSSIBILITY OF SUCH DAMAGE.
package main
import (
"flag";
"fmt";
"os";
)
var n = flag.Int("n", 600, "count")
type Color int
import "fmt"
import "flag"
const (
blue Color = iota;
blue = iota;
red;
yellow;
ncol;
)
func (c Color) String() string {
return []string{"blue", "red", "yellow"}[c]
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,
}
func complement(c1, c2 Color) Color {
switch c1 << 2 | c2 {
case blue << 2 | blue:
return blue
case blue << 2 | red:
return yellow
case blue << 2 | yellow:
return red
case red << 2 | blue:
return yellow
case red << 2 | red:
return red
case red << 2 | yellow:
return blue
case yellow << 2 | blue:
return red
case yellow << 2 | red:
return blue
case yellow << 2 | yellow:
return yellow
}
fmt.Println("invalid colors", c1, c2);
os.Exit(2);
return 0
var colname = [...]string{
blue: "blue",
red: "red",
yellow: "yellow",
}
func printColors(c1, c2 Color) {
fmt.Printf("%s + %s -> %s\n", c1, c2, complement(c1, c2));
// information about the current state of a creature.
type info struct {
colour int; // creature's current colour.
name int; // creature's name.
}
func printColorTable() {
printColors(blue, blue);
printColors(blue, red);
printColors(blue, yellow);
printColors(red, blue);
printColors(red, red);
printColors(red, yellow);
printColors(yellow, blue);
printColors(yellow, red);
printColors(yellow, yellow);
// 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.
}
type Referee struct {
rendezCount int;
cham []*Chameneos;
rendez chan *Chameneos;
done chan int;
}
func NewReferee() *Referee {
ref := new(Referee);
ref.cham = make([]*Chameneos, 0, 100);
ref.rendez = make(chan *Chameneos);
ref.done = make(chan int);
go ref.Serve();
return ref;
}
func (ref *Referee) Serve() {
for i := 0; i < *n; i++ {
c1 := <-ref.rendez;
c2 := <-ref.rendez;
c1.col, c2.col = complement(c1.col, c2.col), complement(c2.col, c1.col);
c1.rendez <- c2;
c2.rendez <- c1;
}
for i := 0; i < len(ref.cham); i++ {
c := <-ref.rendez;
c.rendez <- nil;
}
ref.done <- 1;
}
func (ref *Referee) Add(ch *Chameneos) {
n := len(ref.cham);
ref.cham = ref.cham[0:n+1];
ref.cham[n] = ch;
}
type Chameneos struct {
index int;
col Color;
rendez chan *Chameneos;
count int;
// result sent by each creature at the end of processing.
type result struct {
met int;
same int;
ref *Referee;
}
func (c *Chameneos) Init(index int, ref *Referee, col Color) *Chameneos {
c.index = index;
c.ref = ref;
c.col = col;
c.rendez = make(chan *Chameneos);
go c.Serve();
return c;
}
func (c *Chameneos) Serve() {
for {
c.ref.rendez <- c;
c1 := <- c.rendez;
if c1 == nil {
break
}
if c1.index == c.index {
c.same++
}
c.count++;
}
}
func play(ref *Referee, color []Color) {
cham := make([]Chameneos, len(color));
for i, c := range color {
fmt.Printf(" %s", c);
ref.Add(cham[i].Init(i, ref, c));
}
fmt.Printf("\n");
<-ref.done;
total := 0;
for _, c := range cham {
total += c.count;
fmt.Printf("%d %s\n", c.count, say(c.same));
}
fmt.Printf("%s\n", say(total));
}
var words = []string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
func say(n int) string {
digits := fmt.Sprint(n);
s := "";
for _, c := range digits {
s += " " + words[c-'0'];
}
return s;
}
var np = flag.Int("n", 600, "count")
var N int
func main() {
flag.Parse();
printColorTable();
fmt.Print("\n");
play(NewReferee(), []Color{blue, red, yellow});
fmt.Print("\n");
play(NewReferee(), []Color{blue, red, yellow, red, yellow, blue, red, yellow, red, blue});
N = *np;
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]])
}
}
pallmall([]int{blue, red, yellow});
pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue});
}
func pallmall(cols []int) {
fmt.Print("\n");
// 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.Println(result.met, spell(result.same, true));
}
fmt.Println(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 more than N meetings, 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];
}