【挑戦状】誰が書いたコードか当てまShow!! 〜Kotlin Fest 2025 クイズコンテンツの解説〜

こんにちは。株式会社ヘンリーで開発者をやっているタケハタです。

ヘンリーは去る2025年11月1日に、Kotlin Fest 2025にことりスポンサーとしてスポンサーブースを出展しました。
イベント後に報告のエントリーで書いていたのですが、ブースでコンテンツとしてクイズを出題し、多くの方にチャレンジしていただきました。

そのクイズは「【挑戦状】誰が書いたコードか当てまShow!!」と題し、ヘンリーのエンジニア4人が同じ問題に対してコードを書き、どのコードを誰が書いたか当ててもらうというもので、非常に盛り上がり楽しんでいただくことができました。
そこで今回はそのクイズの紹介と答えの解説を書こうと思います。

正答は下の方に書きますので、この記事を読んでいただいているみなさまもぜひチャレンジしてみてください!

回答者紹介

まずはコードを書いた回答者4名の紹介です(私も回答しています)。
こちらのプロフィールがどのコードを書いたか当てる上でのヒントになります。

コードを書いた4名

VPoTや創業エンジニア、料理長までいてバラエティに飛んだ面々です。

問題

4人が回答した問題は以下です。
上のコメント部分が問題で、書かれている仕様に沿ってsolve関数を実装し、想定実行結果と同じ内容が出力されるようにします。











fun solve(input: String): String {
    
}

fun main() {
    val inputs = listOf(
        
        """
        alice 10
        bob 7
        alice 5
        cara 7
        dave 7
        """.trimIndent(),

        
        """
        taku 30
        haru 20
        ken 25
        haru 15
        ken 10
        """.trimIndent(),

        
        """
        a 5
        b 5
        c 5
        d 1
        e 10
        """.trimIndent()
    )

    for ((i, input) in inputs.withIndex()) {
        println("=== Case ${i + 1} ===")
        println(solve(input))
        println()
    }
}

想定実行結果
=== Case 1 ===
1. alice 15
2. bob 7
2. cara 7
2. dave 7

=== Case 2 ===
1. haru 35
1. ken 35
3. taku 30

=== Case 3 ===
1. e 10
2. a 5
2. b 5
2. c 5

Collection操作が多く必要で、書き方のクセが出やすい問題になっているところがポイントです。

選択肢(4人のエンジニアが書いたコード)

そしてそれぞれのエンジニアが書いたコードが以下のA〜Dの4つになります。

Aの回答

fun solve(input: String): String {
    var prevScore: Int? = null
    var prevRank = 1
    return input.split("\n")
        .map { it.split(" ") }
        .groupBy({ it[0] }, { it[1].toInt() })
        .mapValues { it.value.sum() }
        .toList()
        .sortedWith(compareByDescendingPairString, Int>> { it.second }.thenBy { it.first })
        .mapIndexed { index, (name, score) ->
            val rank = if (prevScore == null || prevScore > score) {
                index + 1
            } else {
                prevRank
            }

            (rank to "$name $score").also {
                prevScore = score
                prevRank = rank
            }
        }.takeWhile { it.first 3 }
        .joinToString("\n") {
            "${it.first}. ${it.second}"
        }
}

Bの回答

fun solve(input: String): String {
    val rankingList = input.lineSequence().map { line ->
        val array = line.split(" ")
        Pair(array[0], array[1])
    }.groupingBy {
        it.first
    }.fold(0) { sum, (_, score) ->
        sum + score.toInt()
    }.toList().sortedWith(
        compareByDescendingPairString, Int>> { it.second }.thenBy { it.first }
    )

    return buildString {
        var rank = 0
        var lastScore = 0
        rankingList.forEachIndexed { index, (name, score) ->
            if (lastScore != score) {
                rank = index + 1
            }
            if (rank > 3) {
                return@forEachIndexed
            }
            appendLine("$rank. $name $score")

            lastScore = score
        }
    }
}

Cの回答

fun solve(input: String): String {
    val scoreMap = buildMapString, Int> {
        input.lineSequence().forEach {
            val (name, score) = it.split(' ', limit = 2)
            set(name, getOrDefault(name, 0) + score.toInt())
        }
    }
    val rankingMap = scoreMap
        .asIterable()
        .sortedWith(compareByDescendingMap.EntryString, Int>> { it.value }.thenBy { it.key })
        .groupBy({ it.value }, { it.key })
    val topScorers = sequenceTripleInt, String, Int>> {
        var rank = 1
        for ((score, names) in rankingMap) {
            val competitionRank = rank 
            for (name in names) {
                yield(Triple(competitionRank, name, score))
                rank++
            }
        }
    }
    return topScorers
        .takeWhile { (rank, _, _) -> rank 3 }
        .joinToString("\n") { (rank, name, score) -> "$rank. $name $score" }
}

Dの回答

import java.util.TreeSet

typealias Name = String
typealias Score = Int

fun solve(input: String): String {
    
    data class Entry(val name: Name, val score: Score)
    data class RankedEntry(val rank: Int, val entry: Entry)

    
    class Ranking : TreeSetEntry>(
        compareByDescendingEntry> { it.score }
            .thenBy { it.name }
    )

    tailrec fun aggregateScores(
        remaining: ListString>,
        scoreMap: HashMap = HashMap()
    ): HashMap {
        if (remaining.isEmpty()) return scoreMap

        val line = remaining.first().trim()
        if (line.isNotBlank()) {
            val (name, scoreStr) = line.split(' ')
            val score = scoreStr.toInt()

            scoreMap[name] = (scoreMap[name] ?: 0) + score

            return aggregateScores(
                remaining.drop(1),
                scoreMap
            )
        }
        return aggregateScores(remaining.drop(1), scoreMap)
    }

    
    val scoreMap = aggregateScores(input.lines())

    
    val ranking = scoreMap
        .map { (name, score) -> Entry(name, score) }
        .toCollection(Ranking())

    
    return ranking
        .foldIndexed(listOf()) { index, acc, entry ->
            
            val rank = if (index > 0 && acc.last().entry.score == entry.score) {
                
                acc.last().rank
            } else {
                
                index + 1
            }
            acc + RankedEntry(rank, entry)
        }
        .takeWhile { it.rank 3 }
        .joinToString("\\n") { "${it.rank}. ${it.entry.name} ${it.entry.score}" }
}

ここまでが問題になります!

誰がどのコードを書いたかわかりましたか?
正答と解説は下の方にありますので、回答を終えた方は下の方へスクロールしてください!

A: Kengo TODA

AはヘンリーのVPoT、VPoEであるKengo TODAが書いたコードでした。
ポイントとしてはすべての処理をメソッドチェーンで書いている点ですね。
「ひとこと」に書かれている「全ては流れであり、流れこそが全てである…」で始まる文章がヒントで、すべてがチェーンされているコードは、まるで流れに身を任せているかのような処理を表現しています。

正解された方からは以下のようコメントをいただきました。

  • 全ては流れであり、流れこそが全てであるって書いてあるから全部メソッドチェーンしてる人だと思った
  • 初手split(“\n”)してるのはJavaっぽいと思ったので、Kotlinを好きって書いてる人とは違うと思った

適切にヒントを読み取って正解されている方も多くいました!

B: タケハタ

Bは私、タケハタが書いたコードでした。
私は一応Kotlinの書籍も過去に出版していて、「ひとこと」にも書いている通り「ワタシ Kotlin チョットデキル」人間として名乗っています。
なのでgroupingByfoldという普通の人がなかなか知らない関数を使用したり、PairのListをforEachIndexedで回す時に(name, score)で扱ったりと、Kotlinの機能をふんだんに使ったコードに仕上げました。

正解された方からは以下のようコメントをいただきました。

  • Pairを(name, score)で扱ってるのはKotlin玄人っぽい感じがした
  • buildStringはKotlin知ってる人っぽい

個人的な想定とは違ったのですが、StringBuilderではなくbuildStringを使うところにKotlinっぽさを感じてわかったという方がかなり多くいました!
やはりKotlin FestではKotlinが好きな方が多く来られていたので、こういった意見も興味深かったです。

C: creasty

Cはヘンリーの創業エンジニアであるcreastyが書いたコードでした。
このコードは正答率も低く、私もポイントがわからなかったのでなにがヒントだったのか後から本人に確認したのですが、なんと「なにも考えてなかった」という答えが返ってきました!
つまりプロフィールにはヒントがなにもなかったのです。どおりで正答率が低いわけですね。

ちなみに正解された方の中には

  • 予測不能って書いてるからこれだと思った

とおっしゃっていた方もいたのですが、その方にはコードからなにか感じる予測不能な要素があったのかもしれません。

D: giiita

Dはヘンリーの料理長であるgiiitaが書いたコードでした。
ポイントとしては「ひとこと」にある「業務コードとしてレビューしてもらう気持ちで実装しました」と書かれている通り、コードに丁寧なコメントが書かれている点ですね。
あとは「好きな言語」にScalaを書いていることもポイントで、正解された方からは

  • tailrec使うの絶対Scalaの人でしょ!

というコメントもいただきました。
このコードは正答率も一番高かったです!

あとはなぜか

  • 「趣味: 土地間取り探し」でわかりました!

とおっしゃっていた方もおり、やはりコードにはエンジニアの様々な一面が表現されるものなのだなと、感動を覚えました。

本記事を読んでいただいたみなさまは、どのコードを誰が書いたかわかったでしょうか?

当日、ブースでこちらのクイズを多くの方が真剣に取り組み、楽しんでいただけました!
かなり難しいクイズになるかと思ったのですが、想像以上に多くの方が正解していて、参加者のみなさまの洞察力に驚きました。
今後もヘンリーでは様々なイベントで、楽しんでいただけるコンテンツを用意していきますので、ブースなどで見かけた際はぜひお立ち寄りください!

最後に告知です。
ヘンリーでは11月25日(火)に、Kotlin Fest 2025の非公式アフターイベントとしてServer-Side Kotlin Night 2025を開催します!

henry.connpass.com

弊社からKotlin Festに登壇したnabeoも含む、計8名の登壇者でお送りするServer-Side Kotlinのイベントです。
当日直前まで申し込み可能ですので、ぜひこちらもご参加いただければと思います!




元の記事を確認する

関連記事