func process(doneTime time.Time, r io.Reader, a *accounting, resultChan chan result) { defer close(resultChan) tr := newTruckReader(r) in := make(chan *truck) out := make(chan *truck) // Construct the repacker. newRepacker(in, out) // A goroutine to read and send trucks go func() { defer close(in) for { done := time.Now().After(doneTime) t, err := tr.Next() if done || err != nil { if done { fmt.Println("timeout") } if err != nil && err != io.EOF { fmt.Println("truck reading error: ", err) } // Send one more empty truck as a signal that they now // need to send out any stored boxes. a.trucksMu.Lock() a.trucks[idLastTruck] = 0 a.trucksMu.Unlock() in <- &truck{id: idLastTruck} return } a.boxesMu.Lock() for _, p := range t.pallets { for _, b := range p.boxes { a.boxes[b.canon()] = true } } a.boxesMu.Unlock() // Remember how many pallets were in the truck. a.trucksMu.Lock() a.trucks[t.id] = len(t.pallets) a.trucksMu.Unlock() in <- t } }() // Receive the trucks and check them. for t := range out { r := result{} totalUtilization := float64(0) palletCount := 0 // Only correctly packed pallets count for pn, p := range t.pallets { palletCount++ for _, b := range p.boxes { if !a.boxOk(b) { log.Printf("box %v in truck %d was not in the input", b.id, t.id) r.fail = true } } if err := p.IsValid(); err == nil { r.items += p.Items() totalUtilization += p.Utilization() } else { log.Printf("pallet %v in truck %d is not correctly packed: %v", pn, t.id, err) r.fail = true } } // Calculate the profit (or loss!) of pallets. a.trucksMu.Lock() if _, ok := a.trucks[t.id]; ok { r.profit = a.trucks[t.id] - len(t.pallets) } else { log.Printf("truck %v unknown", t.id) r.fail = true } a.trucksMu.Unlock() r.palletUtilization = totalUtilization / float64(palletCount) resultChan <- r } a.boxesMu.Lock() if len(a.boxes) != 0 { log.Printf("%v boxes not seen in the departing trucks", len(a.boxes)) resultChan <- result{fail: true} } a.boxesMu.Unlock() }