From ce051f233529f07ac837e34f298796cff4037111 Mon Sep 17 00:00:00 2001 From: Claudio Nave Date: Wed, 20 Nov 2019 07:30:28 +0100 Subject: [PATCH] Divisione in unit file separati --- .../scala/it/nave/caesarcypher/Main.scala | 92 +------------------ .../nave/caesarcypher/actor/CharActor.scala | 50 ++++++++++ .../it/nave/caesarcypher/actor/Guardian.scala | 79 ++++++++++++++++ 3 files changed, 133 insertions(+), 88 deletions(-) create mode 100644 src/main/scala/it/nave/caesarcypher/actor/CharActor.scala create mode 100644 src/main/scala/it/nave/caesarcypher/actor/Guardian.scala diff --git a/src/main/scala/it/nave/caesarcypher/Main.scala b/src/main/scala/it/nave/caesarcypher/Main.scala index a25ecd4..71d1cde 100644 --- a/src/main/scala/it/nave/caesarcypher/Main.scala +++ b/src/main/scala/it/nave/caesarcypher/Main.scala @@ -19,10 +19,9 @@ package it.nave.caesarcypher -import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.{ActorRef, ActorSystem, Behavior} -import it.nave.caesarcypher.CharActor.CharShift -import it.nave.caesarcypher.Guardian.{GuardianMessage, InputString, ResultChar} +import akka.actor.typed.ActorSystem +import it.nave.caesarcypher.actor.Guardian +import it.nave.caesarcypher.actor.Guardian.InputString import scala.io.StdIn @@ -36,90 +35,7 @@ object Main extends App { val inputStr = StdIn.readLine("Insert a string to elaborate: ") ActorSystem(Guardian(ENCRYPT_CHOICE == response), "GuardianActor") ! InputString(inputStr) } else { - println(s""" "${response}" is not a valid choice """.trim) // https://stackoverflow.com/questions/21086263/how-to-insert-double-quotes-into-string-with-interpolation-in-scala + println(s""" "${response}" is not a valid choice """.trim) } } - -object Guardian { - - sealed trait GuardianMessage - - final case class InputString(str: String) extends GuardianMessage - - final case class ResultChar(char: Char, index: Int) extends GuardianMessage - - private val ALPHABETS = List("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "0123456789") - private val SHIFT = 3 - - def apply(encrypt: Boolean): Behavior[GuardianMessage] = Behaviors.setup { context => - context.log.info(s"Guardian actor started in ${if (encrypt) "encrypt" else "decrypt"} mode") - context.log.info(s"Setting up alphabets $ALPHABETS") - val CHAR_ACTORS = ALPHABETS - .flatten - .map(char => char -> context.spawn(CharActor(char), s"CharActor-$char")) - .toMap - context.log.debug("Map of char actors: {}", CHAR_ACTORS) - for (entry <- CHAR_ACTORS) { - ALPHABETS - .find(_.contains(entry._1)) - .map(s => if (encrypt) s else s.reverse) - .map(s => s -> s.indexOf(entry._1)) - .filter(_._2 != -1) - .map(tuple => tuple copy (_2 = (tuple._2 + 1) % tuple._1.length)) - .map(tuple => tuple._1.charAt(tuple._2)) - .foreach(c => entry._2 ! CharActor.LinkCharActor(CHAR_ACTORS(c), context.self)) - } - Behaviors.receiveMessage { - case InputString(str) => - context.log.info("Received string \"{}\"", str) - val (knownChars, unknownChars) = str - .zipWithIndex - .partition(tuple => ALPHABETS.exists(_.contains(tuple._1))) - knownChars.foreach(tuple => CHAR_ACTORS(tuple._1) ! CharShift(SHIFT, tuple._2)) - unknownChars.foreach(tuple => context.self ! ResultChar(tuple._1, tuple._2)) - Guardian(str.length - 1, List.empty) - } - } - - def apply(count: Int, listOfChars: List[(Int, Char)]): Behavior[GuardianMessage] = Behaviors.receive { (context, message) => - context.log.info("Guardian actor: received message {}", message) - context.log.debug("Map of chars: {}", listOfChars) - context.log.debug("Count: {}", count) - message match { - case ResultChar(char, index) if count > 0 => - Guardian(count - 1, index -> char :: listOfChars) - case ResultChar(char, index) if count == 0 => - val outputStr = (index -> char :: listOfChars).sortBy(_._1).map(_._2).mkString - println(s"Output string: $outputStr") - Behaviors.stopped - } - } - -} - -object CharActor { - - sealed trait CharMessage - - final case class CharShift(shift: Int, index: Int) extends CharMessage - - final case class LinkCharActor(nextActorChar: ActorRef[CharMessage], replyTo: ActorRef[GuardianMessage]) extends CharMessage - - def apply(char: Char, nextActorChar: ActorRef[CharMessage], replyTo: ActorRef[GuardianMessage]): Behavior[CharMessage] = Behaviors.receive { (context, message) => - context.log.info("Actor of char {}: received message {}", char, message) - message match { - case CharShift(shift, index) if shift > 0 => nextActorChar ! CharShift(shift - 1, index) - case CharShift(shift, index) if shift == 0 => replyTo ! ResultChar(char, index) - } - Behaviors.same - } - - def apply(char: Char): Behavior[CharMessage] = Behaviors.receive { (context, message) => - context.log.debug("Actor of char {}: received message {}", char, message) - message match { - case LinkCharActor(nextActorChar, replyTo) => CharActor(char, nextActorChar, replyTo) - } - } - -} \ No newline at end of file diff --git a/src/main/scala/it/nave/caesarcypher/actor/CharActor.scala b/src/main/scala/it/nave/caesarcypher/actor/CharActor.scala new file mode 100644 index 0000000..db28d11 --- /dev/null +++ b/src/main/scala/it/nave/caesarcypher/actor/CharActor.scala @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Claudio Nave + * + * This file is part of CaesarCypher. + * + * CaesarCypher is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * CaesarCypher is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package it.nave.caesarcypher.actor + +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.{ActorRef, Behavior} +import it.nave.caesarcypher.actor.Guardian.{GuardianMessage, ResultChar} + +object CharActor { + + trait CharMessage + + final case class CharShift(shift: Int, index: Int) extends CharMessage + + final case class LinkCharActor(nextActorChar: ActorRef[CharMessage], replyTo: ActorRef[GuardianMessage]) extends CharMessage + + def apply(char: Char, nextActorChar: ActorRef[CharMessage], replyTo: ActorRef[GuardianMessage]): Behavior[CharMessage] = Behaviors.receive { (context, message) => + context.log.info("Actor of char {}: received message {}", char, message) + message match { + case CharShift(shift, index) if shift > 0 => nextActorChar ! CharShift(shift - 1, index) + case CharShift(shift, index) if shift == 0 => replyTo ! ResultChar(char, index) + } + Behaviors.same + } + + def apply(char: Char): Behavior[CharMessage] = Behaviors.receive { (context, message) => + context.log.debug("Actor of char {}: received message {}", char, message) + message match { + case LinkCharActor(nextActorChar, replyTo) => CharActor(char, nextActorChar, replyTo) + } + } + +} diff --git a/src/main/scala/it/nave/caesarcypher/actor/Guardian.scala b/src/main/scala/it/nave/caesarcypher/actor/Guardian.scala new file mode 100644 index 0000000..4ad4dd3 --- /dev/null +++ b/src/main/scala/it/nave/caesarcypher/actor/Guardian.scala @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 Claudio Nave + * + * This file is part of CaesarCypher. + * + * CaesarCypher is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * CaesarCypher is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package it.nave.caesarcypher.actor + +import akka.actor.typed.Behavior +import akka.actor.typed.scaladsl.Behaviors +import it.nave.caesarcypher.actor.CharActor.CharShift + +object Guardian { + + trait GuardianMessage + + final case class InputString(str: String) extends GuardianMessage + + final case class ResultChar(char: Char, index: Int) extends GuardianMessage + + private val ALPHABETS = List("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "0123456789") + private val SHIFT = 3 + + def apply(encrypt: Boolean): Behavior[GuardianMessage] = Behaviors.setup { context => + context.log.info(s"Guardian actor started in ${if (encrypt) "encrypt" else "decrypt"} mode") + context.log.info(s"Setting up alphabets $ALPHABETS") + val CHAR_ACTORS = ALPHABETS + .flatten + .map(char => char -> context.spawn(CharActor(char), s"CharActor-$char")) + .toMap + context.log.debug("Map of char actors: {}", CHAR_ACTORS) + for (entry <- CHAR_ACTORS) { + ALPHABETS + .find(_.contains(entry._1)) + .map(s => if (encrypt) s else s.reverse) + .map(s => s -> s.indexOf(entry._1)) + .filter(_._2 != -1) + .map(tuple => tuple copy (_2 = (tuple._2 + 1) % tuple._1.length)) + .map(tuple => tuple._1.charAt(tuple._2)) + .foreach(c => entry._2 ! CharActor.LinkCharActor(CHAR_ACTORS(c), context.self)) + } + Behaviors.receiveMessage { + case InputString(str) => + context.log.info("Received string \"{}\"", str) + val (knownChars, unknownChars) = str.zipWithIndex.partition(tuple => ALPHABETS.exists(_.contains(tuple._1))) + knownChars.foreach(tuple => CHAR_ACTORS(tuple._1) ! CharShift(SHIFT, tuple._2)) + unknownChars.foreach(tuple => context.self ! ResultChar(tuple._1, tuple._2)) + Guardian(str.length - 1, List.empty) + } + } + + def apply(count: Int, listOfChars: List[(Int, Char)]): Behavior[GuardianMessage] = Behaviors.receive { (context, message) => + context.log.info("Guardian actor: received message {}", message) + context.log.debug("Map of chars: {}", listOfChars) + context.log.debug("Count: {}", count) + message match { + case ResultChar(char, index) if count > 0 => + Guardian(count - 1, index -> char :: listOfChars) + case ResultChar(char, index) if count == 0 => + val outputStr = (index -> char :: listOfChars).sortBy(_._1).map(_._2).mkString + println(s"Output string: $outputStr") + Behaviors.stopped + } + } + +}