プロジェクト

全般

プロフィール

Problem 54 » 履歴 » バージョン 3

Noppi, 2024/01/20 07:34

1 1 Noppi
[ホーム](https://redmine.noppi.jp) - [[Wiki|Project Euler]]
2
# [[Problem 54]]
3
4
## Poker Hands
5
In the card game poker, a hand consists of five cards and are ranked, from lowest to highest, in the following way:
6
7 2 Noppi
* **High Card** : Highest value card.
8 1 Noppi
* **One Pair** : Two cards of the same value.
9
* **Two Pairs** : Two different pairs.
10
* **Three of a Kind** : Three cards of the same value.
11
* **Straight** : All cards are consecutive values.
12
* **Flush** : All cards of the same suit.
13
* **Full House** : Three of a kind and a pair.
14
* **Four of a Kind** : Four cards of the same value.
15
* **Straight Flush** : All cards are consecutive values of same suit.
16
* **Royal Flush** : Ten, Jack, Queen, King, Ace, in same suit.
17
18
The cards are valued in the order:
19
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.
20
If two players have the same ranked hands then the rank made up of the highest value wins; for example, a pair of eights beats a pair of fives (see example 1 below). But if two ranks tie, for example, both players have a pair of queens, then highest cards in each hand are compared (see example 4 below); if the highest cards tie then the next highest cards are compared, and so on.
21
22
Consider the following five hands dealt to two players:
23
24
| **Hand** | **Player 1** | **Player 2** | **Winner** |
25
|--|--|--|--|
26
| **1** | 5H 5C 6S 7S KD<br>Pair of Fives | 2C 3S 8S 8D TD<br>Pair of Eights | Player 2 |
27
| **2** | 5D 8C 9S JS AC<br>Highest card Ace | 2C 5C 7D 8S QH<br>Highest card Queen | Player 1 |
28
| **3** | 2D 9C AS AH AC<br>Three Aces | 3D 6D 7D TD QD<br>Flush  with Diamonds | Player 2 |
29
| **4** | 4D 6S 9H QH QC<br>Pair of Queens<br>Highest card Nine | 3D 6D 7H QD QS<br>Pair of Queens<br>Highest card Seven | Player 1 |
30
| **5** | 2H 2D 4C 4D 4S<br>Full House<br>With Three Fours | 3C 3D 3S 9S 9D<br>Full House<br>with Three Threes | Player 1 |
31
32
The file, [poker.txt](https://projecteuler.net/resources/documents/0054_poker.txt), contains one-thousand random hands dealt to two players. Each line of the file contains ten cards (separated by a single space): the first five are Player 1's cards and the last five are Player 2's cards. You can assume that all hands are valid (no invalid characters or repeated cards), each player's hand is in no specific order, and in each hand there is a clear winner.
33
34
How many hands does Player 1 win?
35
36
## ポーカーハンド
37
カードゲームのポーカーでは, 手札は5枚のカードからなりランク付けされている. 役を低い方から高い方へ順に並べると以下である.
38
39
* **役無し(ハイカード)** : 一番値が大きいカード
40
* **ワン・ペア** : 同じ値のカードが2枚
41
* **ツー・ペア** : 2つの異なる値のペア
42
* **スリーカード** : 同じ値のカードが3枚
43
* **ストレート** : 5枚の連続する値のカード
44
* **フラッシュ** : 全てのカードが同じスート (注: スートとはダイヤ・ハート・クラブ/スペードというカードの絵柄のこと)
45
* **フルハウス** : スリーカードとペア
46
* **フォーカード** : 同じ値のカードが4枚
47
* **ストレートフラッシュ** : ストレートかつフラッシュ
48
* **ロイヤルフラッシュ** : 同じスートの10, J, Q, K, A
49
50
ここでカードの値は小さい方から2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, Aである. (訳注:データ中で10は'T'と表される)
51
52
もし2人のプレイヤーが同じ役の場合には, 役を構成する中で値が最も大きいカードによってランクが決まる: 例えば, 8のペアは5のペアより強い (下の例1を見よ). それでも同じランクの場合には (例えば, 両者ともQのペアの場合), 一番値が大きいカードによってランクが決まる (下の例4を見よ). 一番値が大きいカードが同じ場合には, 次に値が大きいカードが比べれられ, 以下同様にランクを決定する.
53
54
例:
55
| **試合** | **プレイヤー1** | **プレイヤー2** | **勝者** |
56
|--|--|--|--|
57
| **1** | 5H 5C 6S 7S KD<br>5のペア | 2C 3S 8S 8D TD<br>8のペア | プレイヤー2 |
58
| **2** | 5D 8C 9S JS AC<br>役無し, A | 2C 5C 7D 8S QH<br>役無し, Q | プレイヤー1 |
59
| **3** | 2D 9C AS AH AC<br>Aのスリーカード | 3D 6D 7D TD QD<br>ダイヤのフラッシュ | プレイヤー2 |
60
| **4** | 4D 6S 9H QH QC<br>Qのペア, 9 | 3D 6D 7H QD QS<br>Qのペア, 7 | プレイヤー1 |
61
| **5** | 2H 2D 4C 4D 4S<br>4-2のフルハウス | 3C 3D 3S 9S 9D<br>3-9のフルハウス | プレイヤー1 |
62
63
[poker.txt](https://projecteuler.net/resources/documents/0054_poker.txt)には1000個のランダムな手札の組が含まれている. 各行は10枚のカードからなる (スペースで区切られている): 最初の5枚がプレイヤー1の手札であり, 残りの5枚がプレイヤー2の手札である. 以下のことを仮定してよい
64
65
* 全ての手札は正しい (使われない文字が出現しない. 同じカードは繰り返されない)
66
* 各プレイヤーの手札は特に決まった順に並んでいるわけではない
67
* 各勝負で勝敗は必ず決まる
68
69
1000回中プレイヤー1が勝つのは何回か? (訳注 : この問題に置いてA 2 3 4 5というストレートは考えなくてもよい)
70
71
```scheme
72 3 Noppi
(import (scheme base)
73
        (gauche base)
74
        (scheme file)
75
        (scheme sort)
76
        (gauche record))
77
78
(define (read-file filename)
79
  (call-with-output-string
80
    (^[string-port]
81
      (call-with-input-file
82
        filename
83
        (^[file-port]
84
          (let loop ([line (read-line file-port)])
85
            (unless (eof-object? line)
86
              (format string-port "~a~%" line)
87
              (loop (read-line file-port)))))
88
        :element-type :character))))
89
90
(define (read-to-list filename)
91
  (string-split (read-file filename)
92
                #[\s]
93
                'suffix))
94
95
(define (analyze-list lis)
96
  (let loop ([rest lis]
97
             [current '()]
98
             [result '()])
99
    (cond
100
      [(and (null? rest)
101
            (null? current))
102
       (reverse result)]
103
      [(null? rest)
104
       (reverse
105
         (cons (reverse current)
106
               result))]
107
      [(<= 5 (length current))
108
       (loop rest
109
             '()
110
             (cons (reverse current)
111
                   result))]
112
      [else
113
        (loop (cdr rest)
114
              (cons (car rest)
115
                    current)
116
              result)])))
117
118
(define-record-type cardinfo #t #t
119
  flush? numbers)
120
121
(define (card->suit card)
122
  (string-ref card 1))
123
124
(define (card->number card)
125
  (ecase (string-ref card 0)
126
    [(#\2) 2]
127
    [(#\3) 3]
128
    [(#\4) 4]
129
    [(#\5) 5]
130
    [(#\6) 6]
131
    [(#\7) 7]
132
    [(#\8) 8]
133
    [(#\9) 9]
134
    [(#\T) 10]
135
    [(#\J) 11]
136
    [(#\Q) 12]
137
    [(#\K) 13]
138
    [(#\A) 14]))
139
140
(define (same-suit? cards)
141
  (let loop ([rest cards] [suit #f])
142
    (cond
143
      [(null? rest) #t]
144
      [(not suit)
145
       (loop (cdr rest)
146
             (card->suit (car rest)))]
147
      [(char=? suit
148
               (card->suit (car rest)))
149
       (loop (cdr rest) suit)]
150
      [else #f])))
151
152
(define (cards->cardinfo cards)
153
  (let ([sorted-numbers (list-sort
154
                          <
155
                          (map card->number cards))])
156
    (let loop ([rest-numbers sorted-numbers]
157
               [current-num #f]
158
               [current-count 0]
159
               [card-result '()])
160
      (cond
161
        [(null? rest-numbers)
162
         (make-cardinfo (same-suit? cards)
163
                        (cons `(,current-num . ,current-count)
164
                              card-result))]
165
        [(zero? current-count)
166
         (loop (cdr rest-numbers)
167
               (car rest-numbers)
168
               1
169
               card-result)]
170
        [(= current-num (car rest-numbers))
171
         (loop (cdr rest-numbers)
172
               current-num
173
               (+ current-count 1)
174
               card-result)]
175
        [else
176
          (loop (cdr rest-numbers)
177
                (car rest-numbers)
178
                1
179
                (cons `(,current-num . ,current-count)
180
                      card-result))]))))
181
182
(define (royal-flush? cardinfo)
183
  (let ([result (straight? cardinfo)])
184
    (and result
185
         (= result 14)
186
         (flush? cardinfo))))
187
188
(define (straight-flush? cardinfo)
189
  (and (straight? cardinfo)
190
       (flush? cardinfo)))
191
192
(define (four-card? cardinfo)
193
  (let ([result (find (^c
194
                        (= (cdr c) 4))
195
                      (cardinfo-numbers cardinfo))])
196
    (if result
197
      (car result)
198
      #f)))
199
200
(define (full-house? cardinfo)
201
  (and (one-pair? cardinfo)
202
       (three-card? cardinfo)))
203
204
(define (flush? cardinfo)
205
  (if (cardinfo-flush? cardinfo)
206
    (caar (cardinfo-numbers cardinfo))
207
    #f))
208
209
(define (straight? cardinfo)
210
  (let ([numbers (cardinfo-numbers cardinfo)])
211
    (if (< (length numbers) 5)
212
      #f
213
      (let loop ([rest numbers] [current #f])
214
        (cond
215
          [(null? rest) (caar numbers)]
216
          [(not current)
217
           (loop (cdr rest) (caar rest))]
218
          [(= (- current 1) (caar rest))
219
           (loop (cdr rest) (caar rest))]
220
          [else #f])))))
221
222
(define (three-card? cardinfo)
223
  (let ([result (find (^c
224
                        (= (cdr c) 3))
225
                      (cardinfo-numbers cardinfo))])
226
    (if result
227
      (car result)
228
      #f)))
229
230
(define (two-pair? cardinfo)
231
  (let ([result (filter (^c
232
                          (= (cdr c) 2))
233
                        (cardinfo-numbers cardinfo))])
234
    (if (<= 2 (length result))
235
      (caar result)
236
      #f)))
237
238
(define (one-pair? cardinfo)
239
  (let ([result (find (^c
240
                        (= (cdr c) 2))
241
                      (cardinfo-numbers cardinfo))])
242
    (if result
243
      (car result)
244
      #f)))
245
246
(define (compare-cardinfo cardinfo1 cardinfo2)
247
  (let loop ([rest1 (cardinfo-numbers cardinfo1)]
248
             [rest2 (cardinfo-numbers cardinfo2)])
249
    (cond
250
      [(or (null? rest1)
251
           (null? rest2))
252
       (errorf "引き分け!~%")]
253
      [(= (caar rest1) (caar rest2))
254
       (loop (cdr rest1) (cdr rest2))]
255
      [(> (caar rest1) (caar rest2))
256
       'player-1]
257
      [else 'player-2])))
258
259
(define (winner cardinfo1 cardinfo2)
260
  (let loop ([procs `(,royal-flush? ,straight-flush? ,four-card?
261
                                    ,full-house? ,flush? ,straight?
262
                                    ,three-card? ,two-pair? ,one-pair?)])
263
    (if (null? procs)
264
      (compare-cardinfo cardinfo1 cardinfo2)
265
      (let ([result1 ((car procs) cardinfo1)]
266
            [result2 ((car procs) cardinfo2)])
267
        (cond
268
          [(and (not result1)
269
                (not result2))
270
           (loop (cdr procs))]
271
          [(and result1 result2)
272
           (if (> result1 result2)
273
             'player-1
274
             'player-2)]
275
          [(boolean result1) 'player-1]
276
          [else 'player-2])))))
277
278
(define each-games
279
  (let loop ([rest (analyze-list (read-to-list "poker.txt"))]
280
             [result '()])
281
    (if (< (length rest) 2)
282
      (reverse result)
283
      (loop (cddr rest)
284
            (cons `(,(car rest) ,(cadr rest))
285
                  result)))))
286
287
(define each-card-info
288
  (map (^[cards-cell]
289
         `( ,(cards->cardinfo (car cards-cell))
290
            ,(cards->cardinfo (cadr cards-cell))))
291
       each-games))
292
293
(define each-winner
294
  (map (^[cardinfo-cell]
295
         (winner (car cardinfo-cell)
296
                 (cadr cardinfo-cell)))
297
       each-card-info))
298
299
(define answer-54
300
  (length
301
    (filter (^s (eq? s 'player-1))
302
            each-winner)))
303
304
(format #t "54: ~d~%" answer-54)
305 1 Noppi
```