はじめに
Paizaで「電脳少女プログラミング2088|壊レタ君を再構築」というプログラミングゲームができるみたいです。
普通に解くのでもよいのですが、今回は解答を1行のプログラムで作成してみようと思います。
こちらのリンクからプレイすることができます。
問題はEランクからSランクまで難易度が分かれています。
今回はDランクからBランクまでの課題の1行解法について、簡単な解説を交えながら紹介します。
テクニック
1行コーディングをするためのテクニックをいくつか紹介します。1行コーディングについては「ワンライナー」と調べるといろいろ出てきます。
リスト内包表記
for文をリストの中で回す記法です。
詳しくは以下の記事が参考になります。
三項演算子
if文を使う時には三項演算子が便利です。
こちらの記事が参考になります。
セイウチ演算子
変数を1行の中で使用するテクニックとして、Python 3.8から使えるようになったセイウチ演算子というものがあります。
これは実行と使用を同時にできるものです。
こちらの記事が参考になります。
ラムダ式
関数を1行で記述する記法です。
これを使いこなすとほぼすべてのコードを1行で書けるようになります。
詳しくはこちらの記事が参考になります。
実は、Pythonでは;
で文を区切ることができるので、普通にプログラムを書いた後に改行を;
に置き換えてしまえば1行でコーディングできてしまいます。
また、文字列をPythonのコードとして実行することができるexec()
というものもあります。
ですが、それでは楽しくないので今回はそれらは使わないことにします。
解答・解説
郊外のスラム街(Dランク)
入力を受け取って簡単な計算をするだけです。
print(int(input())//2+100)
カジノ(Dランク)
リスト内包表記を使います。
print(sum([int(input())*i for i in [1,5,10]]))
ネオン街の裏路地(Dランク)
これもリスト内包表記を使えば簡単に書けます。
print(max([int(input()) for i in range(int(input()))]))
ネオン街のクラブ(Cランク)
種類の数はsetに変換してlen()をとるだけですね。
print(min(int(input()),0)+len(set([i for i in input()])))
最初のmin(int(input()),0)
は1行目が要らないので捨ててるだけです。
自然の残る公園(Cランク)
そろそろ変数を使わないと厳しそうです。
セイウチ演算子を使って、現在地の座標を変数に保存します。
now:=list(map(int,input().split()))
また、Pythonではmin()やmax()、sorted()などに引数としてkeyを指定することができます。結果として得たいものと違うものを比較することができるので使い勝手が良いです。
結果としてはインデックスを取得したいので、第一引数にrange(1,now[0]+1)を指定し、keyに現在地とビーコンの距離を与えます。
以下が最終的なコードです
print(min(range(1,(N:=list(map(int,input().split())))[0]),key=lambda x: ((p:=list(map(int,input().split())))[0]-N[1])**2+(p[1]-N[2])**2))
廃マンションの一室(Cランク)
少し問題が分かりづらいので一度普通に書いてみましょう。
普通のN進数の要領で下の桁から余りを出していき、もし余りが2なら-1にして次の位を一つ繰り上りをすればよいです。
N = int(input())
ans=""
while N!=0:
N, m = N // 3 ,N % 3
if m == 2:
N += 1
ans = str(m) + ans
print(0 if ans == "" else ans)
これを1行にしていきましょう。
しかし、whileをこのままリスト内包表記にはできません。そのため、以下のようにfor文に書き直します。
''.join(["" if n == 0 else(str(n % 3 if L.append(n//3)==None else n%3) if n % 3 != 2 else (str(n % 3 if L.append(n//3+1)==None else n%3))) for n in L])[::-1]
最終的に以下のようなプログラムになります。
print((lambda N: '0' if N == 0 or (len(L:=[N]) and False) else ''.join(["" if n == 0 else(str(n % 3 if L.append(n//3)==None else n%3) if n % 3 != 2 else (str(n % 3 if L.append(n//3+1)==None else n%3))) for n in L])[::-1])(int(input())))
ギャングのアジト(Bランク)
まず、三項演算子を使用して出力の形を作ります
print("Yes" if (******) else "No")
入力は以下の形で取得できます
[map(int,input().split()) for i in range(int(input())]
ここで、1行ずつリストとリストの逆順が等しいかを確認すればよいです。
全ての要素がTrueであるかはall()で取得できるので、以下のように記述することができます。
all(l==l[::-1] for l in [list(map(int,input().split())) for i in range(int(input()))]))
よって、以下のコードが解答となります。
print("Yes" if (all(l==l[::-1] for l in [list(map(int,input().split())) for i in range(int(input()))])) else "No")
ちなみに、各要素は0か1なので、リストではなく文字列として受け取っても動きます。
print("Yes" if (all(l==l[::-1] for l in [input() for i in range(int(input()))])) else "No")
一番通りの繁華街(Bランク)
1点(x1,y1)と辺の長さSを全探索し、4点(x1,y1),(x1+S,y1),(x1,y1+S),(x1+S,y1+S)全てにアジトがあるものを数えればよいです。N<=50なので十分間に合います。
まず、入力をセイウチ演算子で変数に代入します。(min(xxx,0)
とすることで最終的に答えと合わせて出力しても答えが変わらないようにしています。)
min(N:=int(input()),0)+min(len(S:=list(input() for i in range(N))),0)
次に、三重ループで全探索します。
多重ループのリスト内包表記では、後に書いた方が内側になります。条件に合うものを数えるときには、ifを用いたリスト内包表記を使うと便利です。
よって、答えはこのようになります。
sum([1 for i in range(N) for j in range(N) for k in range(1,N-max(i,j)) if (S[i][j]==S[i+k][j]==S[i][j+k]==S[i+k][j+k]==".")])
入力部分と組み合わせて、最終的に以下のようなコードになりました。
print(min(N:=int(input()),0)+min(len(S:=list(input() for i in range(N))),0) + sum([1 for i in range(N) for j in range(N) for k in range(1,N-max(i,j)) if (S[i][j]==S[i+k][j]==S[i][j+k]==S[i+k][j+k]==".")]))
さいごに
「電脳少女プログラミング2088 | 壊レタ君を再構築」のDランクからBランクまでの問題を1行で解いてみました。
1行でプログラムを書くのは頭を使うので、ぜひ力試しに挑戦してみてはいかがでしょうか。
Aランク・Sランクの問題にもぜひ挑戦してみてください!私は力尽きました...