こいこいアプリを作りたいと思っています。

ええと、『サマーウォーズ』見ましてね、うわ、なんて面白いんだろう、この映画! って思ったんです。それで花札やりたくなりまして、でも相手がいない。仕方がないから、ネットで遊べる花札、主にこいこいを探したのですが、なかなかこれだっ! というものが見付からなくて、しかたがない、自分で作ろうか、そんな気になってしまいました。

けれど私はこれまでこうしたプログラムをしたことがなくて、うまくいくかどうかは未知数。無理なんじゃないかな、と思いながらも、少しずつ進めていきたいなと思っているところです。

とりあえずやりたいことは、任天堂のサイトに公開されている花札、こいこいの遊び方で遊べるようにする、ということです。

花札を遊ぶというのなら、その前提としてまず札をちゃんと配れないければならない。つまりシャッフルをどうしようかと考えて、まあ、考えるより書いた方がはやい。書いてみたんですが、いやあ、Pythonは素晴しい。ちゃんと配列をシャッフルする関数が用意されてるんですね。

    def shuffle(self):
        order = self.order
        self.order = list()
        while len(order) != 0:
            i = random.randint(0, len(order) - 1)
            self.order.append(order[i])
            del order[i]

これが、

    def shuffle(self):
        random.shuffle(self.order)

こうなりました。

凡人は、考えるだけ無駄なんだろうか……。

シャッフルできるようになったというわけで、札を配るところまでできるようになりました。あとはロジックさえできれば、とりあえず遊べるようになりそうですね。って、それが一番難しいんでしょうけどさ。

koikoi.py

# -*- coding: utf-8-unix; mode: python -*-
import random

class Deck(object):
    def __init__(self, cards=None):
        if cards is None:
            self.cards = self._default_cards()
        else:
            self.cards = self._default_cards()            
        self.order = list()
        self._initorder()
        self.index = 0

    def _initorder(self):
        self.order = list()
        for season in self.cards:
            for number in self.cards[season]:
                self.order.append(season + u'_' + number)

    def shuffle(self):
        random.shuffle(self.order)
        ## order = self.order
        ## self.order = list()
        ## while len(order) != 0:
        ##     i = random.randint(0, len(order) - 1)
        ##     self.order.append(order[i])
        ##     del order[i]

    def draw(self, index=None):
        if index is None:
            i = self.index
        else:
            i = index - 1
        try:
            (season, number) = self.order[i].split(u'_')
        except:
            return None
        else:
            return self.cards[season][number]
        finally:
            if index is None:
                self.index += 1

    def _default_cards(self):
        return {
            u'01': {
                u'1': Card(u'1', u'01', u'松に鶴', 20),
                u'2': Card(u'2', u'01', u'松に赤短', 5),
                u'3': Card(u'3', u'01', u'松のカス', 1),
                u'4': Card(u'4', u'01', u'松のカス', 1)
                },
            u'02': {
                u'1': Card(u'1', u'02', u'梅に鶯', 10),
                u'2': Card(u'2', u'02', u'梅に赤短', 5),
                u'3': Card(u'3', u'02', u'梅のカス', 1),
                u'4': Card(u'4', u'02', u'梅のカス', 1)
                },
            u'03': {
                u'1': Card(u'1', u'03', u'桜に幕', 20),
                u'2': Card(u'2', u'03', u'桜に赤短', 5),
                u'3': Card(u'3', u'03', u'桜のカス', 1),
                u'4': Card(u'4', u'03', u'桜のカス', 1),
                },
            u'04': {
                u'1': Card(u'1', u'04', u'藤に不如帰', 10),
                u'2': Card(u'2', u'04', u'藤に短冊', 5),
                u'3': Card(u'3', u'04', u'藤のカス', 1),
                u'4': Card(u'4', u'04', u'藤のカス', 1),
                },
            u'05': {
                u'1': Card(u'1', u'05', u'菖蒲に八ツ橋', 10),
                u'2': Card(u'2', u'05', u'菖蒲に短冊', 5),
                u'3': Card(u'3', u'05', u'菖蒲のカス', 1),
                u'4': Card(u'4', u'05', u'菖蒲のカス', 1),
                },
            u'06': {
                u'1': Card(u'1', u'06', u'牡丹に蝶', 10),
                u'2': Card(u'2', u'06', u'牡丹に青短', 5),
                u'3': Card(u'3', u'06', u'牡丹のカス', 1),
                u'4': Card(u'4', u'06', u'牡丹のカス', 1),
                },
            u'07': {
                u'1': Card(u'1', u'07', u'萩に猪', 10),
                u'2': Card(u'2', u'07', u'萩に短冊', 5),
                u'3': Card(u'3', u'07', u'萩のカス', 1),
                u'4': Card(u'4', u'07', u'萩のカス', 1),
                },
            u'08': {
                u'1': Card(u'1', u'08', u'芒に月', 20),
                u'2': Card(u'2', u'08', u'芒に雁', 10),
                u'3': Card(u'3', u'08', u'芒のカス', 1),
                u'4': Card(u'4', u'08', u'芒のカス', 1),
                },
            u'09': {
                u'1': Card(u'1', u'09', u'菊に盃', 10),
                u'2': Card(u'2', u'09', u'菊に青短', 5),
                u'3': Card(u'3', u'09', u'菊のカス', 1),
                u'4': Card(u'4', u'09', u'菊のカス', 1),
                },
            u'10': {
                u'1': Card(u'1', u'10', u'紅葉に鹿', 10),
                u'2': Card(u'2', u'10', u'紅葉に青短', 5),
                u'3': Card(u'3', u'10', u'紅葉のカス', 1),
                u'4': Card(u'4', u'10', u'紅葉のカス', 1),
                },
            u'11': {
                u'1': Card(u'1', u'11', u'小野道風に蛙', 20),
                u'2': Card(u'2', u'11', u'柳に燕', 10),
                u'3': Card(u'3', u'11', u'柳に短冊', 5),
                u'4': Card(u'4', u'11', u'柳のカス', 1),
                },
            u'12': {
                u'1': Card(u'1', u'12', u'桐に鳳凰', 20),
                u'2': Card(u'2', u'12', u'桐のカス', 1),
                u'3': Card(u'3', u'12', u'桐のカス', 1),
                u'4': Card(u'4', u'12', u'桐のカス', 1),
                }
            }

class Card(dict):
    def __init__(self, number, season, name, point=1):
        self[u'number'] = number
        self[u'season'] = season
        self[u'name'] = name
        self[u'point'] = point

テスト用プログラム(index.cgi

#! /usr/bin/env python
# -*- coding: utf-8-unix; mode: python -*-

import cgi
import cgitb; cgitb.enable()
import sys
import locale

sys.path.insert(0, './lib/')
import htmldocument
import koikoi

deck = koikoi.Deck()

locale.setlocale(locale.LC_ALL, '')

ht = htmldocument.HTML(lang=u'ja', sitetitle=u'koikoi',
                       cssfiles=[u'resource/main.css'])

ht.print_resp_header()
ht.print_html_header()

## ht.printe(u'<p>')
## ht.printe(deck.order)
## ht.printe(u'</p>')
deck.shuffle()
## ht.printe(u'<p>')
## ht.printe(deck.order)
## ht.printe(u'</p>')

cards = list()
oya = list()
ba = list()
ko = list()
yama = list()
count = 0
card = deck.draw()

while card is not None:
    count += 1
    cards.append(card)
    if count in [1, 2, 7, 8, 13, 14, 19, 20]:
        ko.append(card)
    elif count in [3, 4, 9, 10, 15, 16, 21, 22]:
        ba.append(card)
    elif count in [5, 6, 11, 12, 17, 18, 23, 24]:
        oya.append(card)
    else:
        yama.append(card)
    card = deck.draw()

ht.printe(ht.h1(u'proto-koikoi'))

ht.printe(u'<div class="oya">')
ht.printe(ht.h2(u'親の手札'))
ht.printe(ht.ol(ht.li([c[u'name'] for c in oya])))
ht.printe(u'</div>')

ht.printe(u'<div class="ba">')
ht.printe(ht.h2(u'場札'))
ht.printe(ht.ol(ht.li([c[u'name'] for c in ba])))
ht.printe(u'</div>')

ht.printe(u'<div class="ko">')
ht.printe(ht.h2(u'子の手札'))
ht.printe(ht.ol(ht.li([c[u'name'] for c in ko])))
ht.printe(u'</div>')

ht.printe(u'<div class="yama">')
ht.printe(ht.h2(u'山札'))
ht.printe(ht.ol(ht.li([c[u'name'] for c in yama])))
ht.printe(u'</div>')

ht.printe(u'<div class="all">')
ht.printe(ht.h2(u'全部'))
ht.printe(ht.ol(ht.li([c[u'name'] for c in cards])))
ht.printe(u'</div>')

ht.printe(u'<div class="test">')
ht.printe(ht.h2(u'番号指定'))
ht.printe(u'<dl>')
for index in [5, 10, 15, 20, 25, 30, 35, 40, 45, 48]:
    ht.printe(ht.dt(u'{0}枚目'.format(index)))
    ht.printe(ht.dd(u'{0[name]} ({0[point]}点)'.format(deck.draw(index))))
ht.printe(u'</dl>')

ht.printe(u'</div>')
ht.print_html_close()