Skip to content

Commit

Permalink
Merge pull request #14 from jetbrains-academy/add-more-theory
Browse files Browse the repository at this point in the history
Add more theory to the first project
  • Loading branch information
nbirillo authored Sep 8, 2023
2 parents c9c9960 + b1d18db commit 75a7bfe
Show file tree
Hide file tree
Showing 1,126 changed files with 23,171 additions and 213 deletions.
5 changes: 4 additions & 1 deletion .courseignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
README.md
backToTheFutureFrontend
duckShopFrontend
oldSchoolFrontend
kotlin-js-store
17 changes: 3 additions & 14 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.util.*

group = "jetbrains.kotlin.course"
version = "0.0.1-SNAPSHOT"
Expand All @@ -9,27 +8,17 @@ fun properties(key: String) = project.findProperty(key).toString()
@Suppress("DSL_SCOPE_VIOLATION") // "libs" produces a false-positive warning, see https://youtrack.jetbrains.com/issue/KTIJ-19369
plugins {
java
val kotlinVersion = "1.7.10"
val kotlinVersion = "1.9.0"
id("org.jetbrains.kotlin.jvm") version kotlinVersion apply false
id("org.jetbrains.kotlin.multiplatform") version kotlinVersion apply false
id("org.springframework.boot") version "2.7.3" apply false
id("io.spring.dependency-management") version "1.0.13.RELEASE" apply false
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion apply false
id("io.gitlab.arturbosch.detekt") version "1.21.0"
id("io.gitlab.arturbosch.detekt") version "1.23.1"

id("org.siouan.frontend-jdk11") version "6.0.0"
}

fun printOutput(output: Any): Task {
return tasks.create("printOutput") {
println("#educational_plugin_check(er_version 1")
val lines = output.toString().split("(?<=\n)|(?=\n)")
for (line in lines) {
println("#educational_plugin$line")
}
}
}

val detektReportMerge by tasks.registering(io.gitlab.arturbosch.detekt.report.ReportMergeTask::class) {
output.set(rootProject.buildDir.resolve("reports/detekt/merge.sarif"))
}
Expand Down Expand Up @@ -75,7 +64,7 @@ configure(subprojects.filter { it.name != "common" && frontendSuffix !in it.name
tasks.getByPath("detekt").onlyIf { project.hasProperty("runDetekt") }

dependencies {
implementation("org.jetbrains.academy.test.system:kotlin-test-system:1.0.4")
implementation("org.jetbrains.academy.test.system:core:2.0.6")
}

val jvmVersion = "11"
Expand Down
2 changes: 1 addition & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
val kotlinVersion = "1.7.10"
val kotlinVersion = "1.9.0"
kotlin("multiplatform") version kotlinVersion
}

Expand Down
14 changes: 6 additions & 8 deletions course-info.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
type: marketplace
title: "Kotlin Onboarding: Collections and co."
title: "Kotlin Onboarding: Collections"
language: English
summary: TODO
vendor:
name: JetBrains
email: support@jetbrains.com
url: https://www.jetbrains.com/
summary: |-
TODO
programming_language: Kotlin
content:
- duckShopServer
- oldSchoolServer
- duckShopServer
environment_settings:
jvm_language_level: JDK_17
4 changes: 2 additions & 2 deletions duckShopFrontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
margin-bottom: 1vmin;
}
.App-button-start:hover {
opacity: 85%;
opacity: 0.85;
}

.App-teams-button-back {
Expand Down Expand Up @@ -311,7 +311,7 @@

.App-unclickable-button {
pointer-events: none;
opacity: 40%;
opacity: 0.4;
}

.App-button-back {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.jetbrains.kotlin.course.duck.shop

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class DuckShopApplication

@Suppress("SpreadOperator")
fun main(args: Array<String>) {
runApplication<DuckShopApplication>(*args)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.jetbrains.kotlin.course.duck.shop.duck

enum class Duck(
val customName: String? = null,
val hasKotlinAttribute: Boolean = false,
val accessories: List<Accessory> = emptyList(),
) {
Alex(accessories = listOf(Accessory.Monocle, Accessory.Hat)),
Daniel(hasKotlinAttribute = true, accessories = listOf(Accessory.Flag)),
Dorian(accessories = listOf(Accessory.Crown)),
Jack(accessories = listOf(Accessory.PirateEyePatch)),
Kristian(accessories = listOf(Accessory.Tie)),
Leo(accessories = listOf(Accessory.Glasses)),
MrPink("Mr. Pink", accessories = listOf(Accessory.Medal)),
Oliver,
Piter(accessories = listOf(Accessory.Hat, Accessory.Pin)),
Vanessa(hasKotlinAttribute = true, accessories = listOf(Accessory.TShirt))
;
}

enum class Accessory(val price: Int = 0) {
Hat(75),
Monocle(90),
Flag(30),
Crown(100),
PirateEyePatch(15),
Tie(25),
Glasses(110),
Medal(18),
Pin(6),
TShirt(45)
;
}

fun generateRandomDuck() = Duck.entries.random()

fun Duck.getDescription() = this.customName ?: this.name
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.jetbrains.kotlin.course.duck.shop.functions.action

import duck.shop.JsDuck
import org.jetbrains.kotlin.course.duck.shop.duck.getDescription
import org.jetbrains.kotlin.course.duck.shop.functions.common.Body
import org.jetbrains.kotlin.course.duck.shop.utils.GameMode
import org.jetbrains.kotlin.course.duck.shop.utils.toAppBody
import org.jetbrains.kotlin.course.duck.shop.utils.toJsDuck
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/functions/")
class GameActionFunctionsResource(val service: GameActionFunctionsService) {
@CrossOrigin
@PostMapping("/shuffle")
fun shuffleDucks(@RequestBody body: Body): List<JsDuck> = with(service) {
val appBody = body.toAppBody()
appBody.ducks.shuffleDucks().map { it.toJsDuck(appBody.mode) }
}

@CrossOrigin
@PostMapping("/sort")
fun sortDucks(@RequestBody body: Body): List<JsDuck> = with(service) {
val appBody = body.toAppBody()
appBody.ducks.sortDucks().map { it.toJsDuck(appBody.mode) }
}

@CrossOrigin
@PostMapping("/filter")
fun filterDucks(@RequestBody body: Body): List<JsDuck> = with(service) {
val appBody = body.toAppBody()
val ducks = when(appBody.mode) {
GameMode.List, GameMode.Set -> appBody.ducks.deleteDucksWithoutKotlinStuff()
GameMode.Map -> appBody.ducks.associateWith { it.getDescription() }.deleteDucksWithoutKotlinStuff().keys
}
ducks.map { it.toJsDuck(appBody.mode) }
}

@CrossOrigin
@PostMapping("/partition")
fun partitionDucks(@RequestBody body: Body): List<List<JsDuck>> = with(service) {
val appBody = body.toAppBody()
val (withKotlin, withoutKotlin) = appBody.ducks.divideDucksIntoKotlinAndNonKotlin()
listOf(withKotlin, withoutKotlin).map { it.map { d -> d.toJsDuck(appBody.mode) } }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.jetbrains.kotlin.course.duck.shop.functions.action

import org.jetbrains.kotlin.course.duck.shop.duck.Duck
import org.springframework.stereotype.Service

@Service
class GameActionFunctionsService {

fun List<Duck>.shuffleDucks(): List<Duck> = TODO("Not implemented yet")

fun List<Duck>.sortDucks(): List<Duck> = TODO("Not implemented yet")

fun Collection<Duck>.deleteDucksWithoutKotlinStuff(): Collection<Duck> = TODO("Not implemented yet")

fun Map<Duck, String>.deleteDucksWithoutKotlinStuff(): Map<Duck, String> = TODO("Not implemented yet")

fun Collection<Duck>.divideDucksIntoKotlinAndNonKotlin(): Pair<Collection<Duck>, Collection<Duck>> = TODO("Not implemented yet")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.jetbrains.kotlin.course.duck.shop.functions.change

import duck.shop.JsDuck
import org.jetbrains.kotlin.course.duck.shop.duck.getDescription
import org.jetbrains.kotlin.course.duck.shop.functions.common.Body
import org.jetbrains.kotlin.course.duck.shop.utils.GameMode
import org.jetbrains.kotlin.course.duck.shop.utils.toAppBody
import org.jetbrains.kotlin.course.duck.shop.utils.toJsDuck
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/functions/")
class GameChangeFunctionsResource(val service: GameChangeFunctionsService) {
@CrossOrigin
@PostMapping("/add")
fun addDuck(@RequestBody body: Body): JsDuck = with(service) {
val appBody = body.toAppBody()
val newDuck = when(appBody.mode) {
GameMode.List -> appBody.ducks.toMutableList().addRandomDuck()
GameMode.Set -> appBody.ducks.toMutableSet().addRandomDuck()
GameMode.Map -> appBody.ducks.associateWith { it.getDescription() }.toMutableMap().addRandomDuck().first
}
newDuck.toJsDuck(appBody.mode)
}

@CrossOrigin
@PostMapping("/remove")
fun removeDuck(@RequestBody body: Body): List<JsDuck> = with(service) {
val appBody = body.toAppBody()
val ducks = when(appBody.mode) {
GameMode.List -> appBody.ducks.removeRandomDuck()
GameMode.Set -> appBody.ducks.toSet().removeRandomDuck()
GameMode.Map -> appBody.ducks.associateWith { it.getDescription() }.removeRandomDuck().keys
}
ducks.map { it.toJsDuck(appBody.mode) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.jetbrains.kotlin.course.duck.shop.functions.change

import org.jetbrains.kotlin.course.duck.shop.duck.Duck
import org.springframework.stereotype.Service

@Service
class GameChangeFunctionsService {
fun List<Duck>.addRandomDuck(): Duck = TODO("Not implemented yet")
fun Set<Duck>.addRandomDuck(): Duck = TODO("Not implemented yet")

fun MutableMap<Duck, String>.addRandomDuck(): Pair<Duck, String> = TODO("Not implemented yet")

fun List<Duck>.removeRandomDuck(): List<Duck> = TODO("Not implemented yet")

fun Set<Duck>.removeRandomDuck(): Set<Duck> = TODO("Not implemented yet")

fun Map<Duck, String>.removeRandomDuck(): Map<Duck, String> = TODO("Not implemented yet")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.jetbrains.kotlin.course.duck.shop.functions.common

// We can not use a typealias here because the Spring framework can not parse it
class DuckNames : ArrayList<String>()
class Body (
val ducks: DuckNames,
val mode: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.jetbrains.kotlin.course.duck.shop.mode

import duck.shop.JsDuck
import org.jetbrains.kotlin.course.duck.shop.utils.GameMode
import org.jetbrains.kotlin.course.duck.shop.utils.toJsDuck
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/api/mode/")
class CardResource(val service: GameModeService) {
@CrossOrigin
@GetMapping("/list")
fun generateListOfCharacters(): List<JsDuck> =
service.generateListOfDucks().map { it.toJsDuck(GameMode.List) }

@CrossOrigin
@GetMapping("/set")
fun generateSetOfCharacters(): List<JsDuck> = service.generateSetOfDucks()
.map { it.toJsDuck(GameMode.Set) }

@CrossOrigin
@GetMapping("/map")
fun generateMapOfCharacters(): List<JsDuck> = service.generateMapOfDucks()
.map { it.key.toJsDuck(GameMode.Map) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.jetbrains.kotlin.course.duck.shop.mode

import org.jetbrains.kotlin.course.duck.shop.duck.Duck
import org.jetbrains.kotlin.course.duck.shop.duck.generateRandomDuck
import org.jetbrains.kotlin.course.duck.shop.duck.getDescription
import org.jetbrains.kotlin.course.duck.shop.utils.MAX_NUMBER_OF_DUCKS
import org.springframework.stereotype.Service

@Service
class GameModeService {
// You could reuse the same approach with the shuffled function here,
// but this way demonstrates different approaches to work with collections
fun generateListOfDucks() = List(MAX_NUMBER_OF_DUCKS) { generateRandomDuck() }

fun generateSetOfDucks() = getRandomDucks().toSet()

// It is better to move common code into a separated function
private fun getRandomDucks() = Duck.entries.toList().shuffled().take(MAX_NUMBER_OF_DUCKS)

fun generateMapOfDucks() = getRandomDucks().associateWith { it.getDescription() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.jetbrains.kotlin.course.duck.shop.utils

import duck.shop.JsDuck
import org.jetbrains.kotlin.course.duck.shop.duck.Duck
import org.jetbrains.kotlin.course.duck.shop.functions.common.Body

fun String.toDuck() = Duck.entries.find { it.name == this || it.customName == this } ?: error("Can not find the duck $this")

fun String.toGameMode() = GameMode.valueOf(this)

fun Body.toAppBody() = AppBody(
ducks = this.ducks.map { it.toDuck() },
mode = this.mode.toGameMode()
)

fun Duck.getJsDescription(mode: GameMode) = when(mode) {
GameMode.Map -> this.customName ?: this.name
else -> null
}

fun Duck.toJsDuck(mode: GameMode) = JsDuck(this.customName ?: this.name, hasKotlinAttribute = this.hasKotlinAttribute, description = this.getJsDescription(mode))
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.jetbrains.kotlin.course.duck.shop.utils

import org.jetbrains.kotlin.course.duck.shop.duck.Duck

enum class GameMode(val key: String) {
List("list"),
Set("set"),
Map("map"),
;
}

data class AppBody(
val ducks: List<Duck>,
val mode: GameMode
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.jetbrains.kotlin.course.duck.shop.utils

const val MAX_NUMBER_OF_DUCKS = 6
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"main.css": "/static/css/main.a4583d36.chunk.css",
"main.js": "/static/js/main.bf41c0d3.chunk.js",
"main.js.map": "/static/js/main.bf41c0d3.chunk.js.map",
"static/js/1.5bff5668.chunk.js": "/static/js/1.5bff5668.chunk.js",
"static/js/1.5bff5668.chunk.js.map": "/static/js/1.5bff5668.chunk.js.map",
"static/js/2.95861944.chunk.js": "/static/js/2.95861944.chunk.js",
"static/js/2.95861944.chunk.js.map": "/static/js/2.95861944.chunk.js.map",
"runtime~main.js": "/static/js/runtime~main.cf32845b.js",
"runtime~main.js.map": "/static/js/runtime~main.cf32845b.js.map",
"static/media/logo.svg": "/static/media/logo.59194e54.svg",
"static/media/App.css": "/static/media/partition.35c2762b.svg",
"static/css/main.a4583d36.chunk.css.map": "/static/css/main.a4583d36.chunk.css.map",
"index.html": "/index.html",
"precache-manifest.1c5b37c8d31a391daf685e13faf741c5.js": "/precache-manifest.1c5b37c8d31a391daf685e13faf741c5.js",
"service-worker.js": "/service-worker.js"
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;300;900&display=swap" rel="stylesheet"><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Duck shop</title><link href="/static/css/main.a4583d36.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(c){function e(e){for(var t,r,n=e[0],o=e[1],u=e[2],i=0,a=[];i<n.length;i++)r=n[i],f[r]&&a.push(f[r][0]),f[r]=0;for(t in o)Object.prototype.hasOwnProperty.call(o,t)&&(c[t]=o[t]);for(d&&d(e);a.length;)a.shift()();return p.push.apply(p,u||[]),l()}function l(){for(var e,t=0;t<p.length;t++){for(var r=p[t],n=!0,o=1;o<r.length;o++){var u=r[o];0!==f[u]&&(n=!1)}n&&(p.splice(t--,1),e=s(s.s=r[0]))}return e}var r={},f={3:0},p=[];function s(e){if(r[e])return r[e].exports;var t=r[e]={i:e,l:!1,exports:{}};return c[e].call(t.exports,t,t.exports,s),t.l=!0,t.exports}s.e=function(u){var e=[],r=f[u];if(0!==r)if(r)e.push(r[2]);else{var t=new Promise(function(e,t){r=f[u]=[e,t]});e.push(r[2]=t);var n,o=document.getElementsByTagName("head")[0],i=document.createElement("script");i.charset="utf-8",i.timeout=120,s.nc&&i.setAttribute("nonce",s.nc),i.src=s.p+"static/js/"+({}[u]||u)+"."+{1:"5bff5668"}[u]+".chunk.js",n=function(e){i.onerror=i.onload=null,clearTimeout(a);var t=f[u];if(0!==t){if(t){var r=e&&("load"===e.type?"missing":e.type),n=e&&e.target&&e.target.src,o=new Error("Loading chunk "+u+" failed.\n("+r+": "+n+")");o.type=r,o.request=n,t[1](o)}f[u]=void 0}};var a=setTimeout(function(){n({type:"timeout",target:i})},12e4);i.onerror=i.onload=n,o.appendChild(i)}return Promise.all(e)},s.m=c,s.c=r,s.d=function(e,t,r){s.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},s.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)s.d(r,n,function(e){return t[e]}.bind(null,n));return r},s.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return s.d(t,"a",t),t},s.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},s.p="/",s.oe=function(e){throw console.error(e),e};var t=window.webpackJsonp=window.webpackJsonp||[],n=t.push.bind(t);t.push=e,t=t.slice();for(var o=0;o<t.length;o++)e(t[o]);var d=n;l()}([])</script><script src="/static/js/2.95861944.chunk.js"></script><script src="/static/js/main.bf41c0d3.chunk.js"></script></body></html>
Loading

0 comments on commit 75a7bfe

Please sign in to comment.