Go Fish/Kotlin

From Rosetta Code
Revision as of 00:02, 18 October 2017 by PureFox (talk | contribs) (Added Kotlin page for Go Fish task)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

<lang scala>// version 1.1.51

import java.util.Random

const val FACES = "23456789tjqka" const val SUITS = "cdhs"

enum class Turn { user, comp }

class Card(val face: Char, val suit: Char) : Comparable<Card> {

   private val value = FACES.indexOf(face) * 4 + SUITS.indexOf(suit)
   override fun compareTo(other: Card) = this.value.compareTo(other.value)
   override fun toString() = "$face$suit"

}

val r = Random()

val ranks = listOf(

   "twos", "threes", "fours", "fives", "sixes", "sevens", "eights",
   "nines", "tens", "jacks", "queens", "kings", "aces"

)

val deck = mutableListOf<Card>()

val userHand = mutableListOf<Card>() val userBooks = mutableListOf<Char>() val compHand = mutableListOf<Card>() val compBooks = mutableListOf<Char>() val compPrev = mutableListOf<Char>()

var turn = Turn.user // user always starts

fun createDeck() {

   for (suit in SUITS) {
       for (face in FACES) deck.add(Card(face, suit))
   }

}

fun shuffleDeck() {

   val shuffled = mutableListOf<Card>()
   do {
       val card = deck[r.nextInt(52)]
       if (card !in shuffled) shuffled.add(card)
   } while (shuffled.size < 52)
   deck.clear()
   deck.addAll(shuffled)

}

/* Chooses a rank at random provided it hasn't already been chosen

  during the current turn. If all ranks have already been chosen,
  it chooses the first again. */

fun compSelectRankIndex(): Int {

   val choices = compHand.map { it.face }.distinct().filter { it !in compPrev }
   val size = choices.size
   val choice = if (size == 0) compHand[0].face else choices[r.nextInt(size)]
   return FACES.indexOf(choice)

}

val userChoices get() = userHand.map { it.face }.distinct()

fun printHand() = println("Your cards : ${userHand.joinToString(" ")}")

fun printBooks() {

   println("Your books : ${userBooks.joinToString("   ")}")
   println("My books   : ${compBooks.joinToString("   ")}")

}

fun printTurn() =

   println(if (turn == Turn.user) "--- YOUR TURN ---" else "--- MY TURN ---")

fun checkForBooks(hand: MutableList<Card>, books: MutableList<Char>) {

   val newBooks = hand.groupBy { it.face }
                      .filter { it.value.size == 4 }
                      .map { it.key }
   if (newBooks.size > 0) {
       books.addAll(newBooks)
       books.sort()
       for (b in newBooks) {
           for (i in hand.size - 1 downTo 0) {
               if (hand[i].face == b) hand.removeAt(i)
           }
       }
       if (hand.size == 0 && deck.size > 0) {
           val e = deck.removeAt(0)
           if (hand === userHand) println("You drew : $e")
           hand.add(e)
       }
       println("Added ${newBooks.joinToString("   ")} to books")
   }

}

fun showStateOfPlay(showTurn: Boolean = true) {

   println()
   userHand.sort()
   printHand()
   printBooks()
   if (showTurn) printTurn()
   println()

}

fun main(args: Array<String>) {

   // create and shuffle deck and deal cards
   createDeck()
   shuffleDeck()
   for (i in 0..16 step 2) userHand.add(deck[i])
   for (i in 1..17 step 2) compHand.add(deck[i])
   for (i in 0..17) deck.removeAt(0)
   // check if there are any books in initial hands
   checkForBooks(userHand, userBooks)
   checkForBooks(compHand, compBooks)
   showStateOfPlay()
   while (true) {
       while (true) {
           var rank: String
           if (turn == Turn.user) {
               val choices = userChoices
               while (true) {
                   print("Enter the rank you want : ")
                   rank = readLine()!!.toLowerCase()
                   if (rank !in ranks) continue
                   val choice = FACES[ranks.indexOf(rank)]
                   if (choice in choices) break
               }
           }
           else {
               val r = compSelectRankIndex()
               rank = ranks[r]
               println("The rank I want is : $rank")
               compPrev.add(FACES[r])
           }
           val face = FACES[ranks.indexOf(rank)]
           var matches = 0
           if (turn == Turn.user) {
               for (i in compHand.size - 1 downTo 0) {
                   if (compHand[i].face == face) {
                       matches++
                       userHand.add(compHand.removeAt(i))
                   }
               }
               println("Matches : $matches")
               if ((matches == 0 || userHand.size == 0) && deck.size > 0) {
                   val e = deck.removeAt(0)
                   println("You drew : $e")
                   userHand.add(e)
               }
               checkForBooks(userHand, userBooks)
               if (userBooks.size >= 7) {
                   showStateOfPlay(false)
                   println("Congratulations, you've won!")
                   return
               }
           }
           else {
               for (i in userHand.size - 1 downTo 0) {
                   if (userHand[i].face == face) {
                       matches++
                       compHand.add(userHand.removeAt(i))
                   }
               }
               println("Matches: $matches")
               if ((matches == 0 || compHand.size == 0) && deck.size > 0) {
                   val e = deck.removeAt(0)
                   compHand.add(e)
               }
               checkForBooks(compHand, compBooks)
               if (compBooks.size >= 7) {
                   showStateOfPlay(false)
                   println("Commiserations, but I've won!")
                   return
               }
           }
           if (matches > 0) showStateOfPlay() else break
       }
       turn = if (turn == Turn.user || userHand.size == 0) Turn.comp else Turn.user
       if (turn == Turn.comp) compPrev.clear()
       showStateOfPlay()
   }

}</lang>