PythonでLLMしか動かしたことがない自分が電脳少女を修復する

# はじめに
この記事は、以下のサイトの問題をほぼ初心者独学の自分が解いてみたときの感想をまとめたものです。
特にルールにはなさそうですが、勝手にAI使用禁止縛りでやっています。
そのため、いろいろ見るに堪えないコードが並ぶと思いますがどうか温かい目でお読みくださるとうれしいです。

https://paiza.jp/entry/denno2088_qiita

:::note warn
記憶に残っているものをピックアップして話すので、すべての問題には触れません。
:::

# カジノ（paizaランクD相当）
ガチで基礎的な問題ですね。
この問題は、カジノのチップ枚数が1ドル・5ドル・10ドルの順で与えられ、そこから合計金額を計算して出力するみたいな内容です。
```py:私が書いたコード
# coding: utf-8
#input_line 入力入れる配列
input_line = []
for i in range(3): #三回繰り返して全部の入力を配列に代入
    input_line.append(input())

#計算して出力
print(int(input_line[0])+int(input_line[1])*5+int(input_line[2])*10)
```
## 自分の書いたコードについての感想
悪くない気がします。配列使わずに直接変数に加算するほうがいいような気がしますが、まぁそこまで変わらないでしょ。多分。

## 結果
提出コードバイト数
211byte
| ケース | 実行時間 |
|:-:|:-:|
| Test case 1  | 0.04秒  |
| Test case 2  | 0.01秒  |
| Test case 3  | 0.01秒  |
| Test case 4  | 0.02秒  |
| Test case 5  | 0.02秒  |

得点は100点。
電脳少女が言うには、「もっとエレガントに書けるんじゃない？」とのこと。
int()を使いすぎたのが原因かな？

# 自然の残る公園（paizaランクC相当）
普通に難しいと感じました。でも、手が付けられないほどではなくて、ちょうど解けたら気持ちいいぐらいの感じ。
自分の腕試し的な気持ちで取り組みました。
この問題は、各地に散らばるビーコンの中から、現在地に一番近いビーコンを見つけるみたいな内容です。

```py:私が書いたコード
# coding: utf-8

# information ビーコン数、現在地を代入する配列
# ビーコンの数  information[0]
# 現在地_Y座標  information[1]
# 現在地_X座標  information[2]
information = []
information = input().split()

# beacon 番号付きビーコン位置を代入する配列
# ビーコン番号  beacon[0]
# ビーコン_Y座標  beacon[1]
# ビーコン_X座標  beacon[2]
beacon = []
for i in range(int(information[0])):
    temp = input().split()
    beacon.append([i+1, int(temp[0]), int(temp[1])])

# most_near_beacon 最も近いビーコンの番号と計算結果
# ビーコン番号 most_near_beacon[0]
# 計算結果 most_near_beacon[1]
most_near_beacon = [None, float('inf')] #初期値は無限大にする

# 比較開始
# 計算式：(ビーコンの x 座標 - 現在地の x 座標 ) ^ 2 + (ビーコンの y 座標 - 現在地の y 座標) ^ 2
for i in beacon:
    temp = ((i[2]-int(information[2]))**2)+((i[1]-int(information[1]))**2)
    if most_near_beacon[1] > temp:
        most_near_beacon = [i[0], temp]

#出力
print(most_near_beacon[0])
```
## 自分の書いたコードについての感想
混乱しそうだったのでゴリゴリにコメントを書きまくり、コメントの行数とプログラムの行数が同じくらいになっています。
何でこの計算式で求められるのかよくわからないのでもやもやしていますが、一応動きます。（計算式は問題文そのままです）
多分配列beaconとか必要ないんだろうなーとか思いましたが、短縮しすぎるのもミスになると思ったので分けました。
こういうの書くのって慣れが必要なんでしょうか。

## 結果
提出コードバイト数
1000byte
| ケース | 実行時間 |
|:-:|:-:|
| Test case 1  | 0.02秒  |
| Test case 2  | 0.02秒  |
| Test case 3  | 0.02秒  |
| Test case 4  | 0.02秒  |
| Test case 5  | 0.01秒  |

得点は100点。
電脳少女が言うには、「変数名とか冗長じゃない？」とのこと。
うーん。やっぱり命名規則決めたほうがいいんですかね。
それにしても電脳少女がレビューをしてくれるの嬉しくてモチベわきますね。
自分は「毒舌メイド」の性格が好みですね。

# 会員制ジム（paizaランクC相当）
SQLはすっごい昔に触ったことあったんですが、その記憶はどこかに抜け落ちて、完全に初心者みたいな気持ちで書きました。(SELECT文の書き方から調べるレベル)
この問題は、memoryテーブルから、重要度が3以上カテゴリ名称が「悲しみ」に該当する記憶IDと会話内容を取得するみたいな内容です。
```sql:私が書いたコード
SELECT memory.id,memory.talk
FROM memory
INNER JOIN category
ON memory.category_id = category.id
WHERE memory.importance >=3
AND category.name = "悲しみ";
```
## 自分の書いたコードについての感想
よくわかんないっす。多分誰が書いても同じようなコードになる気がします。
自分頑張ったなぁ（しみじみ）

## 結果
得点は100点。
電脳少女が言うには、「まぁ、あんたにしては上出来じゃない？」とのこと。
出力に少女が体験したであろう記憶が出てるんですが......なかなかに壮絶な過去だったようで。
これ、忘れさせたままの方が良かったのでは？

# ネオン街のクラブ（paizaランクC相当）
やはりCランクは楽しい。ここがちょうど自分の実力って感じだと思います。
この問題は、箱の中に何種類のクッキーが入っているか出力するみたいな内容です。
```py:私が書いたコード
# coding: utf-8
import unicodedata #一応半角全角変換しておく

# how_many_cookies クッキーの総数
how_many_cookies = int(input())
# cookies 全てのクッキーが入る配列
cookies = list(unicodedata.normalize('NFKC',input()))
# same_cookies 被ったクッキーを残す配列
same_cookies = []

for i in cookies: #クッキー一つ一つに処理をする
    if i not in same_cookies: #既に処理した種類のクッキーは飛ばす
        temp = cookies.count(i)
        if temp > 1:
            how_many_cookies = how_many_cookies - temp + 1
            same_cookies.append(i)
print(how_many_cookies)
```
## 自分の書いたコードについての感想
無駄な処理を省くよう気を付けたつもりです。ただNの範囲が1~100なので、別に気を付ける必要性もなさそうですが。ランキングみると30byteとかいうのがあるんですが......何をすればそうなるんだ。（恐怖）

## 結果
618byte
| ケース | 実行時間 |
|:-:|:-:|
| Test case 1  | 0.01秒  |
| Test case 2  | 0.02秒  |
| Test case 3  | 0.01秒  |
| Test case 4  | 0.02秒  |
| Test case 5  | 0.02秒  |

得点は100点。
電脳少女が言うには、「もうちょっとシンプルにできそうな気がしますよー。setを使えば一発じゃないですか？」とのこと。
setってなんだ......？と思ったので調べてみると、「重複を許さない型」とのこと。
setを使って書くなら、以下のようにコードを短縮できそうです。(ChatGPTで生成)
```py:ChatGPTに手直ししてもらったコード
import unicodedata

# クッキーの総数を取得
how_many_cookies = int(input())

# クッキーのリストを取得して正規化
cookies = list(unicodedata.normalize('NFKC', input()))

# 重複するクッキーの種類をカウント
unique_cookies = set(cookies)

# 総数から重複したクッキーの個数を調整
how_many_cookies = how_many_cookies - (len(cookies) - len(unique_cookies))

print(how_many_cookies)
```
こんな便利なものがあるなんて知らなかった......

# 廃マンションの一室（paizaランクC相当）
〇進数の計算が世界一苦手な自信があります。基本情報技術者試験でも苦戦した思い出......
この問題は、10進数を特殊なルールの3進数に変換するという内容です。
三進数への変換には以下のnoteのコードをめちゃくちゃ参考にさせてもらいました。

https://note.com/omori55/n/n28850ec84c0e

```py:私が書いたコード
# coding: utf-8
#通常の三進数では012を使用するが、今回は2がマイナスの意味を持つ
#三進数変換の方法を改良する必要がある（余りが2なら次の桁に繰り上げる？）

# input_number 入力された値（10進数）
input_number = int(input())
# output_number 出力する値（特殊な3進数）
output_number = ""

# 3進数に変換
if input_number == 0: #入力が0なら出力は0
    output_number = "0"
else:
    # sho 割り算の商
    sho = input_number
    # digits 各桁の値を入れる配列（逆順なことに注意）
    digits = []
    # 商が0になるまで繰り返す
    while sho != 0:
        # amari 割り算のあまり
        amari = sho % 3
        sho=sho//3
        if amari == 2: #余りが2の場合
            sho = sho + 1 #商を繰り上げる
        digits.append(str(amari)) #桁を追加
    digits.reverse() #逆順なので反転させる
    output_number = "".join(digits)

print(output_number)
```
## 自分の書いたコードについての感想
コメントの量からして私の迷いが伝わってくると思います。
よくわからないけどいろいろ弄ってたらできたって感じです。問題理解から躓いたので結構きつかった......

## 結果
提出コードバイト数
999byte
| ケース | 実行時間 |
|:-:|:-:|
| Test case 1  | 0.02秒  |
| Test case 2  | 0.02秒  |
| Test case 3  | 0.01秒  |
| Test case 4  | 0.02秒  |
| Test case 5  | 0.01秒  |

得点は100点。
電脳少女が言うには、「コードの出来はまぁまぁってところですね。」とのこと。
毒舌メイドの性格にしているのでこれはめっちゃ褒められてると思います。

# ギャングのアジト（paizaランクB相当）
難しいですが、ギリ何とかなりそう。
この問題は、ピクセルアートが左右対称かどうか判定するという内容です。
```py:私が書いたコード
# coding: utf-8
# art_size ピクセルアートの一辺のサイズ
art_size = int(input())

# input_art 入力されたピクセルアートの配列 
input_art = []
for i in range(art_size): #二次元配列にピクセルアートを代入
    input_art.append(list(input().replace(' ', '')))

# left_art 入力の半分より左側のピクセルアート
left_art = []
# right_art 入力の半分より右側のピクセルアート
right_art = []

if art_size % 2 == 0: #偶数なら
    half_art_size = int(art_size/2)
    for i in input_art:
        left_art.append(i[:half_art_size])
        right_art.append(i[half_art_size:])
else: #奇数なら
    half_art_size = int((art_size-1)/2)
    for i in input_art:
        left_art.append(i[:half_art_size])
        right_art.append(i[half_art_size+1:])

for i in range(len(right_art)):
    right_art[i].reverse()

if left_art == right_art:
    print("Yes")
else:
    print("No")
```
## 自分の書いたコードについての感想
スライスって有能だなって思いました。自分のコードは結構きれいにまとまったと思います。配列使いすぎ感は否めないですが。
スライスで逆順にする方法もあるようですが、二次元配列でどう生かせばいいか分からなかったので普通にfor文で乗り切りました。

## 結果
提出コードバイト数
937byte
| ケース | 実行時間 |
|:-:|:-:|
| Test case 1  | 0.01秒  |
| Test case 2  | 0.01秒  |
| Test case 3  | 0.02秒  |
| Test case 4  | 0.02秒  |
| Test case 5  | 0.02秒  |

得点は100点。
電脳少女が言うには、「なかなかやるじゃないですか。でも、もう少し効率的にできそうですねー。」とのこと。
うーん。どこを改善すればいいんでしょうか？
特にヒントをくれなかったので、自分が書いたコードをそのままChatGPTに投げてみました。
```py:ChatGPTが書き直したコード
# coding: utf-8
art_size = int(input())

# 各行ごとに左右対称かをチェックする
symmetric = True
half = art_size // 2  # 奇数の場合は中央の文字は無視される

for _ in range(art_size):
    # 空白を除去して1行分のピクセルアートを取得
    row = input().replace(' ', '')
    # 左側と右側（逆順）の部分を比較
    if row[:half] != row[-half:][::-1]:
        symmetric = False
        break

print("Yes" if symmetric else "No")
```
なるほど。確かに左右対称を判定するだけであれば一行ずつ判定するだけでいいですね。そっちの方がfor文の節約につながります。
しかも一次元配列なので、いろいろと処理が簡単になって楽ですね。

# 終わりに
え？Sランクの問題？そっ閉じしましたよ。私の頭ではたとえ100人集まっても無理と悟りました。何ですか、マンハッタン距離って。
ということでこの記事はここまで。これまでプログラミング問題を解いたことがなかったので不安でしたが、実際やってみると楽しく解くことができました。
不正解でも電脳少女がヒントを出してくれるので、初心者でも楽しく進めることができると思います。
是非まだやっていない方は、「電脳少女プログラミング2088-壊レタ君を再構築-」をやってみてください。

https://paiza.jp/entry/denno2088_qiita

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/f8eae1c7-6a95-fc2d-0b08-687fee703762.png)
↑最終的に出来上がった電脳少女。（かわいい）