I tried to fix "I tried stochastic simulation of bingo game with Python"

Original story: [I tried a stochastic simulation of a bingo game with Python] (http://qiita.com/elzup/items/d532ffa1d326fbf75d01)

It was interesting to read, so I modified it a little while looking at Python's manners.

Make the main process

if __name__ == '__main__':
    main()

I like to make * main () *, but by separating the processing when it is executed as a script, you can start an interactive shell in another terminal etc. and import it as a module for debugging. Convenient.

For example, try changing the implementation of * generate_card () *

 def generate_card():
@@ -25,12 +33,22 @@
-    cards = []
-    for i in range(5):
-        cards.extend(sample(range(15 * i + 1, 15 * (i + 1)), 5))
-    cards[12] = HIT
-    return cards
+    def sampling(k=5):
+        for i in range(k):
+            yield sample(range(15 * i + 1, 15 * (i + 1) + 1), k)
+
+    from itertools import chain
+    card = list(chain.from_iterable(sampling()))
+    card[12] = HIT
+    return card

Measure performance with ipython.

$ ipython3-3.4 
In [1]: import orig_Bingo
In [2]: timeit -n 100 orig_Bingo.generate_card()
100 loops, best of 3: 86.4 us per loop

In [3]: import Bingo_kai
In [4]: timeit -n 100 Bingo_kai.generate_card()
100 loops, best of 3: 95.3 us per loop

Argument processing using argparse

Use argparse to handle the arguments, as long as you use * try ... except *. The usage of argparse is also standard, so once you get used to it, it's easy. As an aside, I recently saw cli tools like click and clip. However, I don't really understand the purpose and necessity.

    parser = argparse.ArgumentParser()
    parser.set_defaults(num=10000, times=5, verbose=False)
    parser.add_argument('-n', '--num', type=int, help='set card number')
    parser.add_argument('-t', '--times', type=int, help='set times')
    parser.add_argument(
        '-v', '--verbose', action='store_true',
        help='set verbose mode (loglevel=DEBUG)')

Since I tried to process the arguments, I will try to switch the debug output using logging. How to use the logging module is also standard.

logger = getLogger(__name__)
_handler = StreamHandler()
_handler.setLevel(DEBUG)
logger.addHandler(_handler)
...
logger.setLevel(DEBUG)

Write a doctest

Actually, I just wanted to say this in response to the ↓ of the original article.

I still don't know how to write a doc block, so I'll study

One of the features of Python is doctest. If you combine the document of how to use the function with a simple test, it may be two birds with one stone.

If you modify the logic of the original code so as not to mess with it, the doctest of the modified code is not good, but if you try to develop while writing the doctest, the perspective of the position to use will expand and the function will be easy to use naturally. And modules can be implemented.

Postscript: I revenged because it didn't work => I wrote a doctest in "I tried to simulate the probability of a bingo game with Python"

    """
    >>> check_bingo([False, True, False])
    False
    >>> check_bingo([True] * 5)
    True
    >>> check_bingo([False, False, True, False, False] * 5)
    True
    >>> check_bingo([
    ... True, False, False, False, False,
    ... False, True, False, False, False,
    ... False, False, True, False, False,
    ... False, False, False, True, False,
    ... False, False, False, False, True,
    ... ])
    True
    """

I'm using * random.sample *, so it's difficult to write a test without a mock ...: sweat:

Modified code

When I tried it, I couldn't fix it so well that it matched what I wanted to say ...: disappointed_relieved:

This code runs on Python3.

Bingo_kai.py


# -*- coding: utf-8 -*-

u"""Script that simulates the probability of BINGO
input:
    times =Number of times to turn the lottery machine, card_num =Number of cards
outpu:
Probability of getting even one

"""
import argparse
import sys
from logging import DEBUG, StreamHandler, getLogger
from random import sample

#hole
HIT = True
NOHIT = False

#Log output
logger = getLogger(__name__)
_handler = StreamHandler()
_handler.setLevel(DEBUG)
logger.addHandler(_handler)


def generate_card():
    u"""Generate card
5x5 center(3 rows 3 columns)Card with a hole in
    B(1st row) 1 - 15
    I(2nd row) 16 - 30
    N(3rd row) 31 - 45
    G(4th row) 46 - 60
    O(5th row) 61 - 75
    :returns: array card, length=25

    >>> from math import floor
    >>> card = generate_card()
    >>> card_len = len(card)
    >>> card_len == 25
    True
    >>> card[floor(card_len / 2)]
    True
    """
    def sampling(k=5):
        for i in range(k):
            yield sample(range(15 * i + 1, 15 * (i + 1) + 1), k)

    from itertools import chain
    card = list(chain.from_iterable(sampling()))
    card[12] = HIT
    return card


def check_bingo(card):
    u"""Whether you are BINGO
Judgment only
    param: array
    :returns: boolean

    >>> check_bingo([False, True, False])
    False
    >>> check_bingo([True] * 5)
    True
    >>> check_bingo([False, False, True, False, False] * 5)
    True
    >>> check_bingo([
    ... True, False, False, False, False,
    ... False, True, False, False, False,
    ... False, False, True, False, False,
    ... False, False, False, True, False,
    ... False, False, False, False, True,
    ... ])
    True
    >>> check_bingo([
    ... False, False, False, False, True,
    ... False, False, False, True, False,
    ... False, False, True, False, False,
    ... False, True, False, False, False,
    ... True, False, False, False, False,
    ... ])
    True
    """
    if card.count(HIT) < 5:
        return False

    for i in range(5):
        if all(card[i * 5:(i + 1) * 5]):  # horizontal
            return True
    for i in range(5):
        if all(card[i:i + 21:5]):  # vertical
            return True
    if all(card[0:25:6]) or all(card[4:21:4]):  # skew
        return True

    return False


def print_card(card):
    msg = ''
    for i, v in enumerate(card):
        if v == HIT:
            v = 'o'
        elif v == NOHIT:
            v = 'x'
        msg += '%3s' % v
        if i % 5 == 4:
            msg += '\n'
    logger.debug(msg)


def parse_argument(argv=None):
    """
    >>> parse_argument([])
    Namespace(num=10000, times=5, verbose=False)
    >>> parse_argument(['-n', '3', '-t', '30', '-v'])
    Namespace(num=3, times=30, verbose=True)
    """
    parser = argparse.ArgumentParser()
    parser.set_defaults(num=10000, times=5, verbose=False)
    parser.add_argument('-n', '--num', type=int, help='set card number')
    parser.add_argument('-t', '--times', type=int, help='set times')
    parser.add_argument(
        '-v', '--verbose', action='store_true',
        help='set verbose mode (loglevel=DEBUG)')

    args = parser.parse_args(sys.argv[1:] if argv is None else argv)
    if args.verbose:
        logger.setLevel(DEBUG)

    return args


def do_bingo(args):
    card = generate_card()
    lots = dict(sample([(i, HIT) for i in range(1, 76)], args.times))
    card_hole = [lots.get(i, NOHIT) for i in card]
    logger.debug('lots: {}\n'.format(sorted(lots.keys())))
    print_card(card)
    print_card(card_hole)
    return card_hole


def main():
    args = parse_argument()
    hit_count = 0
    for i in range(args.num):
        card_hole = do_bingo(args)
        if check_bingo(card_hole):
            hit_count += 1

    print(str(args.times) + u"Probability of BINGO even one at the first time:")
    p = hit_count / args.num
    print("%s (%.1f %%)" % (str(p), p * 100))


if __name__ == '__main__':
    main()

Like this.

$ python Bingo_kai.py -n 3 -t 45 -v
...
lots: [1, 3, 8, 9, 10, 11, 12, 14, 16, 17, 19, 21, 22, 24, 26, 28, 29, 30,
       31, 32, 33, 35, 36, 37, 39, 40, 41, 45, 46, 47, 49, 52, 55, 57, 60,
       61, 63, 64, 67, 68, 69, 71, 72, 73, 75]

  3 11  5  o 12
 20 18 16 26 17
 37 42  o 32 40
 50 47 48 51 49
 67 66 70 74 64

  o  o  x  o  o
  x  x  o  o  o
  o  x  o  o  o
  x  o  x  x  o
  o  x  x  x  o

Probability of even one BINGO at the 45th time:
0.6666666666666666 (66.7 %)

Recommended Posts

I tried to fix "I tried stochastic simulation of bingo game with Python"
I tried a stochastic simulation of a bingo game with Python
I wrote a doctest in "I tried to simulate the probability of a bingo game with Python"
I tried to find the entropy of the image with python
I tried to implement blackjack of card game in Python
I tried to create a list of prime numbers with python
I tried to improve the efficiency of daily work with Python
I tried to automatically collect images of Kanna Hashimoto with Python! !!
I tried hundreds of millions of SQLite with python
I tried to get CloudWatch data with Python
I tried to output LLVM IR with Python
I tried to automate sushi making with python
I tried to get the authentication code of Qiita API with Python.
I tried to streamline the standard role of new employees with Python
I tried to get the movie information of TMDb API with Python
I tried to implement a card game of playing cards in Python
I tried fp-growth with python
I tried scraping with Python
I tried to extract features with SIFT of OpenCV
I tried to summarize how to use matplotlib of python
I tried to make a simple mail sending application with tkinter of Python
I tried to implement Minesweeper on terminal with python
I tried to get started with blender python script_Part 01
I tried to touch the CSV file with Python
I tried to draw a route map with Python
I tried to solve the soma cube with python
I tried to get started with blender python script_Part 02
I tried to implement an artificial perceptron with python
I tried to easily visualize the tweets of JAWS DAYS 2017 with Python + ELK
I tried to automatically generate a password with Python3
I tried to solve the problem with Python Vol.1
I tried to analyze J League data with Python
I tried gRPC with Python
I tried scraping with python
[Python] I tried to get Json of squid ring 2
I tried "morphology conversion" of images with Python + OpenCV
I tried to automatically send the literature of the new coronavirus to LINE with Python
I tried to summarize the string operations of Python
I tried to solve AOJ's number theory with Python
I tried to put out the frequent word ranking of LINE talk with Python
I tried to automate the article update of Livedoor blog with Python and selenium.
[Python] I tried to automatically create a daily report of YWT with Outlook mail
I tried to visualize the running data of the racing game (Assetto Corsa) with Plotly
I tried to compare the processing speed with dplyr of R and pandas of Python
The 15th offline real-time I tried to solve the problem of how to write with python
I tried "gamma correction" of the image with Python + OpenCV
I tried to simulate how the infection spreads with Python
I want to specify another version of Python with pyvenv
I tried to find the average of the sequence with TensorFlow
I tried various methods to send Japanese mail with Python
I tried running Movidius NCS with python of Raspberry Pi3
[Python] I tried to visualize tweets about Corona with WordCloud
[Python] I tried to visualize the follow relationship of Twitter
Mayungo's Python Learning Episode 3: I tried to print numbers with print
I tried to implement ListNet of rank learning with Chainer
I tried to make GUI tic-tac-toe with Python and Tkinter
I tried to divide the file into folders with Python
I tried to touch Python (installation)
I tried web scraping with python.
Life game with Python! (Conway's Game of Life)
I want to debug with Python