Commit 9f173532 authored by Roger Peppe's avatar Roger Peppe Committed by Russ Cox

chameneosredux test modified, bug fixed, faster

based on suggestion from arvindht@gmail.com

R=r, rsc, r1
https://golang.org/cl/157091
parent 541eeb8d
...@@ -35,169 +35,142 @@ POSSIBILITY OF SUCH DAMAGE. ...@@ -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; same int;
done chan int;
} }
func NewReferee() *Referee { var np = flag.Int("n", 600, "count")
ref := new(Referee); var N int
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() { func main() {
for i := 0; i < *n; i++ { flag.Parse();
c1 := <-ref.rendez; N = *np;
c2 := <-ref.rendez;
c1.col, c2.col = complement(c1.col, c2.col), complement(c2.col, c1.col); for c0 := 0; c0 < ncol; c0++ {
c1.rendez <- c2; for c1 := 0; c1 < ncol; c1++ {
c2.rendez <- c1; fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
} }
for i := 0; i < len(ref.cham); i++ {
c := <-ref.rendez;
c.rendez <- nil;
} }
ref.done <- 1;
}
func (ref *Referee) Add(ch *Chameneos) { pallmall([]int{blue, red, yellow});
n := len(ref.cham); pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue});
ref.cham = ref.cham[0:n+1];
ref.cham[n] = ch;
} }
type Chameneos struct { func pallmall(cols []int) {
index int; fmt.Print("\n");
col Color;
rendez chan *Chameneos; // invariant: meetingplace always contains a value unless a creature
count int; // is currently dealing with it (whereupon it must put it back).
same int; meetingplace := make(chan rendez, 1);
ref *Referee; meetingplace <- rendez{n: 0};
}
func (c *Chameneos) Init(index int, ref *Referee, col Color) *Chameneos { ended := make(chan result);
c.index = index; msg := "";
c.ref = ref; for i, col := range cols {
c.col = col; go creature(info{col, i}, meetingplace, ended);
c.rendez = make(chan *Chameneos); msg += " " + colname[col];
go c.Serve(); }
return c; 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));
} }
func (c *Chameneos) Serve() { // 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 { for {
c.ref.rendez <- c; var othername int;
c1 := <- c.rendez; // get access to rendez data and decide what to do.
if c1 == nil { switch r := <-meetingplace; {
break 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 c1.index == c.index { if othername == info0.name {
c.same++ same++
} }
c.count++; met++;
}
}
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"} var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
func say(n int) string { func spell(n int, required bool) string {
digits := fmt.Sprint(n); if n == 0 && !required {
s := ""; return ""
for _, c := range digits {
s += " " + words[c-'0'];
} }
return s; return spell(n/10, false) + " " + digits[n%10];
}
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});
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment