Problem:
Problem C: K Poker

Description

時は200X年、K大学で活動する謎のサークルKはその大学の文化祭の最中にK東4Fで彼らが作成した新たなゲーム、Kポーカーを発表した。

このゲームは一見すると普通のポーカーであるが、カードに基本点という要素をつけてポーカーをより奥の深いゲームにしたものである。

カードの基本点はそれぞれのカードに書かれている絵柄によって決まり、手札の点数は手札にある5枚の基本点の合計に手札の役の倍率を掛けたものになる。

この基本点を導入した事により、例えばフルハウスなどの強い役を作ったとしても基本点が0であればブタと同様に扱われてしまい、ワンペアに負けることさえある。

それ以外のルールは通常のポーカーと同じである。

このKポーカーをPCに移植しようと思ったあなたは手札の点数を計算するプログラムを書く事にした。

なおこのゲームは18歳未満の人はプレイ出来ない。

Input

入力は複数のテストケースからなる。

各テストケースの最初の行にはチェックする手札の数Nが書かれている。

次の4行には13個の整数が並びカードの基本点が1-13の順に並んで書かれている。4行のスーツは上から順にスペード、クローバー、ハート、ダイヤの順に並んでいる。

次の行には9個の整数が並び、順にワンペア、ツーペア、スリーカード、ストレート、フラッシュ、フルハウス、フォーカード、ストレートフラッシュ、ロイヤルストレートフラッシュの倍率を表している。役の倍率は必ず昇順となっている。ブタ(役無し、ノーペア)の倍率は常に0である。

次のN行には手札を表す5個の長さ2の異なる文字列が並んでいる。1文字目はカードの数値を表し,A,2,3,4,5,6,7,8,9,T,J,Q,Kのいずれかである。2文字目はカードのスーツを表し、S,C,H,Dのいずれかである。各アルファベットはAはエース、Tは10、Jはジャック、Qはクイーン、Kはキング、Sはスペード、Cはクローバー、Hはハート、Dはダイヤを表す。

入力の数値は全て[0,10000]の範囲に収まっている。

入力はEOFで終わる。

Output

各手札の点数を1行ずつ出力せよ。

連続する2つのテストケースの間には空行を1つ入れること。

役についてはwikipediaのポーカーのページを参照のこと。
なお、ストレートはエースとキングをまたぐ場合があるが、手札が10,ジャック、クイーン、キング、エースの場合にのみストレートとみなされる。

Sample Input

3
0 1 0 1 0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 1 0 0 1 0 0 2
0 1 1 0 1 1 1 0 0 0 0 5 5
3 1 1 1 0 1 0 0 1 0 3 0 2
1 1 2 4 5 10 20 50 100
7H 6H 2H 5H 3H
9S 9C 9H 8H 8D
KS KH QH JD TS
10
1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1
1 2 3 4 5 6 7 8 9
AS 3D 2C 5D 6H
6S 6C 7D 8H 9C
TS TD QC JD JC
KD KH KC AD 2C
3D 4H 6D 5H 7C
2S KS QS AS JS
TS TD JD JC TH
8H 8D TC 8C 8S
4S 5S 3S 7S 6S
KD QD JD TD AD

Output for Sample Input

25
0
14

0
5
10
15
20
25
30
35
40
45

Solution in Kotlin (judge verdict: WA: Presentation Error)


fun main(args:Array<String>):Unit {
    var isNotFirst = false
    while(true){
        if (isNotFirst) print("\n")
        isNotFirst = true
        val n = readLine()?.trim()?.toInt() ?: return
        val basePoint = Array(4){readLine()!!.trim().split(' ').map(String::toInt).toTypedArray()}
        val multiple = readLine()!!.trim().split(' ').map(String::toInt).toTypedArray()
        val score = ScoreBoard(basePoint, multiple)
        repeat(n){
            println(score.score(Cards(readLine()!!.trim().split(' ').map{Card(it)})))
        }
    }
}
class ScoreBoard(private val mBasePoints:Array<Array<Int>>, private val mMultiple:Array<Int>){
    private fun baseScore(card:Card):Int {
        return mBasePoints[when(card.suit){
            Suit.Spade -> 0
            Suit.Clover -> 1
            Suit.Hart -> 2
            Suit.Dia -> 3
        }][card.number - 1]
    }
    fun score(cards:Cards):Int {
        return cards.cards.sumBy{baseScore(it)} * when(cards.role()){
            Role.NoRole -> 0
            Role.OnePair -> mMultiple[0]
            Role.TwoPair -> mMultiple[1]
            Role.ThreeCards -> mMultiple[2]
            Role.Strait -> mMultiple[3]
            Role.Flush -> mMultiple[4]
            Role.FullHouse -> mMultiple[5]
            Role.FourCards -> mMultiple[6]
            Role.StraitFlush -> mMultiple[7]
            Role.RoyalStraitFlush -> mMultiple[8]
        }
    }
}
enum class Suit{
    Spade, Clover, Hart, Dia
}
class Card private constructor(val number:Int, val suit: Suit){
    constructor(str:String):this(when(str[0]){
        'A' -> 1
        'T' -> 10
        'J' -> 11
        'Q' -> 12
        'K' -> 13
        else -> str[0].toString().toInt()
    }, when(str[1]){
        'S' -> Suit.Spade
        'C' -> Suit.Clover
        'H' -> Suit.Hart
        else -> Suit.Dia
    })
}
enum class Role{
    NoRole, OnePair, TwoPair, ThreeCards, Strait, Flush, FullHouse, FourCards, StraitFlush, RoyalStraitFlush
}
class Cards(private val mCards:Iterable<Card>){
    val cards:Iterable<Card>
        get() = mCards
    fun role():Role {
        return when{
            isRoyalStraitFlush(mCards) -> Role.RoyalStraitFlush
            isStraitFlush(mCards) -> Role.StraitFlush
            isFourCards(mCards) -> Role.FourCards
            isFullHouse(mCards) -> Role.FullHouse
            isFlush(mCards) -> Role.Flush
            isStrait(mCards) -> Role.Strait
            isThreeCards(mCards) -> Role.ThreeCards
            isTwoPair(mCards) -> Role.TwoPair
            isOnePair(mCards) -> Role.OnePair
            else -> Role.NoRole
        }
    }
    companion object {
        private fun isRoyalStraitFlush(cards:Iterable<Card>):Boolean {
            return isFlush(cards) && isTenToAceStrait(cards)
        }
        private fun isFlush(cards:Iterable<Card>):Boolean {
            return Suit.values().any{suit -> cards.all{it.suit == suit}}
        }
        private fun isTenToAceStrait(cards:Iterable<Card>):Boolean {
            return listOf(1, 10, 11, 12, 13).all{num -> cards.any{it.number == num}}
        }
        private fun isStrait(cards:Iterable<Card>):Boolean {
            return (1 until 5).map{cards.minBy(Card::number)!!.number + it}.all{num -> cards.any{it.number == num}} || isTenToAceStrait(cards)
        }
        private fun isStraitFlush(cards:Iterable<Card>):Boolean {
             return isStrait(cards) && isFlush(cards)
        }
        private fun isFourCards(cards:Iterable<Card>):Boolean {
            return cards.groupBy(Card::number).any { it.value.size == 4 }
        }
        private fun isTwoPair(cards:Iterable<Card>):Boolean {
            return cards.groupBy(Card::number).filter{it.value.size == 2}.count() == 2
        }
        private fun isThreeCards(cards:Iterable<Card>):Boolean {
            return cards.groupBy(Card::number).any{it.value.size == 3}
        }
        private fun isOnePair(cards:Iterable<Card>):Boolean {
            return cards.groupBy(Card::number).any{it.value.size == 2}
        }
        private fun isFullHouse(cards:Iterable<Card>):Boolean {
            return isOnePair(cards) && isThreeCards(cards)
        }
    }
}