/** * Base classes for students to use for the Checkout line simulation. */ package main import ( "time" "math" "math/rand" "fmt" ) type CheckoutLines struct { lines [] chan Customer completed [] int //the total number of completed items scanned, scaled by their size idleMs [] int //the total number of ms each checkout line was idle, only counting when a customer came afterwards currentIdleMs [] int //the total number of ms each checkout line has been idle currently. exit chan Customer } func NewCheckoutLines(n int, channelSize int, exit chan Customer) CheckoutLines { checkout := CheckoutLines{} checkout.lines = make([] chan Customer, n, n) checkout.completed = make([]int, n, n) checkout.exit = exit checkout.idleMs = make([]int, n, n) checkout.currentIdleMs = make([]int, n, n) for i := 0; i < n; i++ { checkout.lines[i] = make(chan Customer, channelSize) checkout.completed[i] = 0 } return checkout } func (c CheckoutLines) LongestIdle() int { longest := 0 for i :=0; i < len(c.idleMs); i++ { idle := c.idleMs[i] if idle > longest { longest = idle } } return longest } func (c CheckoutLines) AverageIdle() int { total := 0 for i :=0; i < len(c.idleMs); i++ { idle := c.idleMs[i] total += idle } return total / len(c.idleMs) } func (c CheckoutLines) PercentageIdleAverageOfMax() float64 { total := 0 for i :=0; i < len(c.idleMs); i++ { idle := int(math.Max(0.0, float64(c.idleMs[i]+10))) total += idle } maxIdle := math.Max(0.0, float64(c.LongestIdle()+10)) avgIdle := float64(total) / float64(len(c.idleMs)) fmt.Println("idle times: ", c.idleMs) fmt.Println("avgIdle: ", avgIdle, " maxIdle: ", maxIdle) if maxIdle == 0.0 { return 100.0 } else { return float64(100 * total) / float64(len(c.idleMs)) / maxIdle } } func (c *CheckoutLines) Start() { for i :=0; i < len(c.lines); i++ { //each "consumer" thread at the end of the checkout line var j = i go func() { //iterate over each customer for ; true; { //get the next customer if len(c.GetLine(j)) > 0 { customer := <- c.GetLine(j) items := customer.GetItems() //go through their items and scan them for k := 0; k < len(items); k++ { offset := rand.Intn(3) - 1 itemTime := items[k] + offset //scanning takes some time time.Sleep(time.Duration(itemTime * 1000)) c.completed[j] += itemTime / 100 } //the customer exits the store c.exit <- customer c.idleMs[j] += c.currentIdleMs[j] c.currentIdleMs[j] = 0 } else { //idle for one ms c.currentIdleMs[j] += 1 time.Sleep(time.Duration(1000000)) //that's one millisecond } } }() } } func (c CheckoutLines) GetLine(i int) chan Customer { return c.lines[i] } func (c CheckoutLines) GetStats() []int { //return a copy of the completed stats completedCopy := make([]int, len(c.completed), len(c.completed)) for i := 0; i < len(c.completed); i++ { completedCopy[i] = c.completed[i] } return completedCopy } type Customer struct { id int items []int listener CheckoutCoordinator } func NewCustomer(id int, items []int) Customer { customer := Customer{} customer.id = id customer.items = items return customer } func (c Customer) GetItems() []int { return c.items }