Skip to main content
5 of 7
deleted 25 characters in body
138 Aspen
  • 6.6k
  • 1
  • 4
  • 13

Scala 3, 1492 771 bytes

A port of @Doorknob's Ruby answer in Scala.

Saved 721 bytes thanks to @ceilingcat


Golfed version. Attempt This Online!

object m{def t()=scala.io.StdIn.readLine().trim.replace('j','i').toUpperCase.filter(_.isLetter).toList
def f(t:Array[Array[Char]],c:Char):(Int,Int)={t.zipWithIndex.collectFirst{case(r,i)if r.contains(c)=>(i,r.indexOf(c))}.getOrElse(throw new Exception(s""))}
def main(A:Array[String]):Unit={val k=t().distinct
var F=(k++("ABCDEFGHIKLMNOPQRSTUVWXYZ".filterNot(k.contains))).toArray
val T=Array.tabulate(5,5)((r,c)=>F(r*5+c))
val s=t().foldLeft(List[Char]()){(a,c)=>if(a.nonEmpty&&a.last==c)a:+'X':+c else a:+c}
println(s"${(if(s.size%2<1)s else s:+'X').sliding(2,2).toList.flatMap{p=>val(g,h)=(p(0),p.last)
val(r,c)=f(T,g)
val(q,d)=f(T,h)
if(r==q){List(T(r)((c+1)%5),T(q)((d+1)%5))}else if(c==d){List(T((r+1)%5)(c),T((q+1)%5)(d))}else{List(T(r)(d),T(q)(c))}}.mkString}")}}

Ungolfed version. Attempt This Online!

object Main {
  // Function to transform the input string
  def transform(text: String): List[Char] = {
    // Replace 'j' with 'i', convert to uppercase, remove non-alphabet characters, and split into characters
    text.replace('j', 'i').toUpperCase.filter(_.isLetter).toList
  }

  // Function to generate the Playfair cipher key table
  def generateKeyTable(key: String): Array[Array[Char]] = {
    val keyChars = transform(key).distinct
    val remainingChars = "ABCDEFGHIKLMNOPQRSTUVWXYZ".filterNot(keyChars.contains)
    val combinedChars = (keyChars ++ remainingChars).toArray
    // Create the 5x5 key table
    Array.tabulate(5, 5)((row, col) => combinedChars(row * 5 + col))
  }

  // Function to prepare the message for encryption
  def prepareMessage(msg: String): List[List[Char]] = {
    val msgChars = transform(msg)
    val preparedMsg = msgChars.foldLeft(List[Char]()) { (acc, char) =>
      if (acc.nonEmpty && acc.last == char) acc :+ 'X' :+ char else acc :+ char
    }
    val evenPreparedMsg = if (preparedMsg.size % 2 == 0) preparedMsg else preparedMsg :+ 'X'
    evenPreparedMsg.sliding(2, 2).toList
  }

  // Function to find coordinates of a character in the key table
  def findCoords(tbl: Array[Array[Char]], char: Char): (Int, Int) = {
    tbl.zipWithIndex.collectFirst {
      case (row, rowIndex) if row.contains(char) => (rowIndex, row.indexOf(char))
    }.getOrElse(throw new NoSuchElementException(s"Character $char not found in the table"))
  }

  // Function to encrypt a message using the Playfair cipher
  def encryptMessage(tbl: Array[Array[Char]], msg: List[List[Char]]): String = {
    msg.flatMap { pair =>
      val (c1, c2) = (pair.head, pair.last)
      val (c1Row, c1Col) = findCoords(tbl, c1)
      val (c2Row, c2Col) = findCoords(tbl, c2)
      if (c1Row == c2Row) {
        // Same row
        List(tbl(c1Row)((c1Col + 1) % 5), tbl(c2Row)((c2Col + 1) % 5))
      } else if (c1Col == c2Col) {
        // Same column
        List(tbl((c1Row + 1) % 5)(c1Col), tbl((c2Row + 1) % 5)(c2Col))
      } else {
        // Rectangle swap
        List(tbl(c1Row)(c2Col), tbl(c2Row)(c1Col))
      }
    }.mkString
  }

  def main(args: Array[String]): Unit = {
    val key = scala.io.StdIn.readLine().trim
    val msg = scala.io.StdIn.readLine().trim

    // Generate the key table and prepare the message
    val keyTable = generateKeyTable(key)
    val preparedMsg = prepareMessage(msg)

    // Encrypt the message
    val encryptedMsg = encryptMessage(keyTable, preparedMsg)

    // Output the encrypted message
    println(s"Encrypted Message: $encryptedMsg")
  }
}
138 Aspen
  • 6.6k
  • 1
  • 4
  • 13