]> Cypherpunks repositories - gostls13.git/commitdiff
chameneosredux test modified, bug fixed, faster
authorRoger Peppe <rogpeppe@gmail.com>
Tue, 24 Nov 2009 19:45:30 +0000 (11:45 -0800)
committerRuss Cox <rsc@golang.org>
Tue, 24 Nov 2009 19:45:30 +0000 (11:45 -0800)
based on suggestion from arvindht@gmail.com

R=r, rsc, r1
https://golang.org/cl/157091

test/bench/chameneosredux.go

index e89e69b7dc537a4e0bf38e87f1274ae6503a6dc0..e957309f7ccfc6c70691a7d074adf3ff4b619798 100644 (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;
+// result sent by each creature at the end of processing.
+type result struct {
+       met     int;
+       same    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;
-}
+var np = flag.Int("n", 600, "count")
+var N int
 
-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;
+func main() {
+       flag.Parse();
+       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]])
+               }
        }
-       ref.done <- 1;
-}
 
-func (ref *Referee) Add(ch *Chameneos) {
-       n := len(ref.cham);
-       ref.cham = ref.cham[0:n+1];
-       ref.cham[n] = ch;
+       pallmall([]int{blue, red, yellow});
+       pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue});
 }
 
-type Chameneos struct {
-       index   int;
-       col     Color;
-       rendez  chan *Chameneos;
-       count   int;
-       same    int;
-       ref     *Referee;
-}
+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};
 
-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;
+       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));
 }
 
-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 {
-               c.ref.rendez <- c;
-               c1 := <- c.rendez;
-               if c1 == nil {
-                       break
+               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 c1.index == c.index {
-                       c.same++
+               if othername == info0.name {
+                       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));
+               met++;
        }
-       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 {
-       digits := fmt.Sprint(n);
-       s := "";
-       for _, c := range digits {
-               s += " " + words[c-'0'];
+func spell(n int, required bool) string {
+       if n == 0 && !required {
+               return ""
        }
-       return s;
-}
-
-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});
+       return spell(n/10, false) + " " + digits[n%10];
 }