golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/shootout/chameneosredux.go (about)

     1  //go:build ignore
     2  // +build ignore
     3  
     4  /*
     5  Redistribution and use in source and binary forms, with or without
     6  modification, are permitted provided that the following conditions are met:
     7  
     8      * Redistributions of source code must retain the above copyright
     9      notice, this list of conditions and the following disclaimer.
    10  
    11      * Redistributions in binary form must reproduce the above copyright
    12      notice, this list of conditions and the following disclaimer in the
    13      documentation and/or other materials provided with the distribution.
    14  
    15      * Neither the name of "The Computer Language Benchmarks Game" nor the
    16      name of "The Computer Language Shootout Benchmarks" nor the names of
    17      its contributors may be used to endorse or promote products derived
    18      from this software without specific prior written permission.
    19  
    20  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    22  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    23  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    24  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    25  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    26  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    27  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    28  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    29  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    30  POSSIBILITY OF SUCH DAMAGE.
    31  */
    32  
    33  /* The Computer Language Benchmarks Game
    34   * http://shootout.alioth.debian.org/
    35   *
    36   * contributed by The Go Authors.
    37   */
    38  
    39  package main
    40  
    41  import (
    42  	"flag"
    43  	"fmt"
    44  	"strconv"
    45  )
    46  
    47  const (
    48  	blue = iota
    49  	red
    50  	yellow
    51  	ncol
    52  )
    53  
    54  var complement = [...]int{
    55  	red | red<<2:       red,
    56  	red | yellow<<2:    blue,
    57  	red | blue<<2:      yellow,
    58  	yellow | red<<2:    blue,
    59  	yellow | yellow<<2: yellow,
    60  	yellow | blue<<2:   red,
    61  	blue | red<<2:      yellow,
    62  	blue | yellow<<2:   red,
    63  	blue | blue<<2:     blue,
    64  }
    65  
    66  var colname = [...]string{
    67  	blue:   "blue",
    68  	red:    "red",
    69  	yellow: "yellow",
    70  }
    71  
    72  // information about the current state of a creature.
    73  type info struct {
    74  	colour int // creature's current colour.
    75  	name   int // creature's name.
    76  }
    77  
    78  // exclusive access data-structure kept inside meetingplace.
    79  // if mate is nil, it indicates there's no creature currently waiting;
    80  // otherwise the creature's info is stored in info, and
    81  // it is waiting to receive its mate's information on the mate channel.
    82  type rendez struct {
    83  	n    int         // current number of encounters.
    84  	mate chan<- info // creature waiting when non-nil.
    85  	info info        // info about creature waiting.
    86  }
    87  
    88  // result sent by each creature at the end of processing.
    89  type result struct {
    90  	met  int
    91  	same int
    92  }
    93  
    94  var n = 600
    95  
    96  func main() {
    97  	flag.Parse()
    98  	if flag.NArg() > 0 {
    99  		n, _ = strconv.Atoi(flag.Arg(0))
   100  	}
   101  
   102  	for c0 := 0; c0 < ncol; c0++ {
   103  		for c1 := 0; c1 < ncol; c1++ {
   104  			fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
   105  		}
   106  	}
   107  	fmt.Print("\n")
   108  
   109  	pallmall([]int{blue, red, yellow})
   110  	pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue})
   111  }
   112  
   113  func pallmall(cols []int) {
   114  
   115  	// invariant: meetingplace always contains a value unless a creature
   116  	// is currently dealing with it (whereupon it must put it back).
   117  	meetingplace := make(chan rendez, 1)
   118  	meetingplace <- rendez{n: 0}
   119  
   120  	ended := make(chan result)
   121  	msg := ""
   122  	for i, col := range cols {
   123  		go creature(info{col, i}, meetingplace, ended)
   124  		msg += " " + colname[col]
   125  	}
   126  	fmt.Println(msg)
   127  	tot := 0
   128  	// wait for all results
   129  	for range cols {
   130  		result := <-ended
   131  		tot += result.met
   132  		fmt.Printf("%v%v\n", result.met, spell(result.same, true))
   133  	}
   134  	fmt.Printf("%v\n\n", spell(tot, true))
   135  }
   136  
   137  // in this function, variables ending in 0 refer to the local creature,
   138  // variables ending in 1 to the creature we've met.
   139  func creature(info0 info, meetingplace chan rendez, ended chan result) {
   140  	c0 := make(chan info)
   141  	met := 0
   142  	same := 0
   143  	for {
   144  		var othername int
   145  		// get access to rendez data and decide what to do.
   146  		switch r := <-meetingplace; {
   147  		case r.n >= n:
   148  			// if no more meetings left, then send our result data and exit.
   149  			meetingplace <- rendez{n: r.n}
   150  			ended <- result{met, same}
   151  			return
   152  		case r.mate == nil:
   153  			// no creature waiting; wait for someone to meet us,
   154  			// get their info and send our info in reply.
   155  			meetingplace <- rendez{n: r.n, info: info0, mate: c0}
   156  			info1 := <-c0
   157  			othername = info1.name
   158  			info0.colour = complement[info0.colour|info1.colour<<2]
   159  		default:
   160  			// another creature is waiting for us with its info;
   161  			// increment meeting count,
   162  			// send them our info in reply.
   163  			r.n++
   164  			meetingplace <- rendez{n: r.n, mate: nil}
   165  			r.mate <- info0
   166  			othername = r.info.name
   167  			info0.colour = complement[info0.colour|r.info.colour<<2]
   168  		}
   169  		if othername == info0.name {
   170  			same++
   171  		}
   172  		met++
   173  	}
   174  }
   175  
   176  var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
   177  
   178  func spell(n int, required bool) string {
   179  	if n == 0 && !required {
   180  		return ""
   181  	}
   182  	return spell(n/10, false) + " " + digits[n%10]
   183  }