机を配置しようぜ☆(^~^)?<その2>

読了目安:41分

<前回の続き>

出力

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ソースは Git hub にある☆
まず 何が出力されるかを説明しよう☆」

Git hub: event-placement-ai

20190721blog48a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 机の配置だな☆ 数字は参加者番号☆」

20190721blog48a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 CSV形式で ここまでは作ってくれる☆
あとは 手打ちで 何とかしろだぜ☆」

best-position.csv

X,Y,BLOCK,TABLE,PARTICIPANT,GENRE_CODE
0,0,C,27,35,Gray
1,0,C,26,22,Blue
2,0,C,25,41,Red
3,0,C,24,18,Yellow
4,0,C,23,8,Blue
7,0,B,22,20,Yellow
8,0,B,21,23,Black
9,0,B,20,54,Orange
10,0,B,19,21,Red
13,0,A,18,1,Red
14,0,A,17,27,Blue
15,0,A,16,53,Green
16,0,A,15,31,Yellow
17,0,A,14,34,Pink
18,0,A,13,52,Red
19,0,A,12,49,Gray
0,1,C,28,30,Blue
19,1,A,11,4,Blue
0,2,C,29,7,Red
2,2,F,57,57,Green
3,2,F,56,48,White
4,2,F,55,24,Black
7,2,E,50,25,White
8,2,E,49,47,Brown
9,2,E,48,56,Blue
10,2,E,47,60,Blue
13,2,D,41,58,Yellow
14,2,D,40,5,Green
15,2,D,39,19,SkyBlue
16,2,D,38,10,Green
17,2,D,37,40,Blue
19,2,A,10,38,Orange
0,3,C,30,33,Blue
2,3,F,58,15,Blue
3,3,F,59,14,Green
4,3,F,60,32,Orange
7,3,E,51,11,Purple
8,3,E,52,39,White
9,3,E,53,36,Green
10,3,E,54,12,Red
13,3,D,42,28,Pink
14,3,D,43,2,Red
15,3,D,44,45,YellowGreen
16,3,D,45,3,Blue
17,3,D,46,6,Blue
19,3,A,9,50,Blue
0,4,C,31,51,Yellow
19,4,A,8,44,Green
0,5,C,32,46,Black
1,5,C,33,26,Yellow
2,5,C,34,17,Blue
3,5,C,35,16,Yellow
4,5,C,36,59,White
13,5,A,1,9,Green
14,5,A,2,13,Violet
15,5,A,3,42,Green
16,5,A,4,29,Green
17,5,A,5,43,Yellow
18,5,A,6,55,Violet
19,5,A,7,37,Red

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 この出力データを使って、さらに思考の材料にしてもいいわけだしな☆」

入力

CCCCC..BBBB..AAAAAAA
C..................A
C.FFF..EEEE..DDDDD.A
C.FFF..EEEE..DDDDD.A
C..................A
CCCCC........AAAAAAA

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ブロックは Rogue形式で示せだぜ☆ 半角1文字でなんとかしろ☆」

27,26,25,24,23, 0, 0,22,21,20,19, 0, 0,18,17,16,15,14,13,12
28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11
29, 0,57,56,55, 0, 0,50,49,48,47, 0, 0,41,40,39,38,37, 0,10
30, 0,58,59,60, 0, 0,51,52,53,54, 0, 0,42,43,44,45,46, 0, 9
31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8
32,33,34,35,36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 テーブル番号は CSV形式で示せだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 なんだぜ、この二重管理……☆」

ID,GENRE_CODE
1,Red
2,Red
3,Blue
4,Blue
5,Green
6,Blue
7,Red
8,Blue
9,Green
10,Green
11,Purple
12,Red
13,Violet
14,Green
15,Blue
16,Yellow
17,Blue
18,Yellow
19,SkyBlue
20,Yellow
21,Red
22,Blue
23,Black
24,Black
25,White
26,Yellow
27,Blue
28,Pink
29,Green
30,Blue
31,Yellow
32,Orange
33,Blue
34,Pink
35,Gray
36,Green
37,Red
38,Orange
39,White
40,Blue
41,Red
42,Green
43,Yellow
44,Green
45,YellowGreen
46,Black
47,Brown
48,White
49,Gray
50,Blue
51,Yellow
52,Red
53,Green
54,Orange
55,Violet
56,Blue
57,Green
58,Yellow
59,White
60,Blue

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 参加者は番号に ジャンルコードを対応付けろだぜ☆
ジャンルコードは HTML/CSS で使われる色の名前☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ジャンルコードじゃなくて、色じゃない」

思考部

# Shuffule
random.shuffle(par_id_list)
random.shuffle(flo_id_list)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 思考部は今は シャッフルしてるだけだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 要らね☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 参加者番号と、テーブル番号を 対応付けながら 先頭から順に並べろだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ブロックに 同じジャンルコードで まとめてくれるところまで やってくれてもいいんじゃない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これは数学で言うと 何問題☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 椅子問題☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ブロックからはみ出た人を0に近づける 最小誤差」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 うーむ☆」

import random
from my_lib.html_generator.css_builder import new_csv
from my_lib.html_generator.html_builder import new_html
from my_lib.entry_list import read_entry_lists
from my_lib.mapper import write_mappings
from my_lib.position import new_position
from my_lib.build_floor_map import convert_map
from evaluation import evaluate

# Location.
best_position_file = "./event-placement-ai/output-data/best-position.csv"

# Read a cloor map.
convert_map()

par_id_list, flo_id_list = read_entry_lists()
print("Info    : Participants count: {}".format(len(par_id_list)))
print("Info    : Table        count: {}".format(len(flo_id_list)))

max_score = -1
best_pos_df = None

for i in range(0, 10):
    # Shuffule
    random.shuffle(par_id_list)
    random.shuffle(flo_id_list)

    write_mappings(par_id_list, flo_id_list)

    pos_df = new_position()

    # Evaluation
    score = evaluate(pos_df)

    if max_score < score:
        max_score = score
        best_pos_df = pos_df

new_html(best_pos_df)
new_csv(best_pos_df)

best_pos_df.to_csv(best_position_file, index=False)

print("Info    : Finished.")

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 とりあえず ループで10回 回して 一番評価値の多い配置を返すなら
外側の形は こうだな☆」

evaluation.py

def evaluate(pos_df):
    return 0

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 評価値を返す関数を実装すればいいわけだが……☆」

def evaluate(pos_df):

    # 評価値
    value = 0

    # Block は A~F とする。
    # GenreCode は色々。
    block_dict = {}

    for _index, row in pos_df.iterrows():
        # x = row["X"]
        # y = row["Y"]
        block = row["BLOCK"]
        # table_id = row["TABLE"]
        # participant_id = row["PARTICIPANT"]
        genre_code = row["GENRE_CODE"]

        if not(block in block_dict):
            block_dict[block] = {}

        if not(genre_code in block_dict[block]):
            block_dict[block][genre_code] = 0

        block_dict[block][genre_code] += 1

    # 集計
    for _block_name, genre_code_dict in block_dict.items():
        for _genre_code_name, count in genre_code_dict.items():
            value += count ** 2
            break

    return value

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 例えば こうとか☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 ラッキーパンチ待ち評価関数か☆」

20190721blog49loop10.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ループで 10回 トライすると こう☆
評価値は 99 ぐらいかだぜ☆ Cブロックに少し 青 が固まっているな☆」

20190721blog49loop1000.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 1000回 トライ……しても 何にもならないな☆」

20190721blog49loop1000value119.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もう1回 1000回 トライで 評価値119☆ 黄色と青が 固まっているような気もするが……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ラッキーパンチ待ちの 電気代がかかるやつじゃない!」

KIFUWARABE_80x100x8_01_Futu.gif
「 シャッフルするのではなく、1つずつ 入れ替えて 少しずつ 良くしていくのが
いいんじゃないか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 作り込むには 週末の休みが終わってしまった……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 そもそも その評価関数は わたしたちの目的に沿ってるのかだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 検定しようぜ☆?」

評価関数を検定しようぜ☆(^~^)?

評価関数を検定しようぜ☆(^~^)?

20190723blog50value8.png

20190723blog50value13.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 1回しかテストしてないが、次に進もうぜ☆」

探索しようぜ☆(^~^)?

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 シャッフルして ラッキーパンチを待っていては くじ運頼りになってしまう☆
わたしたちは もう少しマシな探し方を知っているだろう☆」

import random
import pandas as pd
from my_lib.html_generator.css_builder import new_csv
from my_lib.html_generator.html_builder import new_html
from my_lib.entry_list import read_entry_lists
from my_lib.mapper import new_mappings
from my_lib.position import new_position
from my_lib.build_floor_map import convert_floor_map
from evaluation import evaluate

# Location.
block_file = "./event-placement-ai/input-data/block.txt"
table_file = "./event-placement-ai/input-data/table.txt"
best_position_file = "./event-placement-ai/output-data/best-position.csv"
position_file = "./event-placement-ai/auto-generated/position.csv"
floor_file = "./event-placement-ai/auto-generated/floor.csv"
participant_file = "./event-placement-ai/input-data/participant.csv"
mappings_file = "./event-placement-ai/auto-generated/mappings.csv"

# Read a floor.
floor_df = convert_floor_map(block_file, table_file)
floor_df.to_csv(floor_file, index=False)

par_id_list, flo_id_list = read_entry_lists()
# print(&quot;Info    : Participants count: {}&quot;.format(len(par_id_list)))
# print(&quot;Info    : Table        count: {}&quot;.format(len(flo_id_list)))

# Shuffule at first.
random.shuffle(par_id_list)
flo_id_list.sort()
# random.shuffle(flo_id_list)

max_value = -1

for i in range(0, 1000):
    # Swap.
    size = len(par_id_list)
    index1 = random.randint(0, size-1)
    index2 = random.randint(0, size-1)
    # print("size={}, index1={}, index2={}".format(size, index1, index2))
    temp = par_id_list[index1]
    par_id_list[index1] = par_id_list[index2]
    par_id_list[index2] = temp

    mappings_df = new_mappings(par_id_list, flo_id_list)
    mappings_df.to_csv(mappings_file, index=False)

    # floor_df = pd.read_csv(floor_file,
    #                       sep=',', engine='python')
    participant_df = pd.read_csv(participant_file)
    # mappings_df = pd.read_csv(mappings_file,
    #                          sep=',', engine='python')

    pos_df = new_position(floor_df,
                          participant_df, mappings_df)

    """
    output
    ------

    X,Y,BLOCK,PARTICIPANT,TABLE,GENRE_CODE
    0,0,C,1,27,Red
    1,0,C,2,26,Red
    2,0,C,3,25,Blue
    3,0,C,4,24,Blue
    4,0,C,5,23,Green
    """
    pos_df.to_csv(position_file, index=False)

    # Evaluation
    value = evaluate(pos_df)
    print("Info    : i={}, Value={}, Max={}".format(i, value, max_value))

    if max_value < value:
        # Update and output.
        max_value = value
        new_html(pos_df, 0, 0, max_value)
        new_csv(pos_df, 0, 0)
        pos_df.to_csv(best_position_file, index=False)
    else:
        # Cancel swap.
        temp = par_id_list[index2]
        par_id_list[index2] = par_id_list[index1]
        par_id_list[index1] = temp


print("Info    : Finished.")

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 2か所を選んで 交換し、評価値が上がれば採用、そうでなければ 元に戻す、
ということを ちまちま 繰り返そうぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 確実だが 時間がかかるぜ☆
最悪、机の数の2乗ぐらい 回数が かかるんじゃないか☆?」

20190724blog51value342.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これ、評価値342☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 評価関数は ちゃんと働いているようね」

KIFUWARABE_80x100x8_01_Futu.gif
「 緑、赤、青は 自分にあったブロックを選んでいるようにみえるが、まぐれ だからな☆
最初に 自分に合わないブロックに集まってしまうと、
そこから出ようとしなくなるのは 想像付くぜ☆」

20190724blog51value390.png

KIFUWARABE_80x100x8_01_Futu.gif
「 例えば このように、 赤 が小さいブロックに陣取ってしまうと、もう修正がきかない☆
これを 極大の丘に登る という☆
わたしたちは 最大の丘に登りたい んだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ひとまず 1000回で探索を終了するのではなく、どこを1つ交換しても評価値が上がらなくときに
終了するように変更しようぜ☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 じゃあ ランダムに2か所選んで交換するのではなく、机の数の2乗÷2 の組み合わせを あらかじめ作って
シャッフルするの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 机の数が 300 なら 90000 の組み合わせがあるのか……☆
じゃあ やっぱ ランダム・ヒットで☆」

import os
import random
import pandas as pd
from my_lib.html_generator.css_builder import new_csv
from my_lib.html_generator.html_builder import new_html
from my_lib.html_generator.json_builder import new_json
from my_lib.entry_list import new_entry_lists_from_mappings
from my_lib.entry_list import read_entry_lists
from my_lib.mapper import new_mappings
from my_lib.position import new_position
from my_lib.build_floor_map import convert_floor_map
from evaluation import evaluate

# Location.
block_file = "./event-placement-ai/input-data/block.txt"
table_file = "./event-placement-ai/input-data/table.txt"
best_position_file = "./event-placement-ai/output-data/best-position.csv"
position_file = "./event-placement-ai/auto-generated/position.csv"
floor_file = "./event-placement-ai/auto-generated/floor.csv"
participant_file = "./event-placement-ai/input-data/participant.csv"
best_mappings_file = "./event-placement-ai/auto-generated/best-mappings.csv"

# Read a floor.
floor_df = convert_floor_map(block_file, table_file)
floor_df.to_csv(floor_file, index=False)

if os.path.isfile(best_mappings_file):
    tbl_id_list, par_id_list = new_entry_lists_from_mappings(
        best_mappings_file)
else:
    tbl_id_list, par_id_list = read_entry_lists(floor_file, participant_file)
# print(&quot;Info    : Participants count: {}&quot;.format(len(par_id_list)))
# print(&quot;Info    : Table        count: {}&quot;.format(len(tbl_id_list)))

# Sort table.
tbl_id_list.sort()
# random.shuffle(tbl_id_list)

# Shuffule at first.
# random.shuffle(par_id_list)

prod_num = 0
time_num = 0
retry = True
max_value = -1

while retry:
    retry = False
    for i in range(0, 1000):
        time_num += 1

        # Random swap.
        size = len(par_id_list)
        index1 = random.randint(0, size-1)
        index2 = random.randint(0, size-1)
        # print("size={}, index1={}, index2={}".format(size, index1, index2))
        temp = par_id_list[index1]
        par_id_list[index1] = par_id_list[index2]
        par_id_list[index2] = temp

        mappings_df = new_mappings(tbl_id_list, par_id_list)

        participant_df = pd.read_csv(participant_file)

        pos_df = new_position(floor_df,
                              participant_df, mappings_df)

        """
        output
        ------

        X,Y,BLOCK,PARTICIPANT,TABLE,GENRE_CODE
        0,0,C,1,27,Red
        1,0,C,2,26,Red
        2,0,C,3,25,Blue
        3,0,C,4,24,Blue
        4,0,C,5,23,Green
        """
        pos_df.to_csv(position_file, index=False)

        # Evaluation
        value = evaluate(pos_df)
        print("Info    : i={}, Value={}, Max={}".format(i, value, max_value))

        if max_value < value:
            # Update and output.
            max_value = value
            new_html(pos_df, prod_num, time_num, max_value)
            new_csv(pos_df, prod_num, time_num)
            new_json(pos_df, prod_num, time_num, max_value)
            mappings_df.to_csv(best_mappings_file, index=False)
            pos_df.to_csv(best_position_file, index=False)
            retry = True
        else:
            # Cancel swap.
            temp = par_id_list[index2]
            par_id_list[index2] = par_id_list[index1]
            par_id_list[index1] = temp

print("Info    : Finished.")

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 あれっ、ループの中で ファイル読込してしまっている☆
遅いわけだぜ☆」

20190725blog52value409.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 評価値が 409 にもなると、ランダムでは 1000回 入れ替えても 評価値が上がらなかったぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 テーブル番号順で 同じ色が連続したら 評価値1点 追加しない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 評価関数が 机の数 分だけ重たくなるぜ☆ まあ O(n) なら軽微か……☆」

evaluation.py

def evaluate(pos_df):

    # 評価値
    value = 0

    # block_dict[block][genre_code] = value
    block_dict = {}

    for _index, row in pos_df.iterrows():
        # x = row["X"]
        # y = row["Y"]
        block = row["BLOCK"]
        # table_id = row["TABLE"]
        # participant_id = row["PARTICIPANT"]
        genre_code = row["GENRE_CODE"]

        if not(block in block_dict):
            block_dict[block] = {}

        if not(genre_code in block_dict[block]):
            block_dict[block][genre_code] = 0

        block_dict[block][genre_code] += 1

    # 集計。ブロックに同じ色が集まっているほど高評価。
    for _block_name, genre_code_dict in block_dict.items():
        for _genre_code_name, count in genre_code_dict.items():
            value += count ** 2
            break

    # 集計。テーブル番号順にして、同じ色が連続したら 1点加点。
    sorted_pos_df = pos_df.sort_values(by=["TABLE"], ascending=True)
    # print(sorted_pos_df.head(5))
    table_ordered_list = sorted_pos_df[["TABLE", "GENRE_CODE"]].values.tolist()
    # print("table_ordered_list: {}".format(table_ordered_list))
    prev_genre_code = None
    for entry in table_ordered_list:
        if prev_genre_code == entry[1]:
            value += 1
            # print("prev_genre_code: {}, entry[1]: {}, value: {}".format(
            #    prev_genre_code, entry[1], value))
        else:
            prev_genre_code = entry[1]

    return value

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 評価関数に 同じ色のテーブルが続いたら1点追加☆」

20190725blog53value458.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ランダムだと こんなところで止まるな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 2個つながっている黒のところに 青を持っていかないのは、入れ替えても 同点だからね。
連続していたら1点追加じゃなくて、連続していた数だけ追加 にしたら
もっと つながると思うわよ?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 細かい点 拾っていくの わらう☆」

    # 集計。テーブル番号順にして、同じ色が連続したら、連続した数だけ加点。
    continue_bonus = 0
    sorted_pos_df = pos_df.sort_values(by=["TABLE"], ascending=True)
    # print(sorted_pos_df.head(5))
    table_ordered_list = sorted_pos_df[["TABLE", "GENRE_CODE"]].values.tolist()
    # print("table_ordered_list: {}".format(table_ordered_list))
    prev_genre_code = None
    for entry in table_ordered_list:
        if prev_genre_code == entry[1]:
            continue_bonus += 1
            value += continue_bonus
            # print("prev_genre_code: {}, entry[1]: {}, value: {}".format(
            #    prev_genre_code, entry[1], value))
        else:
            prev_genre_code = entry[1]
            continue_bonus = 0

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 こんな感じで どうか☆?」

20190725blog54value620.png

KIFUWARABE_80x100x8_01_Futu.gif
「 良いんじゃないか、夢美☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 49のグレーと 19のスカイブルーが入れ替わって欲しいんだけど、
テーブル1つ1つずつのランダムじゃなくて、ジャンルコードが連続するテーブルの両端以外のテーブルは除いたあとでのランダムって
できないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 できるが、仕事帰りに ゆったりするはずの わたしの休みが 消し飛ぶ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ダメだ今日中に 終わんね☆
ランダムなスワップだけでは 評価関数で ごり押しするにも すぐ上限がくる☆
次回から ランダムをやめて 探索部を作り込んでいこうぜ☆」

のどがいたい

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ゲホッ☆ ゴホッ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 寝ろ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 探索部を書く前に、ブロックの中のジャンルコードの両端の2つの机、あるいは単独の1つの机を ピックアップするモジュールを作りたい☆
絵を描いて説明すると……☆」

20190726blog55a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 すべての机から ランダムに2つ選ぶのではなく、
上図の赤丸で示した机から ランダムに2つ選びたい☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 定義を緩めると、かんたんに実装できるわよ?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 連続するジャンルコードの 始端と終端、または 単独のジャンルコード を選べばいいのよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そうしよ……☆」

import os
import random
import pandas as pd
from my_lib.html_generator.css_builder import new_csv
from my_lib.html_generator.html_builder import new_html
from my_lib.html_generator.json_builder import new_json
from my_lib.entry_list import new_entry_lists_from_mappings
from my_lib.entry_list import read_entry_lists
from my_lib.mapper import new_mappings
from my_lib.position import new_position
from my_lib.build_floor_map import convert_floor_map
from evaluation import evaluate

# Location.
block_file = "./event-placement-ai/input-data/block.txt"
table_file = "./event-placement-ai/input-data/table.txt"
participant_file = "./event-placement-ai/input-data/participant.csv"
position_file = "./event-placement-ai/auto-generated/position-{}-{}-{}.csv"
floor_file = "./event-placement-ai/auto-generated/floor.csv"
best_mappings_file = "./event-placement-ai/auto-generated/best-mappings.csv"

# Read a floor.
floor_df = convert_floor_map(block_file, table_file)
floor_df.to_csv(floor_file, index=False)

participant_df = pd.read_csv(participant_file)

if os.path.isfile(best_mappings_file):
    tbl_id_list, par_id_list = new_entry_lists_from_mappings(
        best_mappings_file)
    # print("len(tbl_id_list): {}".format(len(tbl_id_list)))
    # print("len(par_id_list): {}".format(len(par_id_list)))
    # print("tbl_id_list: {}".format(tbl_id_list))
    # print("par_id_list: {}".format(par_id_list))

    genre_code_list = []
    for i in range(0, len(tbl_id_list)):
        temp_df = participant_df[participant_df.ID == par_id_list[i]]
        temp_df = temp_df['GENRE_CODE']
        # print(temp_df.head(5))
        # print("temp_df.values.tolist()[0]: {}".format(
        #    temp_df.values.tolist()[0]))
        genre_code_list.append(temp_df.values.tolist()[0])
    # print("len(genre_code_list): {}".format(len(genre_code_list)))
    # print("genre_code_list: {}".format(genre_code_list))
else:
    tbl_id_list, par_id_list, genre_code_list = read_entry_lists(
        floor_file, participant_df)
# print(&quot;Info    : Participants count: {}&quot;.format(len(par_id_list)))
# print(&quot;Info    : Table        count: {}&quot;.format(len(tbl_id_list)))

# テーブル番号を崩さずスキャンしたいので、ソートしない。
# tbl_id_list.sort()
# random.shuffle(tbl_id_list)

# Shuffule at first.
# random.shuffle(par_id_list)

prod_num = 0
var_num = 0
progress_num = 0
retry = True
max_value = -1


def pick_up_index_list(tbl_id_list, genre_code_list):
    """
    index_list = []
    for i in range(0, len(par_id_list)):
        index_list.append(i)
    return index_list
    """

    order_list = [0] * len(tbl_id_list)
    index = 0
    for tbl_id in tbl_id_list:
        order_list[tbl_id-1] = index
        index += 1

    # print("order_list: {}".format(order_list))

    index_list = []
    prev_genre_code = None
    prev_index = -1
    # 同じジャンルコードが連続しているところは、始点と終点だけを取る。
    for index in order_list:
        genre_code = genre_code_list[index]

        # print("prev_genre_code: {}, genre_code: {}".format(
        #    prev_genre_code, genre_code))
        if prev_genre_code == None:
            prev_genre_code = genre_code

            # Index of start.
            index_list.append(index)

        elif prev_genre_code != genre_code:
            prev_genre_code = genre_code
            # print("start: {}, end: {}".format(
            #    start, current-1))

            if index_list[len(index_list)-1] != prev_index:
                # Index of previous end.
                index_list.append(prev_index)

            # Index of start.
            index_list.append(index)

        prev_index = index

    # print("len(genre_code_list)-1: {}".format(len(genre_code_list)-1))
    index_list.append(order_list[len(order_list)-1])
    # print("index_list: {}".format(index_list))

    # # 並び順を崩さないようにすること。
    # # result = list(set(index_list))
    # # print("result: {}".format(result))
    return index_list


def choice_index():
    # Pick up table.
    picked_up_index_list = pick_up_index_list(tbl_id_list, genre_code_list)
    # print("picked_up_index_list: {}".format(picked_up_index_list))

    # Random swap.
    size = len(picked_up_index_list)
    index11 = random.randint(0, size-1)
    index12 = random.randint(0, size-1)
    index1 = picked_up_index_list[index11]
    index2 = picked_up_index_list[index12]
    # print("size={}, index1={}, index2={}".format(size, index1, index2))
    # print("Choiced index1={}, index2={}".format(index1, index2))
    return index1, index2


def swap_par(index1, index2, par_id_list, genre_code_list):
    """
    テーブルIDは固定し、参加者IDを入れ替えます。
    """
    temp_par_id = par_id_list[index1]
    temp_genre_code = genre_code_list[index1]

    par_id_list[index1] = par_id_list[index2]
    genre_code_list[index1] = genre_code_list[index2]

    par_id_list[index2] = temp_par_id
    genre_code_list[index2] = temp_genre_code
    return


while retry:
    retry = False
    for i in range(0, 1000):
        progress_num += 1

        index1, index2 = choice_index()

        swap_par(index1, index2, par_id_list, genre_code_list)

        mappings_df = new_mappings(tbl_id_list, par_id_list)

        pos_df = new_position(floor_df,
                              participant_df, mappings_df)

        # Evaluation
        value = evaluate(pos_df)
        print("Info    : i={}, Value={}, Max={}".format(i, value, max_value))

        if max_value < value:
            # Update and output.
            max_value = value
            new_html(pos_df, prod_num, var_num, progress_num, max_value)
            new_csv(pos_df, prod_num, var_num, progress_num)
            new_json(pos_df, prod_num, var_num, progress_num, max_value)
            mappings_df.to_csv(best_mappings_file, index=False)
            pos_df.to_csv(position_file.format(
                prod_num, var_num, progress_num), index=False)
            retry = True
        else:
            # Cancel swap.
            swap_par(index2, index1, par_id_list, genre_code_list)
            """
            temp = par_id_list[index2]
            par_id_list[index2] = par_id_list[index1]
            par_id_list[index1] = temp
            """

print("Info    : Finished.")

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ぜんぜん簡単ではなかった……☆」

20190727blog56a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 人工知能どころか 機械学習も無しの ただのアルゴリズムで 結構揃うものだ……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 黄色はもっと まとまるな☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ブロックで切れてないので、上図の黄色はつながっている☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ブロックで切りましょう!」

20190727blog58a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ一旦、初期配置をシャッフルするぜ☆
少しずつ良くしていくような最適化は、一度付いた癖は 直らないからな☆」

20190727blog58a3.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そして最適化されたのが これだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 白はもっと くっつきそうなものだが☆
赤も 極大 に登りあがってしまった☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 青、緑、黄 は なかなかのものじゃない?」

20190727blog58a4.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ 初期配置をまた シャッフルして……、って
ぜんぜん シャッフルされてないじゃないか☆!」

KIFUWARABE_80x100x8_01_Futu.gif
「 ぜんぜん テストもせずに エクステンド(増築)してるからな☆
結果の正当性も疑わしいものだぜ☆」

20190727blog58a5.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 少し異なるとか、同じとか、初期配置が どれほどの影響があるか分からないが、ランダム配置であることは重要だろう☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 1個浮いている緑は 橙色のところに移したいけど、そうすると橙色が離れてしまうから、
2か所の交換だけではなく、3か所同時交換 とか有効そうじゃない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ランダムな組み合わせが爆発して どうでもいいところで 3か所同時交換するばかりに なる気もするが……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 もっとスワップの精度を上げていきましょう! 例えば!」

20190727blog59a1.png

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 同じジャンルコード動詞で スワップ しても スワップしたことにならないので、
違う色動詞で スワップするようにしなさい」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 さすがご主人さま、細かいところを拾っていく……☆」

def choice_index():
    # Pick up table.
    picked_up_index_list = pick_up_index_list(tbl_id_list, genre_code_list)
    # print("picked_up_index_list: {}".format(picked_up_index_list))

    # リトライ回数が多すぎると、終わりたいときに、逆に終わらないかもしれない。
    retry = 3
    genre_code1 = None
    genre_code2 = None
    while genre_code1 == genre_code2 and 0 < retry:
        # Random choice at first.
        size = len(picked_up_index_list)
        index11 = random.randint(0, size-1)
        index1 = picked_up_index_list[index11]
        genre_code1 = genre_code_list[index1]

        # 同じ色はなるべく選ばない。
        index12 = random.randint(0, size-1)
        index2 = picked_up_index_list[index12]
        genre_code2 = genre_code_list[index2]
        retry -= 1

    # print("size={}, index1={}, index2={}".format(size, index1, index2))
    # print("Choiced index1={}, index2={}".format(index1, index2))
    return index1, index2

20190727blog60a1.png

20190727blog60a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なるほど、すごい速さで席替えが進むぜ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 しかし 緑が1個浮いている気がするが、くっつけなかったのかだぜ☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 10と55を ピンポイントで入れ替えるのは 確率が低いんじゃない?
それか 改造したコードがエンバグしたか」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 いったい どういう確率なのかも ページに表示したいよな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 JSONを Java Script で読み込んで、writeln したらどうだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 手間だが それが1番かだぜ☆」

placement-0-0-5412.json

{
    "test": 0,
    "variation": 0,
    "progress": 5412,
    "value" : 614
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 json(ジェイソン)は こんな感じでいいかだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 HTMLファイルから読めるか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 web-server を立ててたら読めるんだが、プログラマーでない読者に サーバー立てろとか言っても むずかしいだろうしな……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 HTMLファイルに JSONを直書きしたら?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 豪快だな……☆」

def new_json(test_number, variation_number, progress_num, value):
    return """
{{
    "test": {0},
    "variation": {1},
    "progress": {2},
    "value" : {3}
}}
            """.format(test_number, variation_number, progress_num, value)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ JSONのテキストを書く部分だけを、モジュールに切りだそう☆」

import pandas as pd


def write_json(test_number, variation_number, progress_num, json):
    # Location.
    json_file = "./event-placement-ai/auto-generated/placement-{}-{}-{}.json"

    try:
        file = open(json_file.format(
            test_number, variation_number, progress_num), 'w', encoding='utf-8')

        file.write(json)
    except Exception as e:
        print(e)
    finally:
        file.close()
    return


def new_json(test_number, variation_number, progress_num, value):
    return """
{{
    "test" : {0},
    "variation" : {1},
    "progress" : {2},
    "value" : {3}
}}
            """.format(test_number, variation_number, progress_num, value)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 京アニ爆発事件の生き残りも 1人減った☆ まだ分からなさそうだぜ☆
あたまに集中力が入らん☆
これだけ 書き直すのに 5時間ぐらいかかった……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 腰が入ってないな☆」

20190727blog62a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 このブログに画像貼り付けるのも 記憶が飛んでしまう☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 JSONを 直書きできてるじゃない。 十分、十分」

次の日

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もうプログラムするのも嫌だ☆(^~^) 仕事に行くのも嫌だぜ☆(^~^)」

KIFUWARABE_80x100x8_01_Futu.gif
「 いつものことじゃないか☆」

20190729blog63a1.png

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 この離れ離れになってるのは くっつけれないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 場所を入れ替えて 等価値 だったら 入れ替えないからな☆
ずれることもないし、動かないぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 入れ替えではなく、挿入だったら もっと かき混ぜれるのかだぜ☆? 例えば……☆」

20190729blog63a2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 同じブロックで 離れ離れ になっているブロックは 挿入でくっつけるとか☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 やれだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ まず シフト を実装しようぜ☆?」

participants = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
blocks = ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C']
print("participants: {}.".format(participants))
print("blocks: {}.".format(blocks))


def shift_smaller():
    """
    ブロック単位でシフトします。[1,2,3,4]を、[2,3,4,1]にする動きです。
    """

    prev_block = None
    # テーブルID順に並んでいるとします。
    for i in range(0, 10):
        print("i:{}, blocks[i]: {}, prev_block: {}.".format(
            i, blocks[i], prev_block))
        if prev_block == blocks[i]:
            # Swap.
            temp = participants[i-1]
            participants[i-1] = participants[i]
            participants[i] = temp

        prev_block = blocks[i]


shift_smaller()

print("participants: {}.".format(participants))
participants: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
blocks: ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C'].
i:0, blocks[i]: A, prev_block: None.
i:1, blocks[i]: A, prev_block: A.
i:2, blocks[i]: A, prev_block: A.
i:3, blocks[i]: B, prev_block: A.
i:4, blocks[i]: B, prev_block: B.
i:5, blocks[i]: B, prev_block: B.
i:6, blocks[i]: B, prev_block: B.
i:7, blocks[i]: C, prev_block: B.
i:8, blocks[i]: C, prev_block: C.
i:9, blocks[i]: C, prev_block: C.
participants: [2, 3, 1, 5, 6, 7, 4, 9, 10, 8].

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 こういうのは 小さなプログラムを書いて、まずテストだぜ☆」

def shift_bigger():
    """
    ブロック単位でシフトします。[1,2,3,4]を、[4, 1, 2, 3]にする動きです。
    """

    prev_block = None
    # テーブルID順に並んでいるとします。
    for i in reversed(range(0, 10)):
        print("i:{}, blocks[i]: {}, prev_block: {}.".format(
            i, blocks[i], prev_block))
        if prev_block == blocks[i]:
            # Swap.
            temp = participants[i]
            participants[i] = participants[i+1]
            participants[i+1] = temp

        prev_block = blocks[i]
participants: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
blocks: ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C'].
i:9, blocks[i]: C, prev_block: None.
i:8, blocks[i]: C, prev_block: C.
i:7, blocks[i]: C, prev_block: C.
i:6, blocks[i]: B, prev_block: C.
i:5, blocks[i]: B, prev_block: B.
i:4, blocks[i]: B, prev_block: B.
i:3, blocks[i]: B, prev_block: B.
i:2, blocks[i]: A, prev_block: B.
i:1, blocks[i]: A, prev_block: A.
i:0, blocks[i]: A, prev_block: A.
participants: [3, 1, 2, 7, 4, 5, 6, 10, 8, 9].

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 逆順もないと 戻せないよな☆」

def shift_smaller():
    """
    ブロック単位でシフトします。[1,2,3,4]を、[2,3,4,1]にする動きです。
    """

    prev_block = None
    # テーブルID順に並んでいるとします。
    for index, block in enumerate(block_list):
        # for index, row in floor_df.iterrows():
        if prev_block == block:
            swap_participant(
                index-1, index, par_id_list, genre_code_list)

        prev_block = block

    return


def shift_bigger():
    """
    ブロック単位でシフトします。[1,2,3,4]を、[4, 1, 2, 3]にする動きです。
    """

    prev_block = None
    index = len(block_list)-1
    # テーブルID順に並んでいるとします。
    for block in reversed(block_list):
        # print("shift_bigger: index={}, block={}.".format(index, block))
        if prev_block == block:
            swap_participant(
                index, index+1, par_id_list, genre_code_list)

        prev_block = block
        index -= 1

    return

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 pandas の API がトンチンカンなんで、結局リストに出してシフト☆」

20190729blog63a3.png

KIFUWARABE_80x100x8_01_Futu.gif
「 テーブル1個ずつのシフトではなく、かたまりで シフトしないとな☆ ごそっと☆」

また次の日

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 先頭から 連続するジャンルコードのテーブル数を数えるモジュールが欲しいな☆
名前は count_joined_genre_code とかかだぜ☆?」

20190730blog64a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 つまり 上図の赤丸のところを数えるんだぜ☆
10、4、14、1、8、4 みたいな感じ☆」

genre_code_list = ['green', 'green', 'blue', 'red', 'red',
                   'blue', 'yellow', 'black', 'black', 'black']
block_list = ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C']


def count_joined_genre_code():
    """
    TODO 同じブロック内での、連続するジャンルコードの数。
    """

    count = 0
    result_dict = {}
    prev_block = None
    prev_genre_code = None
    for idx in range(0, len(block_list)):
        block = block_list[idx]
        genre_code = genre_code_list[idx]
        if prev_block != block or prev_genre_code != genre_code:
            if prev_block not in result_dict:
                result_dict[prev_block] = []

            result_dict[prev_block].append(count)
            count = 1
        else:
            count += 1

        prev_block = block
        prev_genre_code = genre_code

    # last
    if prev_block not in result_dict:
        result_dict[prev_block] = []
    result_dict[prev_block].append(count)

    return result_dict


result_dict = count_joined_genre_code()
print("result_dict: {}.".format(result_dict))
result_dict: {None: [0], 'A': [2, 1], 'B': [2, 1, 1], 'C': [3]}.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 サンプル・プログラムを作って試しながら 動くまで持っていくのが 開発だぜ☆
作っているプログラムに いきなり拡張するのは テストがしにくいからな☆」

次の次の次の日

20190731blog65a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 先頭の10個抜いて、うしろを 10個詰めて、空いた10個のところに先頭の10個を埋めたいぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 また、それをアンドゥする動きも欲しいよな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 スワップを使ってばかりではなく、スタックとムーブをそろそろ作るべきでは☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 うっ、ループ書くの 苦し……☆」

participants = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
blocks = ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B']
print("participants: {}.".format(participants))
print("blocks: {}.".format(blocks))


def for_block_asc(callback_head_block, callback_same_block):
    """
    ブロックの切れ目が分かるループです。昇順。
    """
    # テーブルID順に並んでいるとします。
    prev_block = None
    for i in range(0, len(blocks)):
        if prev_block == blocks[i]:
            callback_same_block(i, blocks[i])
        else:
            callback_head_block(i, blocks[i])
        prev_block = blocks[i]
    return


def for_block_desc(callback_tail_block, callback_same_block):
    """
    ブロックの切れ目が分かるループです。降順。
    """
    # テーブルID順に並んでいるとします。
    prev_block = None
    for i in reversed(range(0, len(blocks))):
        if prev_block == blocks[i]:
            callback_same_block(i, blocks[i])
        else:
            callback_tail_block(i, blocks[i])
        prev_block = blocks[i]
    return


print("Info    : for_block_asc.")
for_block_asc(
    lambda i, block:
        print("Head: i={}, block={}.".format(i, block)),
    lambda i, block:
        print("Same: i={}, block={}.".format(i, block))
)

print("Info    : for_block_desc.")
for_block_desc(
    lambda i, block:
        print("Tail: i={}, block={}.".format(i, block)),
    lambda i, block:
        print("Same: i={}, block={}.".format(i, block))
)

print("Info    : Finished.")
participants: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
blocks: ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B'].
Info    : for_block_asc.
Head: i=0, block=A.
Same: i=1, block=A.
Same: i=2, block=A.
Same: i=3, block=A.
Same: i=4, block=A.
Same: i=5, block=A.
Same: i=6, block=A.
Same: i=7, block=A.
Head: i=8, block=B.
Same: i=9, block=B.
Info    : for_block_desc.
Tail: i=9, block=B.
Same: i=8, block=B.
Tail: i=7, block=A.
Same: i=6, block=A.
Same: i=5, block=A.
Same: i=4, block=A.
Same: i=3, block=A.
Same: i=2, block=A.
Same: i=1, block=A.
Same: i=0, block=A.
Info    : Finished.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ループのコードは 関数に隠してしまうかだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 block_list とか tbl_id_list のような よく使うリストを ひとかたまりにできないかだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 それこそ position クラスに まとめられないのかだぜ☆?」

position-0-0-666.csv

X,Y,BLOCK,TABLE,PARTICIPANT,GENRE_CODE
13,5,A,1,57,Green
14,5,A,2,10,Green
15,5,A,3,53,Green

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 pandas が扱いやすければ 何も工夫しなくていいんだが、 API がトンチンカンだからな……☆
position クラスを自作するしかないのか……☆」

<書きかけ>

ツイッターでシェア
みんなに共有、忘れないようにメモ

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント