No Programming, No Lifeで出ていたので、ちょっとやってみました。
元ネタ。
難易度 激簡単 目標時間10分以内
あなたはこれからトランプを配っていきます。
あなたにはトランプを配る人数、
そしてトランプが渡されます。今回はとても簡単なので例題で説明します。
例)
2つの引数がもらえます。3
"123123123"最初の3はプレイヤーの人数を示しています。
"123123123" はトランプの並びを示しています。あなたはこのなかのトランプを
配っていかなければなりません。この場合、あなたのプログラムは
{"111","222","333"}
を返さなければなりません。
"111"は一番めのプレイヤーが受け取るトランプです。
"222"が2番目のプレイヤーが受け取るトランプです。
"333"が2番目のプレイヤーが受け取るトランプです。ところが、以下のような場合もあります。
すべてのプレイヤーは同じ数だけのトランプを受け取らなければなりません。
ですので4
"123123123"この場合、あなたのプログラムは
{"12","23","31","12"}
を返さなければなりません。
{"123","23","31","12"} は駄目です。
では、以下にもうすこし例をのせます。
例1)
6
"012345012345012345"
Returns: {"000", "111", "222", "333", "444", "555" }例2)
4
"111122223333"
Returns: {"123", "123", "123", "123" }例3)
1
"012345012345012345"
Returns: {"012345012345012345" }例4)
6
"01234"
Returns: {"", "", "", "", "", "" }例5)
2
""
Returns: {"", "" }
クラス名、などは以下のとおりです。
Class: Cards
10分でコーディング|プログラミングに自信があるやつこい!!
Method: deal
Parameters: int, String
Returns: String
Method signature: String deal(int numPlayers, String deck)
Scalaで解いてみました。
Cards.scala
import scala.annotation.tailrec import scala.collection.Iterator class Cards { def deal(numPlayers: Int, deck: String): Array[String] = { val join: ((String, Char)) => String = { case (x, y) => x + y } @tailrec def dealInner(acc: List[String], xs: List[Char]): List[String] = xs splitAt numPlayers match { case (first, rest) if first.size == numPlayers => dealInner((acc zip first).map(join), rest) case _ => acc } dealInner( Iterator.continually("").take(numPlayers).toList, deck.toList ).toArray } } object Cards extends App { val cards = new Cards p(cards.deal(6, "012345012345012345")) p(cards.deal(4, "111122223333")) p(cards.deal(1, "012345012345012345")) p(cards.deal(6, "01234")) p(cards.deal(2, "")) def p(array: Array[String]): Unit = println { array map { s => '"' + s + '"' } mkString("{", ", ", "}") } }
実行結果。
{"000", "111", "222", "333", "444", "555"} {"123", "123", "123", "123"} {"012345012345012345"} {"", "", "", "", "", ""} {"", ""}
でも、余裕で10分越えたよ(笑)。だいたい、15分くらいかかったような…。
今日の問題はかなり簡単です。
できるだけ早い時間でエレガントなコードを書きましょう。
あまりに簡単なので制限時間を10分としてやってみてください。これ以上かかった人は
自分はかなりプログラミングができない。
とつらい事実を認識しましょう。
そして、これからすごくなりましょう。
さて、頑張りますか…。
(追記)
こういう機会に、普段機会がないと使わない言語を使ってみるってことで、Python版を作成。
#!/usr/bin/python # -*- coding: utf-8 -*- def deal(numPlayers, deck): def dealInner(acc, current): first = current[0:numPlayers] rest = current[numPlayers:] if len(first) == numPlayers: return dealInner(map(lambda x, y: x + y, acc, first), rest) else: return acc init = [''] * numPlayers return dealInner(init, deck) if __name__ == '__main__': print deal(6, '012345012345012345') print deal(4, '111122223333') print deal(1, '012345012345012345') print deal(6, '01234') print deal(2, '')
考え方は、Scala版と全く同じ。
関数とか思いっきり忘れてて、30分くらいかかりましたが…。
(さらに追記)
いろいろあって、Ruby版も書きました。
cards.rb
#!/usr/bin/ruby # -*- coding: utf-8 -*- class Cards def deal(numPlayers, deck) cards = Array.new(numPlayers, "") if numPlayers > deck.length cards else limit = deck.length - deck.length % numPlayers zipped = (0...limit).to_a.zip(deck.split(//).slice(0, limit)) zipped.reduce(cards) { |acc, elm| acc[elm[0] % numPlayers] += elm[1] acc } end end end cards = Cards.new p cards.deal(6, "012345012345012345") p cards.deal(4, "111122223333") p cards.deal(1, "012345012345012345") p cards.deal(6, "01234") p cards.deal(2, "") p cards.deal(3, "123123123") p cards.deal(4, "123123123")
何気に、初Ruby。Rubyっぽくないなどあったら、ご容赦いただけますよう、お願い致します…。
(追記)
畳み込みで、ということで、何も考えずに書き換えてみる。
def deal(numPlayers: Int, deck: String): Array[String] = { val join: ((String, Char)) => String = { case (x, y) => x + y } (0 until (deck.size / numPlayers)) .foldLeft( (Iterator.continually("").take(numPlayers).toList, deck.toList)) { case ((acc, xs), _) => xs splitAt numPlayers match { case (first, rest) if first.size == numPlayers => ((acc zip first).map(join), rest) case _ => (acc, xs) } }._1.toArray }
…ちょっと、書き直したことを後悔しました。
sliceにしとく?
def deal(numPlayers: Int, deck: String): Array[String] = (0 until (deck.size / numPlayers)) .foldLeft(Iterator.continually("").take(numPlayers).toList) { (acc, i) => deck.slice(i * numPlayers, (i * numPlayers) + numPlayers) match { case cs if cs.size == numPlayers => (acc zip cs) map { case (x, y) => x + y } case cs => acc } }.toArray
なんか元々の課題を難しくしてる気がしたので、だったらImmutableにこだわらずに素直にArray使った方がわかりやすいかなー、と。
def deal(numPlayers: Int, deck: String): Array[String] = ((0 until deck.size) zip deck) .take(deck.size - (deck.size % numPlayers)) .foldLeft(Array.fill(numPlayers)("")) { case (cards, (i, c)) => cards.updated(i % numPlayers, cards(i % numPlayers) + c) }
まあ、Ruby版とやってることはだいたい一緒ですね。