1  package main
   2  import ( "fmt"; "os"; "flag"; "strconv"; "rand"; "time" )
   3  
   4  
   5  type Throw int
   6  const ( ROCK Throw = iota; PAPER; SCISSORS; NUM_THROWS )
   7  
   8  
   9  func beats(me Throw, you Throw) bool {
  10    return (me == ROCK     && you == SCISSORS) ||
  11           (me == SCISSORS && you == PAPER)    ||
  12           (me == PAPER    && you == ROCK)
  13  }
  14  
  15  
  16  func random_throw() Throw { return Throw(rand.Intn(int(NUM_THROWS))) }
  17  
  18  
  19  type Packet struct { throw Throw; lifetime int }
  20  
  21  
  22  type Result struct { player int; score int }
  23  
  24  
  25  
  26  
  27  
  28  
  29  
  30  
  31  
  32  
  33  
  34  
  35  
  36  func play_rounds(read chan Packet, write chan Packet, n int) int {
  37    score := 0
  38    
  39    for r := 0; r < 1000; r++ {
  40      throw := random_throw()
  41      write <- Packet { throw, n - 1 }
  42      
  43      
  44      for got := 1; got < n; got++ {
  45        opp := <- read
  46        if beats(throw, opp.throw) { score++ }
  47        
  48        
  49        opp.lifetime--
  50        if opp.lifetime != 0 { write <- opp }
  51      }
  52    }
  53    
  54    return score
  55  }
  56  
  57  
  58  
  59  
  60  
  61  
  62  
  63  
  64  
  65  
  66  
  67  
  68  
  69  
  70  func player(write chan Packet, report chan Result, id int, n int) chan Packet {
  71    read := make(chan Packet, n)
  72    
  73    go func() {
  74      score := play_rounds(read, write, n);
  75      report <- Result { id, score }
  76    }()
  77    
  78    return read
  79  }
  80  
  81  
  82  
  83  
  84  func main() {
  85    if flag.NArg() != 1 {
  86      os.Stderr.WriteString("Usage: jkp <N>\n")
  87      os.Exit(1)
  88    }
  89  
  90    n, err := strconv.Atoi(flag.Arg(0))
  91    
  92    if err != nil {
  93      fmt.Fprintf(os.Stderr, "The argument must be a number (%v)\n", err)
  94      os.Exit(1)
  95    }
  96    
  97    if n < 2 {
  98      fmt.Fprintf(os.Stderr, "The argument must be 2 or greater (not %d)\n", n)
  99      os.Exit(1)
 100    }
 101    
 102    rand.Seed(time.Nanoseconds())
 103    
 104    
 105  
 106  
 107  
 108  
 109  
 110  
 111    report := make(chan Result)
 112    ring := make(chan Packet, n)
 113    
 114    
 115    read := ring
 116    
 117    for i := 1; i < n; i++ {
 118      ring = player(ring, report, i, n)
 119    }
 120    
 121    write := ring
 122    
 123    
 124    score := play_rounds(read, write, n);
 125  
 126    
 127    fmt.Printf("Player %d  Score %d\n", 0, score)
 128    
 129    for i := 1; i < n; i++ {
 130      r := <- report
 131      fmt.Printf("Player %d  Score %d\n", r.player, r.score)
 132    }
 133  }