I don't think there's much trouble at all fixing the toy example by extending the message type to allow communication of the additional conditions, and I think my changes are better than the alternative of using a mutex. Have I overlooked something?
Assuming the number of players are set up front, and players can only play or leave, not join. If the expectation is that players can come and go freely and the game ends some time after all players have left, I believe this pattern can still be used with minor adjustment
(please overlook the pseudo code adjustments, I'm writing on my phone - I believe this translates reasonably into compilable Go code):
  type Message struct {
    exit bool
    score    int
    reply chan bool
  }
  type Game struct {
    bestScore int
    players int // > 0
    messages    chan Message
  }
  func (g *Game) run() {
    for message := range g.messages {
      if message.exit {
        g.players = g.players - 1;
        if g.players == 0 {
          return
        }
        continue
      }
  
      if g.bestScore < 100 && g.bestScore < message.score {
        g.bestScore = message.score
      }
      acceptingScores := g.bestScore < 100
      message.reply <- acceptingScores
    }
  }
  func (g *Game) HandlePlayer(p Player) error {
    for {
      score, err := p.NextScore()
      if err != nil {
        g.messages <- { exit: true
      }
      return err
    }
    g.messages <- { score, reply }
    if not <- reply {
       g.messages <- { exit: true }
       return nil
      }
    }
  }