유한 상태 머신의 좋은 예를 찾고 있습니다. 언어는 특별히 중요하지 않고 좋은 예일뿐입니다.
코드 구현은 유용하지만 (일반화 된 의사 코드) FSM의 다양한 용도를 수집하는 것도 매우 유용합니다.
예를 들어 컴퓨터 기반 일 필요는 없습니다. 예를 들어 Mike Dunlavey의 Railroad 네트워크 예제는 매우 유용합니다.
유한 상태 머신의 좋은 예를 찾고 있습니다. 언어는 특별히 중요하지 않고 좋은 예일뿐입니다.
코드 구현은 유용하지만 (일반화 된 의사 코드) FSM의 다양한 용도를 수집하는 것도 매우 유용합니다.
예를 들어 컴퓨터 기반 일 필요는 없습니다. 예를 들어 Mike Dunlavey의 Railroad 네트워크 예제는 매우 유용합니다.
답변:
안전 (이벤트 발생)
신호등 (시간 트리거 | 센서 [이벤트] 트리거)
자동 판매기 (이벤트 발생, 금고 의 변형 )
BGP는 인터넷의 핵심 라우팅 결정을 뒷받침하는 프로토콜입니다. 주어진 노드에서 호스트의 도달 가능성을 결정하기 위해 테이블을 유지 관리하고 인터넷을 실제로 분산시킵니다.
네트워크에서 각 BGP 노드는 피어이며 유휴 상태 , 연결 상태 , 활성 상태 중 하나 인 유한 상태 머신을 사용합니다. , OpenSent 상태 , OpenConfirm 상태 및 설정 . 네트워크의 각 피어 연결은 이러한 상태 중 하나를 유지합니다.
BGP 프로토콜은 상태를 변경하기 위해 피어로 전송되는 메시지를 결정합니다.
첫 번째 상태 유휴 상태 입니다. 이 상태에서 BGP는 리소스를 초기화하고 인바운드 연결 시도를 거부하고 피어에 대한 연결을 시작합니다.
두 번째 상태는 Connect 입니다. 이 상태에서 라우터는 연결이 완료 될 때까지 대기하고 성공 하면 OpenSent 상태로 전환합니다 . 실패하면 ConnectRetry 타이머를 재설정하고 만료시 활성 상태로 .
에서 활성 상태, 라우터는에 ConnectRetry의 제로 타이머 반환 재설정 연결을 상태를.
에서 OpenSent의 상태, 라우터는 개방 메시지 창 하나 기다린다 보낸다. Keepalive 메시지가 교환되고 성공적으로 수신되면 라우터는 설정 됨 상태가됩니다.
에서 설립 상태, 라우터는 송 / 수신 할 수 있습니다 : 연결 유지를; 최신 정보; 및 피어와의 알림 메시지.
모든 종류의 것을 모델링하는 데 유용합니다. 예를 들어, 선거주기는 (정상 정부)-선거 부름-> (초기 선거 운동)-의회 해산-> (무거운 선거 운동)-선거-> (투표 계수)의 선을 따라 상태로 모델링 할 수 있습니다. ). 그런 다음 (투표 수)-다수결 없음-> (연합 협상)-계약에 도달-> (일반 정부) 또는 (투표 수)-다수-> (일반 정부). 정치적 하위 게임이있는 게임에서이 체계에 대한 변형을 구현했습니다.
AI는 게임의 다른 측면에서도 사용됩니다. AI는 종종 상태 기반입니다. 메뉴와 레벨 사이의 전환 및 사망 또는 레벨 완료시의 전환은 종종 FSM에 의해 잘 모델링됩니다.
jquery-csv 플러그인 에서 사용되는 CSV 파서
기본적인 Chomsky Type III 문법 파서입니다.
정규식 토크 나이 저는 문자별로 데이터를 평가하는 데 사용됩니다. 제어 문자가 발생하면 시작 상태를 기반으로 추가 평가를 위해 코드가 switch 문으로 전달됩니다. 제어되지 않는 문자는 그룹화되어 대량으로 복사되어 필요한 문자열 복사 작업 수를 줄입니다.
토크 나이저 :
var tokenizer = /("|,|\n|\r|[^",\r\n]+)/;
첫 번째 일치 항목은 제어 문자입니다. 값 구분 기호 ( ") 값 구분 기호 (,) 및 항목 구분 기호 (모든 줄 바꿈) 마지막 제어는 비 제어 문자 그룹화를 처리합니다.
파서가 충족해야하는 10 가지 규칙이 있습니다.
참고 : 상위 7 개 규칙은 IETF RFC 4180 에서 직접 파생됩니다 . 마지막 3 개는 기본적으로 모든 값을 구분하지 않는 최신 스프레드 시트 앱 (예 : Excel, Google Spreadsheet)에서 도입 한 엣지 사례를 다루기 위해 추가되었습니다. RFC 변경 사항을 다시 제공하려고했지만 아직 문의에 대한 답변을 듣지 못했습니다.
와인딩과 함께 충분한 다이어그램이 있습니다.
상태 :
전환 :
참고 : 실제로 상태가 없습니다. 이스케이프 된 두 번째 구분 기호는 첫 번째 구분 기호가 여전히 열려 있음을 의미하므로 'c'-> 'b'에서 상태가 '1'로 표시된 줄이 있어야합니다. 실제로 다른 전환으로 표시하는 것이 좋습니다. 이것들을 만드는 것은 예술이며, 올바른 방법은 없습니다.
참고 : 종료 상태도 없지만 유효한 데이터에서 파서는 항상 전환 'a'에서 종료되며 구문 분석 할 항목이 없으므로 상태가 없습니다.
상태와 전환의 차이점 :
상태는 유한하기 때문에 한 가지 의미 만 유추 할 수 있습니다.
전이는 상태 간의 흐름을 나타내므로 많은 것을 의미 할 수 있습니다.
기본적으로, 상태-> 전이 관계는 1-> * (즉, 일대 다)입니다. 상태는 '무엇인가'를 정의하고 전환은 '어떻게 처리되는지'를 정의합니다.
참고 : 상태 / 전환 적용이 직관적이지 않다고 걱정하지 마십시오. 직관적이지 않습니다. 나는 마침내 개념을 고수하기 전에 나보다 훨씬 똑똑한 사람과 광범위하게 대응했습니다.
의사 코드 :
csv = // csv input string
// init all state & data
state = 0
value = ""
entry = []
output = []
endOfValue() {
entry.push(value)
value = ""
}
endOfEntry() {
endOfValue()
output.push(entry)
entry = []
}
tokenizer = /("|,|\n|\r|[^",\r\n]+)/gm
// using the match extension of string.replace. string.exec can also be used in a similar manner
csv.replace(tokenizer, function (match) {
switch(state) {
case 0:
if(opening delimiter)
state = 1
break
if(new-line)
endOfEntry()
state = 0
break
if(un-delimited data)
value += match
state = 3
break
case 1:
if(second delimiter encountered)
state = 2
break
if(non-control char data)
value += match
state = 1
break
case 2:
if(escaped delimiter)
state = 1
break
if(separator)
endOfValue()
state = 0
break
if(newline)
endOfEntry()
state = 0
break
case 3:
if(separator)
endOfValue()
state = 0
break
if(newline)
endOfEntry()
state = 0
break
}
}
참고 : 이것은 요점입니다. 실제로 고려해야 할 것이 더 많습니다. 예를 들어, 오류 검사, 널 (NULL) 값, 후행 공백 행 (예 : 유효한) 등
이 경우 상태는 정규식 일치 블록이 반복을 완료 할 때의 상태입니다. 전이는 사례 진술로 표현됩니다.
인간으로, 우리는 높은 수준의 초록하지만 FSM 작업이로 낮은 수준의 작업을 단순화하는 경향이 있다 낮은 수준의 연산 작업을. 상태와 전환은 개별적으로 작업하기가 매우 쉽지만 전체를 한 번에 시각화하는 것은 본질적으로 어렵습니다. 전환이 어떻게 진행되는지 직감 할 때까지 반복되는 개별 실행 경로를 따르는 것이 가장 쉽다는 것을 알았습니다. 기본 수학을 배우는 것과 마찬가지로 저수준 세부 사항이 자동으로 시작될 때까지 높은 수준에서 코드를 평가할 수 없습니다.
따로 : 실제 구현을 보면 많은 세부 정보가 빠져 있습니다. 첫째, 모든 불가능한 경로는 특정 예외를 발생시킵니다. 타격을 가하는 것은 불가능하지만 어떤 것이 고장 나면 테스트 러너에서 예외가 발생합니다. 둘째, '법적'CSV 데이터 문자열에서 허용되는 것에 대한 파서 규칙이 매우 느슨하여 코드가 많은 특수한 경우를 처리하는 데 필요했습니다. 사실과 상관없이, 이것은 모든 버그 수정, 확장 및 미세 조정 전에 FSM을 조롱하는 데 사용 된 프로세스였습니다.
대부분의 디자인과 마찬가지로 구현의 정확한 표현은 아니지만 중요한 부분을 간략하게 설명합니다. 실제로이 디자인에서 파생 된 csv 특정 라인 스플리터, 단일 라인 파서 및 완전한 다중 라인 파서의 세 가지 파서 함수가 실제로 있습니다. 그들은 모두 비슷한 방식으로 작동하며 개행 문자를 처리하는 방식이 다릅니다.
Java의 간단한 FSM
int i=0;
while (i<5) {
switch(i) {
case 0:
System.out.println("State 0");
i=1;
break;
case 1:
System.out.println("State 1");
i=6;
break;
default:
System.out.println("Error - should not get here");
break;
}
}
당신은 간다. 좋습니다, 훌륭하지는 않지만 아이디어를 보여줍니다.
통신 제품에서 FSM은 종종 복잡한 상황에 대한 간단한 솔루션을 제공하기 때문에 찾을 수 있습니다.
나는 리프트 (엘리베이터)에 대한 생각 / 모델링이 유한 상태 기계의 좋은 예라는 것을 알았습니다. 도입 방법은 거의 필요하지 않지만 구현하기에는 사소한 상황과는 거리가 멀다.
상태는 예를 들어 1 층, 1 층 등에서, 1 층으로 이동하거나 3 층에서 1 층으로 이동하지만 현재 3 층과 2 층 사이에 있습니다.
리프트 케이지 및 바닥에있는 버튼의 효과는 입력을 제공하며,이 효과는 현재 상태와 함께 눌려진 버튼에 따라 달라집니다.
상단과 하단을 제외한 각 층에는 두 개의 버튼이 있습니다. 하나는 리프트 상승을 요청하고 다른 하나는 내려갑니다.
예, 여기 예가 있습니다. 정수를 구문 분석한다고 가정하십시오. 정수 자릿수 와 같은 dd*
곳으로 갈 것 d
입니다.
state0:
if (!isdigit(*p)) goto error;
p++;
goto state1;
state1:
if (!isdigit(*p)) goto success;
p++;
goto state1;
물론 @Gary가 말했듯 goto
이 switch 문과 state 변수를 사용하여 이들을 위장 할 수 있습니다. 이 코드로 구성 할 수 있습니다.이 코드는 원래 정규식과 동형입니다.
if (isdigit(*p)){
p++;
while(isdigit(*p)){
p++;
}
// success
}
else {
// error
}
물론 조회 테이블을 사용하여 수행 할 수도 있습니다.
유한 상태 머신은 여러 가지 방법으로 만들 수 있으며, 많은 것을 유한 상태 머신의 인스턴스로 설명 할 수 있습니다. 그것은 사물에 대해 생각하기위한 개념만큼이나 "사물"이 아닙니다.
FSM의 한 예는 철도 네트워크입니다.
기차가 두 개의 트랙 중 하나를 갈 수있는 유한 한 수의 스위치가 있습니다.
이 스위치들을 연결하는 트랙은 유한합니다.
열차는 언제든지 한 트랙에 있으며 단일 비트의 입력 정보를 기반으로 스위치를 건너 다른 트랙으로 전송할 수 있습니다.
루비의 유한 상태 머신 :
module Dec_Acts
def do_next
@now = @next
case @now
when :invite
choose_round_partner
@next = :wait
when :listen
@next = :respond
when :respond
evaluate_invites
@next = :update_in
when :wait
@next = :update_out
when :update_in, :update_out
update_edges
clear_invites
@next = :exchange
when :exchange
update_colors
clear_invites
@next = :choose
when :choose
reset_variables
choose_role
when :done
@next = :done
end
end
end
이것이 분산 시스템에서 단일 컴퓨팅 노드의 동작으로 링크 기반 통신 체계를 설정합니다. 다소간. 그래픽 형식에서는 다음과 같습니다.
간단한 어휘 분석 (FSM)의 예를 보려면이 링크를 확인하십시오.
http://ironbark.bendigo.latrobe.edu.au/subjects/SS/clect/clect03.html
예를 들어 "드래곤 북"을 확인할 수도 있습니다 (빛이 아님).
실제로 State Machine은 종종 다음 용도로 사용됩니다.
한 가지 예는 문자열을 스캔하여 올바른 구문이 있는지 확인하는 상태 머신입니다. 예를 들어 네덜란드 우편 번호는 "1234 AB"형식입니다. 첫 번째 부분은 숫자 만 포함하고 두 번째 부분은 문자 만 포함 할 수 있습니다. NUMBER 상태인지 LETTER 상태인지 여부를 추적하고 잘못된 입력이 발생하면이를 거부하는 상태 머신을 작성할 수 있습니다.
이 억 셉터 상태 머신에는 숫자와 알파의 두 가지 상태가 있습니다. 상태 머신은 숫자 상태에서 시작하여 확인할 문자열의 문자를 읽기 시작합니다. 어떤 상태에서도 유효하지 않은 문자가 발견되면 함수는 False 값으로 리턴하여 입력을 유효하지 않은 것으로 거부합니다.
파이썬 코드 :
import string
STATE_NUMERIC = 1
STATE_ALPHA = 2
CHAR_SPACE = " "
def validate_zipcode(s):
cur_state = STATE_NUMERIC
for char in s:
if cur_state == STATE_NUMERIC:
if char == CHAR_SPACE:
cur_state = STATE_ALPHA
elif char not in string.digits:
return False
elif cur_state == STATE_ALPHA:
if char not in string.letters:
return False
return True
zipcodes = [
"3900 AB",
"45D6 9A",
]
for zipcode in zipcodes:
print zipcode, validate_zipcode(zipcode)
출처 : 실제 유한 기계