package o1game.Server import scala.util.Try import scala.util.Random class Clients(maxClients: Int): private val clients: Array[Option[Client]] = Array.fill(maxClients)(None) /** Adds `client` to this collection of clients. * * @param client the Client to add * @return true if there was room for the client * i.e. fewer clients than `maxClients`, false otherwise */ def addClient(client: Client): Boolean = val i = this.clients.indexOf(None) if i == -1 then false else this.clients(i) = Some(client) true /** Returns all the clients. * * @return an iterable of all the clients */ def allClients: Iterable[Client] = clients.toVector.flatten /** Applies the function `f` to all the clients for its side effects. */ def foreach(f: Client => Any): Unit = this.clients.flatten.foreach(f) /** Executes the function `f` for all clients in a pseudorandom order. */ def inRandomOrder(f: Client => Any): Unit = Random.shuffle(this .clients .flatten) .foreach(f) /** Returns true if the predicate `f` stands for all clients, * false otherwise * * @param f the predicate to check for all clients * @return whether `f` stands for all clients */ def forall(f: Client => Boolean): Boolean = this.clients.flatten.forall(f) /** Gets the names of all the clients stored by this object. * * @return the names of the clients */ def names: Vector[String] = this.clients.flatten.flatMap(_.getName).toVector def isEmpty: Boolean = this.clients.flatten.isEmpty /** Applies the function `f` to all the clients for its side effects * and removes all the clients for which `f([client])` returns false. * This is useful for doing IO with the client and removing clients * with stale sockets. * * @param f the function to apply to all the clients and filter them with */ def removeNonSatisfying(f: Client => Boolean): Unit = for i <- this.clients.indices do this.clients(i) match case Some(c) => if !f(c) then this.clients(i) = None case None => /** Removes clients that have not behaved according to protocol */ def removeNonCompliant(): Unit = this.removeNonSatisfying(_.isIntactProtocolWise) /** Applies the function f to all clients for its side effects. * If the function throws an exception, the client is removed. * Probably a more concise alternative to `removeNonSatisfying`, * but might catch exceptions unintentionally. * * @param f the function to apply for its side effects to each client */ def mapAndRemove(f: Client => Unit): Unit = this.removeNonSatisfying(c => Try(f(c)).isSuccess)