1
0
mirror of https://github.com/golang/go synced 2024-11-25 23:07:58 -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 package main
import ( import "fmt"
"flag"; import "flag"
"fmt";
"os";
)
var n = flag.Int("n", 600, "count")
type Color int
const ( const (
blue Color = iota; blue = iota;
red; red;
yellow; yellow;
ncol;
) )
func (c Color) String() string { var complement = [...]int{
return []string{"blue", "red", "yellow"}[c] 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 { var colname = [...]string{
switch c1 << 2 | c2 { blue: "blue",
case blue << 2 | blue: red: "red",
return blue yellow: "yellow",
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
} }
func printColors(c1, c2 Color) { // information about the current state of a creature.
fmt.Printf("%s + %s -> %s\n", c1, c2, complement(c1, c2)); type info struct {
colour int; // creature's current colour.
name int; // creature's name.
} }
func printColorTable() { // exclusive access data-structure kept inside meetingplace.
printColors(blue, blue); // if mate is nil, it indicates there's no creature currently waiting;
printColors(blue, red); // otherwise the creature's info is stored in info, and
printColors(blue, yellow); // it is waiting to receive its mate's information on the mate channel.
printColors(red, blue); type rendez struct {
printColors(red, red); n int; // current number of encounters.
printColors(red, yellow); mate chan<- info; // creature waiting when non-nil.
printColors(yellow, blue); info info; // info about creature waiting.
printColors(yellow, red);
printColors(yellow, yellow);
} }
type Referee struct { // result sent by each creature at the end of processing.
rendezCount int; type result struct {
cham []*Chameneos; met int;
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;
same int; same int;
ref *Referee;
} }
func (c *Chameneos) Init(index int, ref *Referee, col Color) *Chameneos { var np = flag.Int("n", 600, "count")
c.index = index; var N int
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;
}
func main() { func main() {
flag.Parse(); flag.Parse();
printColorTable(); N = *np;
fmt.Print("\n");
play(NewReferee(), []Color{blue, red, yellow}); for c0 := 0; c0 < ncol; c0++ {
fmt.Print("\n"); for c1 := 0; c1 < ncol; c1++ {
play(NewReferee(), []Color{blue, red, yellow, red, yellow, blue, red, yellow, red, blue}); 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];
} }