自從我寫了任何Logo以來已經有一段時間了,所以我不確定這是否是最簡單的方法,但這裏有一種方法可以實現。總的想法是,您可以使用字符串作爲字符列表,使用FIRST
,LAST
,BUTFIRST
和BUTLAST
來獲取字符串的不同部分。 (我測試這前兩個在線徽標解釋我能找到 - http://www.logointerpreter.com/turtle-editor.php和http://www.calormen.com/jslogo/ - 它跑了兩個很好,但你可能需要爲其它徽標方言一些小的修改)
TO RUN_COMMANDS :commands
IF (EMPTY? :commands) [STOP]
MAKE "first_command (FIRST :commands)
MAKE "rest_of_commands (BUTFIRST :commands)
IF (NOT EMPTY? :rest_of_commands) [MAKE "split (GET_NUMBER :rest_of_commands ")]
MAKE "numeric_argument (LAST :split)
MAKE "rest_of_commands (FIRST :split)
RUN_SINGLE_COMMAND :first_command :numeric_argument
RUN_COMMANDS :rest_of_commands
END
TO MERGE_STRING :word :characters
IF (NOT EMPTY? :characters) [OP (MERGE_STRING (WORD :word (FIRST :characters)) (BUTFIRST :characters))]
OP :WORD
END
TO GET_NUMBER :word :number
IF (AND (NOT (EMPTY? :word)) (IS_DIGIT (FIRST :word))) [OP (SE (GET_NUMBER (BUTFIRST :word) (LPUT (FIRST :word) :number))]
OP (SE (MERGE_STRING " :word) (MERGE_STRING " :number))
END
TO IS_DIGIT :character
OP (OR
:character = "0
:character = "1
:character = "2
:character = "3
:character = "4
:character = "5
:character = "6
:character = "7
:character = "8
:character = "9)
END
TO RUN_SINGLE_COMMAND :command :parameter
(PRINT_COMMAND :command :parameter)
IF (:command = "F) [FD :parameter]
IF (:command = "B) [BK :parameter]
IF (:command = "L) [LT 90 FD :parameter]
IF (:command = "R) [RT 90 FD :parameter]
IF (:command = "N) [SETH 0 FD :parameter]
IF (:command = "S) [SETH 180 FD :parameter]
IF (:command = "E) [SETH 90 FD :parameter]
IF (:command = "W) [SETH 270 FD :parameter]
END
TO PRINT_COMMAND :command :parameter
IF (:command = "F) [PRINT (SE "FD :parameter)]
IF (:command = "B) [PRINT (SE "BK :parameter)]
IF (:command = "L) [PRINT (SE "LT 90 "FD :parameter)]
IF (:command = "R) [PRINT (SE "RT 90 "FD :parameter)]
IF (:command = "N) [PRINT (SE "SETH 0 "FD :parameter)]
IF (:command = "S) [PRINT (SE "SETH 180 "FD :parameter)]
IF (:command = "E) [PRINT (SE "SETH 90 "FD :parameter)]
IF (:command = "W) [PRINT (SE "SETH 270 "FD :parameter)]
END
然後,嘗試運行:
RUN_COMMANDS "F20N20E10L10
此打印並執行以下操作:
FD 20
SETH 0 FD 20
SETH 90 FD 10
LT 90 FD 10
一些說明
RUN_COMMANDS
是主要功能。它:
- 提取從刺的第一個字母(我假設每個命令被縮寫爲單個字母)
- 呼叫
GET_NUMBER
從的開始提取數(其可以是多個字符)串。
- 通行證的單字母縮寫命令和數量
RUN_SINGLE_COMMAND
- 遞歸重複
IS_DIGIT
是內GET_NUMBER
用來檢查一個字符是數字(儘管我敢打賭一些標誌方言有一個過程內置函數)
被使用,因爲我有一些多字符的單詞(「字」是標誌說話的字符串),我已經變成單字符單詞列表,我想將列表合併到單個Word中。不過,這實際上並不是必須的。
RUN_SINGLE_COMMAND
執行從輸入字符串解析的每個單獨命令。我只是使用了一個大的IF
語句,而不是像你所建議的那樣使用將字符串解釋爲代碼的函數。 (某些徽標方言可能有這樣的功能,但我不確定它是否是標準方式。)RUN_SINGLE_COMMAND
也會調用PRINT_COMMAND
,它會在運行時打印出未縮放的命令。
潛在的堆棧上溢
我用大量的遞歸的,因爲它是更地道的Logo,而且由於標誌方言往往沒有很多循環結構(比其他REPEAT
)。但我以一種不小心的方式做到了這一點,因爲我只是快速寫下這些內容來給大家提供一個總體思路。特別是,我並不擔心堆棧溢出(沒有雙關語意圖),如果您提供了長輸入字符串,我認爲這可能會發生。爲了解決這個問題,你應該確保可以多次調用的任何遞歸路徑是一個尾部調用,這個Logo將優化掉。
一目瞭然,它看起來像RUN_COMMANDS
是好的,但和GET_NUMBER
反轉 - 而不是IF <condition> [<recursive_call>]
其次OUTPUT <return_value>
,倒不如做IF (NOT <condition>) [OUTPUT <return_value>]
隨後<recursive_call>
。測試堆棧溢出並應用此修復程序我已作爲練習留給讀者。 :)