質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

4回答

279閲覧

Python3 指示通り計算できるプログラム 条件分岐

python3_beginer

総合スコア46

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/04/09 10:57

目標)
ボードゲームをつくりたい
二人用のゲームで、財産 0 からスタートとして、ゴール時点の財産を比較する
それぞれプレイヤー1、2と呼び、彼らの財産にコンピュータの指示通りに
数を代入、増加、減少、させる。

指示の出し方は、コンピューターが、N回分 以下の3種類あるうちの一つずつ出す。

プレイヤー1: a = 0
プレイヤー2: b = 0

三種類の指示の説明

① IN i A : プレイヤー i に値 A を代入する (i = 1, 2)
② Add A :「プレイヤー 1 の値 + A」を計算し、計算結果をプレイヤー 2 に代入する
③ Sub A :「プレイヤー 1 の値 - A」を計算し、計算結果をプレイヤー 2 に代入する

入力例1
3
IN 1 10
IN 2 20
Add 40

出力例1
10 50

入力例2
3
IN 1 -23
Sub 77
IN 1 0

出力例2
0 -100

考え方)

N回分の異なる指示をdataにまとめ、リストに入れる。

リストの第一項indexをもとに、条件分岐を行う

最後に、a,bの数をもとめる

期待値を取得できたが、以下の問題を処理したい。

問題)

N回分の異なる指示をdataにまとめ、リストに入れる。
入力例のように、文字列、数字が混在するため、文字列としてリスト作成。

入力例
IN 1 10

条件分岐の中身で、リストの中身の一部を数字として扱いたい。
その都度、int()を利用するため面倒。

コード N = int(input()) data = [input().split() for x in range(N)] a=0 b=0 for x in range(N): if (data[x][0] == 'IN'): if (data[x][1] == '1'): a = int(data[x][-1]) elif (data[x][1] == '2'): b = int(data[x][-1]) else: pass elif (str(data[x][0]) == 'Add'): b = int(a) + int(data[x][-1]) else: b = int(a) - int(data[x][-1]) print(a,b)

また、ループの部分を関数でまとめて、map()で実行したいが、結果が異なってしまう。

コード N = int(input()) data = [input().split() for x in range(N)] a = 0 b = 0 def computer(): for x in range(N): if (data[x][0] == 'SET'): if (data[x][1] == '1'): a = int(data[x][-1]) elif (data[x][1] == '2'): b = int(data[x][-1]) else: pass elif (str(data[x][0]) == 'ADD'): b = int(a) + int(data[x][-1]) else: b = int(a) - int(data[x][-1]) print(a,b) result = map(computer,data)

よりスマートな書き方があればアドバイスお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

平易に組んでみました。行毎の指示を関数で処理する例です。

Python

1# 1行の指示 2def command( params, players): 3 op = params[0] 4 vals = [int(v) for v in params[1:]] 5 if op == 'IN': 6 players[vals[0]-1] = vals[1] 7 elif op == 'Add': 8 players[1] = players[0] + vals[0] 9 elif op == 'Sub': 10 players[1] = players[0] - vals[0] 11 12# 入力 13N = int(input()) 14data = [input().split() for x in range(N)] 15 16# N回の指示どおり処理 17players = [0,0] # a,b 18for d in data: 19 command( d, players) 20 21print(players)

投稿2018/04/09 13:42

can110

総合スコア38260

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

python3_beginer

2018/04/09 14:51

お返事頂きありがとうございます。 シンプルで美しいコードですね。コードの中にコメント付きで説明もあり、初心者の私に分かりやすくかつウ美しいコードを読めてとても嬉しいです。 ご指導ありがとうございます。
guest

0

ベストアンサー

型変換は簡単にできます。ループも色々スマートにして書き直してみました。

python

1N = int(input()) 2 3data = [input().split() for x in range(N)] 4data = [[line[0]] + [int(x) for x in line[1:]] for line in data] 5 6a=0 7b=0 8for x in data: 9 if x[0] == 'IN': 10 if x[1] == 1: 11 a = x[-1] 12 elif x[1] == 2: 13 b = x[-1] 14 else: 15 pass 16 elif x[0] == 'Add': 17 b = a + x[-1] 18 else: 19 b = a - x[-1] 20 21print(a,b)

mapに関しては、まだよく理解されていないみたいですね。mapはリストの各要素に対して同じ関数を適用するものです。たとえば、次のように使います。

python

1>>> list(map(lambda x:x*x, [1,2,3,4,5])) # 1,2,3,4,5のニ乗を計算 2[1, 4, 9, 16, 25]

前の結果を引き継いで処理したい場合、mapは向いていません(というか基本的に使えない)。mapや内包表記が効いてくるのは、ぜんぶの要素に対して独立に同じ処理をする場合です。
今回のケースであれば、まあ敢えて関数型ライクに書くとしたらreduceが使えなくはないかもしれませんが、普通にループ書くのがいちばんスマートだと思います。

投稿2018/04/09 11:17

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

arch_

2018/04/09 12:48

クラスを使用することで、内部状態の変化をクラスにまとめ、mapを適用できるコードを作成しました。
python3_beginer

2018/04/09 14:45

お返事頂きありがとうございます。 型変換はこんなに風にできるんですね。美しいですね。 data = [input().split() for x in range(N)] data = [[line[0]] + [int(x) for x in line[1:]] for line in data] また、ループ内処理もスマートで気持ちがいいですね。 追記のmap()の習熟度ですが、ご指摘とおりまだ理解度が低いと思います。 mapや内包表記が効いてくるのは、ぜんぶの要素に対して独立に同じ処理をする場合を再認識できました。ご指導ありがとうございました。
guest

0

クラスを使うのが自然な考え方な気がします。

Python

1class Status: 2 def __init__(self): 3 self.player = [0, 0] 4 5 def s_in(self, i, v): 6 self.player[i-1] = v 7 8 def s_add(self, v): 9 self.player[1] = self.player[0] + v 10 11 def s_sub(self, v): 12 self.s_add(-v) 13 14 15n = int(input()) 16 17s = Status() 18op_dict = { 19 'IN': s.s_in, 'Add': s.s_add, 'Sub': s.s_sub 20} 21 22for _ in range(n): 23 op, *value = input().split() 24 value = [int(e) for e in value] 25 26 op_dict[op](*value) 27 28print(*s.player)

Wandbox


また、ループの部分を関数でまとめて、map()で実行したいが、結果が異なってしまう。

関数の内部で使っているaと、外部で使っているa別物だからです。
global文を用いるか(非推奨)、ミュータブルなオブジェクトで値を保管すれば良いです。

追記:
hayataka2049さんが既に指摘されているとおりに、もっと根本的な問題がありました。
mapの使い方を誤っており、そもそも関数computerが一度も実行されようとしていません。

投稿2018/04/09 11:14

編集2018/04/09 11:38
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

python3_beginer

2018/04/09 14:47

お返事頂きありがとうございます。 クラスを利用したコードとても勉強になりました。map()に関するご指摘もありがとうございます。 参考にさせて頂きます。
guest

0

無理やり感が半端ないコードに仕上がりました。
reduceという複数の要素(リスト)を何らかの処理で1つにまとめる方式をとりました。
reduceはリストに対して先頭から2つの要素をとり何らかの処理を行った結果を、その次の要素に対して同様の処理を繰り返します。

run_commandはプレイヤーの財産(property)と指示(command)を引数に指示に従った後のプレイヤーの財産を返します。

--- 追記1 ---

LouiS0616さんのクラスのアイデアからmapを使用した別解を提案します。

--- 追記2 ---

2つ目のプログラムはmapの用法の悪い例です。
今回の問題のポイントは、指示が上から下へと順序があるので、その通りに実行する必要があるため内包表記の処理に改めました。

python

1''' 23 # [ 0, 0] 3IN 1 10 # [10, 0] 4IN 2 20 # [10, 20] 5Add 40 # [10, 50] 6''' 7from functools import reduce 8 9 10def run_command(property, command): 11 kw, args = command[0], command[1:] 12 if kw == 'IN': 13 property[args[0] == '2'] = int(args[1]) 14 else: 15 property[1] = property[0] + int(args[0]) * [-1, 1][kw == 'Add'] 16 return property 17 18commands = [ 19 input().split() 20 for _ in range(int(input())) 21] 22 23init_property = [[0, 0]] 24print(reduce(run_command, init_property + commands))

python

1# —- Another solution 1 —- 2 3class Status: 4 def __init__(self): 5 self.properties = [0, 0] 6 7 def __str__(self): 8 return ' '.join(map(str, self.properties)) 9 10 def s_in(self, i, v): 11 self.properties[i - 1] = v 12 13 def s_add(self, v): 14 self.properties[1] = self.properties[0] + v 15 16 def s_sub(self, v): 17 self.s_add(-v) 18 19 20def run_command(status): 21 command_dict = { 22 'IN': status.s_in, 23 'Add': status.s_add, 24 'Sub': status.s_sub, 25 } 26 27 def _run_command(command): 28 kw = command[0] 29 args = list(map(int, command[1:])) 30 command_dict[kw](*args) 31 return None 32 33 return _run_command 34 35 36status = Status() 37commands = [ 38 input().split() 39 for _ in range(int(input())) 40] 41after = list(map(run_command(status), commands)) 42print(status)

python

1# —- Another solution 2 —- 2 3class Status: 4 def __init__(self): 5 self.properties = [0, 0] 6 7 def __str__(self): 8 return ' '.join(map(str, self.properties)) 9 10 def s_in(self, i, v): 11 self.properties[i - 1] = v 12 13 def s_add(self, v): 14 self.properties[1] = self.properties[0] + v 15 16 def s_sub(self, v): 17 self.s_add(-v) 18 19 def command(cmd): 20 kw = command[0] 21 args = list(map(int, command[1:])) 22 after = { 23 'IN': status.s_in, 24 'Add': status.s_add, 25 'Sub': status.s_sub, 26 }[kw](*args) 27 return None 28 29status = Status() 30commands = [ 31 input().split() 32 for _ in range(int(input())) 33] 34after = [status.command(cmd) for cmd in commands] 35print(status)

投稿2018/04/09 12:01

編集2018/04/09 13:18
arch_

総合スコア158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2018/04/09 12:05

「使えなくはないかもしれないとか書いちゃったけど、まともに書くのは無理だナ」と思っていましたが、ここまで簡潔になるとは・・・脱帽です けどやっぱり、トリッキーすぎる気が(笑)
arch_

2018/04/09 12:09

自分も同感です()
arch_

2018/04/09 12:49

今更ですが、最初のアイデアはクロージャで何とかなりますね笑
hayataka2049

2018/04/09 12:53

追記に関して: あまり良いコードとは思いません。これもmapの使い方を誤っている例と言わざるを得ないかと。 mapに副作用を期待するのは発想として間違っているのです。 pythonのmapの実装がたまたま先頭から順番通り一つずつ実行されるからできるだけで、いわゆる関数型言語のmapだとスレッド並列で走ったりしますから・・・
arch_

2018/04/09 12:59

おっしゃる通りですね。。 良い勉強になりました。
python3_beginer

2018/04/09 14:50

お返事頂きありがとうございます。 たくさんのコードありがとうございます。 お二人の会話とコードの内容をすべて理解できました!とは言えるレベルではないので、時間をかけて吸収したいと思います。ご指導ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問