プログラミング上達講座4：ピクセルロジック

プログラミング上達講座の4回目です。

ピクセルロジックを題材にして
プログラムを考えてみましょう。

解説動画はこちら

[![表示されなかったらすみません](https://img.youtube.com/vi/V895qH8yqYs/0.jpg)](https://youtu.be/V895qH8yqYs)


## ピクセルロジックとは

ピクセルロジックご存知でしょうか？

結構昔からあるゲームで
やったことがある人も多いんじゃないかと。

一応のルールは
縦横の数値の数だけマスを黒く塗るゲーム。

数値の分だけ連続して塗られ
数値が分かれているところは
最低でも1マス以上白マスが有る。

全てのマスを正しく塗ることができたら
絵が完成する。

例えば 5 x 5マスの問題で1つの行の数値が
2  2であれば■■□■■という風になる。

数値の通りにマスを塗っていけば
良いわけです。


### 初級編:塗りつぶされたマスのチェック関数を作る

一行に塗りつぶされたマスが何マスあるか数えて
数値を出力する関数`check_row`を作成してみましょう。

イラストロジックのように白マスが間に来たら数値を分けること。

出力は数値のリスト型

```python
check_row(行のデータ):
    return 数値のリスト
```

例：

```python
check_row('□■□■□■□')
```
1 1 1





### 中級編:

画像からイラストロジックの問題を作成するプログラムを考えてみよう。

画像の入力データは白黒マスを文字列要素としたリスト型とする。
なお入力データは Nマス x Nマスの正方形とする。

下記のような画像データの場合

```python
data = [
'□□■■■■□□',
'□■■□□■■□',
'■■□□□□■■',
'■■■■■■■■',
'■■□□□□□□',
'■■□□□□■■',
'□■■□□■■□',
'□□■■■■□□']

N = 8
```

出力例は

<img width="399" alt="pix.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379626/517586a3-621a-9561-2164-55d29d3d84bd.png">


## 解答編

### 初級編の解答

1個ずつ最初から黒マスの個数を数えていく。

黒マスが続く場合は+1　
白マスが来た時に、前が黒マスなら数値を記録し
最後のマスが黒マスなら数値を記録。

`□■■■■□□□ 4`
`□■■■■□□■ 4 1`

```python
# 黒マスが何個あるかをチェックする
def check_row(row):
    res,checked,count = [],0,0
    while True:
        if row[checked]=='■':
            count+=1
        elif count!=0:
            res.append(count)
            count=0
        checked+=1
        if checked==len(row):
            if count!=0:
                res.append(count)
            break
    return res
​
check_row('□□□■□■■■□□■■■■■■■□□□')
```
[1, 3, 7]



### 中級編の解答

行方向と列方向で分けて黒マスの数え上げの結果を出しておく。

出力するものを考える場合は
先に列方向の数値を書き出し、後で行方向の数値を書き出す。

繋げたものを文字列として出力する(タブ区切り)

```python
data = [
'□□■■■■□□',
'□■■□□■■□',
'■■□□□□■■',
'■■■■■■■■',
'■■□□□□□□',
'■■□□□□■■',
'□■■□□■■□',
'□□■■■■□□']

N = len(data)

# 黒マスが何個あるかをチェックする
def check_row(row):
    res,checked,count = [],0,0
    while True:
        if row[checked]=='■':
            count+=1
        elif count!=0:
            res.append(count)
            count=0
        checked+=1
        if checked==len(row):
            if count!=0:
                res.append(count)
            break
    return res

# 行列の結果を格納する
result1,result2 = [],[]

# row方向
for row in data:
    tmp = check_row(row)
    result1.append(tmp)

# 列方向
for x in range(N):
    col = []
    for y in range(N):
        col.append(data[y][x])
    tmp = check_row(col)
    result2.append(tmp)

# 出力用の関数を作る
def make_num_data(res1,res2,num):
    row_len = max([len(r) for r in res1])
    col_len = max([len(c) for c in res2])
    row_num = row_len + num
    res_data = []
    
    # 先に列方向の出力データを作る
    for c in range(col_len):
        tmp = ['　'] * row_len
        for x in range(num):
            if len(res2[x])-1>=c:
                tmp+=[str(res2[x][c])]
            else:
                tmp+= ['　'] 
        res_data.append(tmp)

    # 行方向のデータをつなげる
    for n in range(num):
        tmp = []
        for r in range(row_num):
            if len(res1[n])-1>=r:
                tmp+=[str(res1[n][r])]
            else:
                tmp+= ['　']
        res_data.append(tmp)
    return res_data

# 出力用のデータを作成する
d = make_num_data(result1,result2,N)

# 出力
for y in d:
    print('\t'.join(y))
```
<img width="399" alt="pix.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379626/517586a3-621a-9561-2164-55d29d3d84bd.png">　	　	　	　	　	　	　
## 上級編

イラストロジックを解くプログラムを作ってください。

自分は時間がないので、お手上げでしたwww。

暇な方はぜひチャレンジしてみてください。


## まとめ

イラストロジックは問題を作るところと
問題を解くところ、両方の醍醐味があります。

問題を解くには効率の良い探索プログラムを書かないと
マス目が大きくなった時に解けなくなってきてしまうので
実装には時間がかかるんじゃないかなーと思いました。

時間ができたらチャレンジしたいですね。

それでは。

## 作者の情報

乙pyのHP：
http://www.otupy.net/

Youtube：
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw

Twitter：
https://twitter.com/otupython