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

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

ただいまの
回答率

88.58%

Pythonで関数を使わずにループさせたい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,337

kyogym

score 13

 Python(IDLE)でプログラミング教材を作っています。while文やfor文を用いることなく、一言(一単語)の命令でループさせたいです。

 発生している問題・エラーメッセージ

初等教育向けのプログラミング教材を開発しています。(専門高校高3)
受験の推薦入試でプレゼンで行うときに使います。
使用するCPUはRaspberry Piで言語はPythonです。
自分が製作した車型のロボットを簡単な命令コードで動作できるようにしたいです。
作りたい命令コードは以下の8つです。

FWD・・・前進    WAT・・・待機
BRK・・・後退    MRK(ⅹ)・・・ⅹは番号
LFT・・・左折    LMP(ⅹ)・・・MRK(x)へジャンプ
RGT・・・右折    SW(ⅹ)・・・MRK(x)へジャンプ

FWD,BRK,LFT,RGT,WATはGPIOによる出力をするプログラムをモジュールにして、
関数として呼び出せるのですが、MRK,JMPに関してはそう簡単にいきませんでした。
MRK,JMPは組み合わせることでループの役割をさせたいです。
そのため、
入力したプログラムを全て読み込む→MRKの行を記憶→JMPを検知→MRKにジャンプ
→JMP以下のプログラムを再実行
の流れで処理する必要がある。と、学校の教諭は言っていました。
以下に記すのが、入力したプログラム例です。

MRK(1)               マーク1番を置く
FWD(1.0)             前進(1s)
LFT(1.0)             左折(1s)
JMP(x)               マークの1番へジャンプ

以上のプログラムの実行結果としては

→前進(1s)→左折(s)→
↑          ↓
← ← ← ← ← ← 

です。ループ制御をしたいのです。
しかし、Pythonでプログラムを途中(ここではMRKの後)から実行するやり方が分かりません。

エラーメッセージ

### 該当のソースコード

Python
ソースコード
```

 試したこと

一度書き込んだプログラムを全て読み取りMRK、JMPと名づけた関数の文字列をfind()でみつける

JMPの文字列を取得したらMRKまでジャンプし、MRK以下の命令をまた順番に実行する。事を試みた。

 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • LouiS0616

    2018/11/07 23:47

    ①入力は最初に全行与えられるのですか?②ご提示の例の場合、無限ループに陥りますが脱出条件は用意しないのですか?③JMP命令とSW命令の差は何ですか?

    キャンセル

  • kyogym

    2018/11/07 23:53

    ①一行ずつ入力し、保存してから実行します。②用意したいのですが、先ずはループを完成させたいです。③SWはロボットについているリミットスイッチの入力でMARにジャンプさせたいです。分岐命令のようなものにしたいと考えています。

    キャンセル

  • can110

    2018/11/08 00:07

    まずは途中まででよいのでご自身で書いたコードを提示ください。

    キャンセル

回答 2

checkベストアンサー

0

pythonとしてはgotoはないので、そのままpythonとして実行して望む出力が得られるようなコードを作ることは難しいと思います(もしかしたら誰かが黒魔術で解決する方法を書いてくれるかもだけど)。

簡単とはいえpythonとは別の言語処理系を作ることになるので、相応の気合と知識が要ります。

フロー制御だけできれば良いなら、読み込んだ命令をリストに入れて先頭から逐次実行、JMP系はプログラムカウンタ的な変数を用意しておいてそれを書き換える……みたいな方針で書けるとは思いますが。

 追記

一応具体例を書いておきます。

MRK(1)        
FWD(1.0)      
LFT(1.0)      
JMP(x) 


を動かすとしたら、

まず読み込んで次のようなフォーマットに変換する。ここは面倒くさいので今回パスします。

instructions = [("MRK", 1), ("FWD", 1.0), ("LFT", 1.0), ("JMP", 1)]

ラベルと命令のindexの対応テーブルを作っておきます。

label_table = dict()
for i, (ins, arg) in enumerate(instructions):
    if ins == "MRK":
        label_table[arg] = i

命令を実際に実行するための関数を書く。なお、各命令の関数は別途用意しておきます。

def exec_instruction(ins, arg):
    global pc
    if ins == "FWD":
        fwd(arg)
    elif ins == "LFT":
        lft(arg)
    # 中略...
    # JMP系はまた扱いが別
    elif ins == "JMP":
        pc = label_table[arg]
    elif ins == "SW":
        if スイッチがHなら:
            pc = label_table[arg]

あとはメインループを回せば良いです。

pc = 0
while True:
    if pc >= len(instructions):
        break
    exec_instruction(*instructions[pc])
    pc += 1

以上をまとめてみました。実行可能です。あまりきれいじゃないんですが、何かの参考にはなると思います。

import time

def fwd(arg):
    # fwdとlftは自分の名前をprintしてarg秒sleepする関数にしてみました
    print("fwd")
    time.sleep(arg)

def lft(arg):
    print("lft")
    time.sleep(arg)

def exec_instruction(ins, arg):
    global pc
    if ins == "FWD":
        fwd(arg)
    elif ins == "LFT":
        lft(arg)
    elif ins == "JMP":
        pc = label_table[arg]
    else:
        pass

instructions = [("MRK", 1), ("FWD", 1.0), ("LFT", 1.0), ("JMP", 1)]

label_table = dict()
for i, (ins, arg) in enumerate(instructions):
    if ins == "MRK":
        label_table[arg] = i

pc = 0
while True:
    if pc >= len(instructions):
        break
    exec_instruction(*instructions[pc])
    pc += 1

ぱっと思いつく、他にやらないといけないであろうこと。

  • 構文が間違っていたらわかりやすいエラーを出す
  • MRKで同じラベルを複数作ると困るので、エラーを出すようにする

 余談

大学の推薦入試くらいならけっこうウケるかもしれませんが、この「プログラミング言語」にはいろいろ問題があります。

  • 変数がない
  • 状態を持てない
  • よってかなり表現能力は低い
  • あと、初等教育の子たちってパソコンのキーボードを使えるんですか

さらにこの分野ではLEGOのマインドストームという強力な競合があります(他にもあるけど)。私は小学生の頃触っていましたが、けっこう高機能でした。

今から練り直すもよし、あるいはその辺は割り切ってプレゼン力で乗り切るのも一つの戦略です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/15 15:06

    実行出来ました

    [読み取ってフォーマットに変換]を教えてくださいませんか

    キャンセル

  • 2018/11/15 15:36 編集

    テキストのソースファイルを読み込んで同様のフォーマットに変換すれば良いです。受験に使うということなので、あまり他人が助言するのも問題になりますから、ご自身で実装されると良いかと思います。

    キャンセル

  • 2018/11/19 22:39

    そうですね
    後は自分で勉強していきたいと思います。
    ご指導ありがとうございました。

    キャンセル

0

どうやら事前に解析する余地があるようですね。
それならば、扱いやすいように命令を書き直してしまっても良いのでは?

例えば、スクリプト読み込み時に次のように処理を置きなおしてやります。

MRK(1)
FWD(1.0)
LFT(1.0)
JMP(1)

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

MRK None
FWD 1.0
LFT 1.0
JMP 0     # ジャンプ先の行番号

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/08 00:24

    勉強不足で申し訳ないのですが、この場合MRK,JMPではどのような処理をさせればよいのでしょうか
    関数として扱えばよいのでしょうか

    キャンセル

  • 2018/11/08 00:29

    リストに全行放り込んで、一行一行処理していけば良いです。
    hayataka2049さんが書かれているような、カウンタを用意する方法が最も安直かつ簡単かと思います。

    もちろん、OOP的に綺麗に設計・実装できるならそのような開発方針をとっても良いでしょう。

    キャンセル

  • 2018/11/08 06:23

    ご丁寧にありがとうございます
    アドバイス頂いた通りにやったみたいと思います。

    キャンセル

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

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る