Шаг 130.
Основы Kotlin.
Ассоциативные массивы. Изменение значений в ассоциативном массиве

    На этом шаге мы рассмотрим особенности выполнения этой операции и подведем некоторые итоги.

    Чтобы завершить покупку, мы должны вычесть цену товара в меню из содержимого кошелька посетителя. Ассоциативный массив patronGold связывает значение баланса денег с ключом - именем посетителя. Измените баланс посетителя, записав новое значение после завершения покупки.

    Функции performPurchase() и displayBalance() связаны с кошельком героя и подробно показывают, сколько монет там находится. Впрочем, нам эти подробности сейчас не понадобятся. Удалите их, а также переменные playerGold и playerSilver, применяемые только в этих функциях. Затем объявите новую функцию performPurchase(), чтобы обрабатывать покупки посетителей. (Вы объявите новую функцию для отображения состояния баланса посетителей далее.)

    Чтобы обновить значение после завершения покупки, функция получит его из ассоциативного массива patronGold по имени посетителя. Вызовите новую функцию performPurchase() после того, как посетитель поговорит с трактирщиком Taernyl по поводу своего заказа (не забудьте раскомментировать вызов).

import kotlin.math.roundToInt
import java.io.File

const val TAVERN_NAME = "Taernyl's Folly"

val patronList = mutableListOf("Eli", "Mordoc", "Sophie")
val menuList = File("data/tavern-menu-items.txt")
        .readText()
        .split("\n")
val patronGold = mapOf("Eli" to 10.5, "Mordoc" to 8.0, "Sophie" to 5.5)
.   .   .   .
private fun placeOrder(patronName: String, menuData: String) {
    val indexOfApostrophe = TAVERN_NAME.indexOf('\'')
    val tavernMaster = TAVERN_NAME.substring(0 until indexOfApostrophe)
    println("$patronName speaks with $tavernMaster about their order.")
    val (type, name, price) = menuData.split(',')
    val message = "$patronName buys a $name ($type) for $price."
    println(message)

    performPurchase(price.toDouble(), patronName)

    val phrase = if (name == "Dragon's Breath") {
        "$patronName exclaims: ${toDragonSpeak("Ah, delicious $name!")}"
    } else {
        "$patronName says: Thanks for the $name."
    }
    println(phrase)
}

fun performPurchase(price: Double, patronName: String) {
    val totalPurse = patronGold.getValue(patronName)
    patronGold[patronName] = totalPurse - price
}
Файл с проектом можно взять здесь.


Рис.1. Обновление значений в patronGold() (Tavern.kt)

    Запустите Tavern.kt. Вы увидите произвольные заказы среди строк:

The tavern master says: Eli's in the back playing cards.
The tavern master says: Yea, they're seated by the stew kettle.
Mordoc Fernsworth speaks with Taernyl about their order.
Mordoc Fernsworth buys a goblet of la croix (meal) for 1.22.
Mordoc Fernsworth says: Thanks for the goblet of la croix.
Eli Baggins speaks with Taernyl about their order.
Eli Baggins buys a goblet of la croix (meal) for 1.22.
Eli Baggins says: Thanks for the goblet of la croix.
.   .   .   .   


Рис.2. Результат работы приложения

    Вы обновили баланс денег у посетителей, и осталась только одна задача - вывести отчет после покупки. Это можно реализовать, выполнив обход ассоциативного массива посредством функции forEach().

    Добавьте в Tavern.kt новую функцию под названием displayPatronBalances(), которая перебирает элементы ассоциативного массива и выводит баланс в золотых монетах (с округлением до второго десятичного знака) для каждого посетителя. Вызовите ее в конце функции main().

.   .   .   .
fun main() {
    .    .   .   .
    var orderCount = 0
    while (orderCount <= 9) {
        placeOrder(uniquePatrons.shuffled().first(),
                menuList.shuffled().first())
        orderCount++
    }
    displayPatronBalances()
}
.   .   .   .
private fun displayPatronBalances() {
    patronGold.forEach { patron, balance ->
        println("$patron, balance: ${"%.2f".format(balance)}")
    }
}
Файл с проектом можно взять здесь.


Рис.3. Отображение балансов посетителей (Tavern.kt)

    Запускайте Tavern.kt, устраивайтесь поудобнее и смотрите, как посетители Taenyl's Folly ведут беседу с трактирщиком, делают заказы и оплачивают их:

The tavern master says: Eli's in the back playing cards.
The tavern master says: Yea, they're seated by the stew kettle.
Mordoc Baggins speaks with Taernyl about their order.
Mordoc Baggins buys a shirley temple (elixir) for 4.12.
Mordoc Baggins says: Thanks for the shirley temple.
Mordoc Fernsworth speaks with Taernyl about their order.
Mordoc Fernsworth buys a pickled camel hump (desert dessert) for 7.33.
Mordoc Fernsworth says: Thanks for the pickled camel hump.
Sophie Baggins speaks with Taernyl about their order.
Sophie Baggins buys a goblet of la croix (meal) for 1.22.
Sophie Baggins says: Thanks for the goblet of la croix.
Eli Baggins speaks with Taernyl about their order.
Eli Baggins buys a pickled camel hump (desert dessert) for 7.33.
Eli Baggins says: Thanks for the pickled camel hump.
Mordoc Baggins speaks with Taernyl about their order.
Mordoc Baggins buys a goblet of la croix (meal) for 1.22.
Mordoc Baggins says: Thanks for the goblet of la croix.
Mordoc Baggins speaks with Taernyl about their order.
Mordoc Baggins buys a shirley temple (elixir) for 4.12.
Mordoc Baggins says: Thanks for the shirley temple.
Eli Ironfoot speaks with Taernyl about their order.
Eli Ironfoot buys a pickled camel hump (desert dessert) for 7.33.
Eli Ironfoot says: Thanks for the pickled camel hump.
Mordoc Fernsworth speaks with Taernyl about their order.
Mordoc Fernsworth buys a pickled camel hump (desert dessert) for 7.33.
Mordoc Fernsworth says: Thanks for the pickled camel hump.
Sophie Baggins speaks with Taernyl about their order.
Sophie Baggins buys a shirley temple (elixir) for 4.12.
Sophie Baggins says: Thanks for the shirley temple.
Eli Ironfoot speaks with Taernyl about their order.
Eli Ironfoot buys a shirley temple (elixir) for 4.12.
Eli Ironfoot says: Thanks for the shirley temple.
Mordoc Baggins, balance: -3,46
Mordoc Fernsworth, balance: -8,66
Eli Fernsworth, balance: 6,00
Eli Baggins, balance: -1,33
Eli Ironfoot, balance: -5,45
Sophie Baggins, balance: 0,66
Sophie Fernsworth, balance: 6,00


Рис.4. Результат работы приложения

    В последних шагах вы научились работать в Kotlin с разными типами коллекций: со списками, множествами и ассоциативными массивами. Таблица 1 сравнивает их возможности.

Таблица 1. Резюме коллекций Kotlin
Тип коллекции Упорядоченная? Уникальные значения? Хранит Поддерживает деструктуризацию?
Список (List) Да Нет Элементы Да
Множество (Set) Нет Да Элементы Нет
Ассоциативный массив (Map) Нет Ключи Пары "ключ-значение" Нет

    Так как коллекции по умолчанию доступны только для чтения, вам следует создать изменяемую коллекцию (или преобразовать в изменяемую версию), чтобы изменять ее содержимое. Так вы предотвратите возможность случайного добавления или удаления элементов.

    В следующих шагах вы научитесь применять принципы объектно-ориентированного программирования на примере объявления своего собственного класса в NyetHack.

    На следующем шаге мы приведем задание для самостоятельного решения.




Предыдущий шаг Содержание Следующий шаг