C코드 java코드 비스무리하게 표현해봤다.
팩토리오의 회로는 tick이라는 것을 기반으로 동작하고, 입력에서 읽어오거나 하는 값은 항상 1tick이전의 값이라서, 소스코드같은 로직 스크립트 형태로 바꾸기엔 애로사항이 꽃핀다...
while(true)루프 안에서 반복되면서 내부에서 읽어오는 값은 항상 이전루프에서 저장했던 값이고,
모든 연산이 끝나면 최종적으로 색색깔의 "전선에 값을 저장"하는 방식이 된다.
다음 tick이 되면 이전 tick에 값을 저장했던 전선으로부터 값을 읽어와서 연산을 하는 구조다.
일단 몇가지 예시를 정리해봤어.
회로 늅늅에게도 도움이 되길 바란다.
###edge detector###
입력이 거짓이다가, 참으로 변하는 순간에 1틱짜리 펄스를 발생시킨 뒤, 입력이 참으로 계속 바뀌어있는 상태라도 더이상 신호를 발생시키지 않는 장치.
###설정내용###
A : 만약 I=C, X=1 ### I=C는 임의의 입력조건
B : X=X*-1
C : 만약 X>0, O=1 ### O는 최종출력
###연결도###
입력 -> A -> r1
r1 -> B -> g1
r1+g1 -> C -> 출력
###코드로 표현하면###
struct r1, g1, 최종출력, 최초입력;
//r1, g1등은 구간 레지스터. 일종의 구조체라서, 예를 들어 r1=[철광석,구리판,A,B,C,빨간색,파란색...] 등 여러개의 값을 가질 수 있다.
struct R1=[], G1=[], 출력=[];
//R1는 빨간선, G1는 초록선. 최종합산 전, 값 목록 배열. 틱 내부 연산에 쓰이고 버리는 임시값 같은 것.
int tick=0;
while(true){
//임시값 초기화 시작
R1=[];
B1=[];
//임시값 초기화 끝
//A조합기
if( 최초입력[I]==최초입력[C] ) R1.0[X]=1, else R1.0=[];
// 여기서 .0은 배열의 0번째 원소를 의미. r1에 연결된 다른 장치의 출력부의 숫자만큼 그냥 이 숫자를 늘려가면서 구분하려고 쓴다.
//B조합기
G1.0[X] = r1[X]*-1;
//C조합기
if( r1[X]+g1[X] > 0 ) 출력.0[O]=1, else 출력.0=0;
//결과대입 시작
r1=sum(R1);
g1=sum(G1);
최종출력=sum(출력);
//결과대입 끝
tick++;
}
###일어나는 일###
*최초입력이 계속 false이다가, tick이 23일 때 true로 바뀐다고 가정해보자.
struct r1, g1, 최종출력, 최초입력;
struct R1=[], G1=[], 출력=[];
int tick=0;
while(true){
R1=[];
B1=[];
//A조합기
if( 최초입력[I]==최초입력[C] ) R1.0[X]=1, else R1.0=[];
*현재 r1에는 연결된 출력이 이것 하나 뿐이지만, r1에 출력이 여러개 연결될 경우를 위해서 R1.0이라는 등록예비값으로 표현했다.
22틱까지 계속 0을 나타낼 것이다.
23틱때 r1으로 X=1이 나온다.
//B조합기
G1.0[X] = r1[X]*-1;
*r1이라는 값이 처음으로 호출되었다.
만약 tick==0 이었거나 이전에 계속 최초입력의 결과가 false였다면 처음에 r1에 저장된 값은 없을 것이다.
n틱일 때 읽는 r1의 값은 과거 n-1틱 때의 것이다. 팩토리오의 회로는 언제나 한 틱 이전의 과거 정보를 읽어온다.
23틱이 끝났을 때, A조합기에 의해서 처음으로 r1에 X=1값이 저장된다.
따라서, 24틱이 되면 이 계산결과는 1*-1이 되어서 B조합기에서는 g1쪽으로 -1이 출력된다.
23틱 까지는 이 계산결과는 r1에 아무것도 없었기 때문에 0이다.
만약 최초입력의 결과가 계속해서 true인 경우에는 B조합기에서는 계속 -1이 나올 것이다.
//C조합기
if( r1[X]+g1[X] > 0 ) 출력.0[O]=1, else 출력.0=0;
*조합기의 입력부에 빨간선과 초록선이 모두 연결되면, 두 개의 값을 자동으로 합산한다. 합산결과가 양수이면 출력이 true가 되는 내용이다.
23틱이 되어도 C조합기에서 읽어오는 r1, g1값은 22틱때의 것이므로 r1+g1은 0이다.
24틱이 되면 무슨일이 벌어질까.
일단 23틱이 끝났을 때, A조합기로부터 r1에 X=1이 저장되었다.
그리고 B조합기로부터 나오는 23틱때의 g1에는 0이 저장되어있다. 이 0이라는 값은 22틱이 끝났을 때의 r1을 가지고 계산한 것이기 때문이다.
따라서 24틱때 C조합기에서 나오는 값은 r1의 X=1, g1의 0을 합해서 1이 출력된다.
25틱이되면 B조합기가 23틱이 끝났을 때의 r1을 읽고 -1을 출력하기 때문에 r1의 1, g1의 -1을 더해서 C조합기에서는 0이 출력된다.
r1=sum(R1);
g1=sum(G1);
최종출력=sum(출력);
tick++;
}
*23틱이 시작될 때 최초입력의 조건이 true로 바뀐다고 가정하면, 위 알고리즘은 23틱까지 0을 출력하고, 24틱이 되었을 때 1을 출력하며, 25틱 이후로는 다시 0을 출력한다.
계속 최초입력이 true로 고정되어 있거나 false가 되어도 말이다.
true -> false로 바뀌는 순간에는 C조합기의 입력이 0이라서 false가 아닌 -1이라서 false가 된다.
따라서 false -> true로 바뀌는 순간에만 1틱짜리 펄스를 발생시키게 된다.
만약 C조합기의 조건을 X>0 대신에 X!=0이라고 하면, 최초입력이 false<->true 왔다갔다 할 때마다 펄스를 발생시키게 된다.
###SR latch###
S조건이 되면 true를 출력하고, R조건이 되면 false를 출력하며, 이외의 조건에서는 기존의 출력을 유지하는 장치.
S는 Set, R은 Reset을 보통 의미한다.
###설정내용###
A : 만약 I>90, R=1
B : 만약 I
C : 만약 S>R, S=1 ### S는 최종출력
###연결도###
입력 -> A -> r1
입력 -> B -> r1
r1, g1 -> C -> 출력, g1
###코드로 표현하면###
struct r1, g1, 최종출력, 최초입력;
struct R1=[], G1=[], 출력=[];
int tick=0;
while(true){
R1=[];
B1=[];
//A조합기
if( 최초입력[I]>90 ) R1.0[R]=1, else R1.0=[];
//B조합기
if( 최초입력[I]
//C조합기
if( r1[S]+g1[S] > r1[R]+g1[R] ) G1.0[S]=1, else G1.0=[];
출력.0=G1.0;
r1=sum(R1);
g1=sum(G1);
최종출력=sum(출력);
tick++;
}
###일어나는 일###
*처음에 입력값이 100이다가, 50정도이다가, 10미만으로 떨어졌다가 다시 50, 100으로 간다고 가정해보자.
struct r1, g1, 최종출력, 최초입력;
struct R1=[], G1=[], 출력=[];
int tick=0;
while(true){
R1=[];
B1=[];
//A조합기
if( 최초입력[I]>90 ) R1.0[R]=1, else R1.0=[];
//B조합기
if( 최초입력[I]
*A와 B조합기는 단순히 입력내용을 1또는 0의 값으로 변환하는 기능을 한다. 변환해서 r1으로 내보낸다.
입력수치가 90~이면 r1에는 R=1,
10~90이면 r1에는 아무것도 없고,
~10이면 r1에는 S=1이 저장되는 구조이다.
A,B조합기는 똑같은 길이로 병렬연결되어있기 때문에 타이밍에 의한 틱 오차가 없어서 변화순간 같은 틱에 민감한건 고려하지 않아도 된다.
//C조합기
if( r1[S]+g1[S] > r1[R]+g1[R] ) G1.0[S]=1, else G1.0=[];
출력.0=G1.0;
*게임상에는 초록+빨강 해서 S>R 조건을 걸었을 뿐인데, 실제 계산은 저렇게 각각 더한걸 비교하게 된다.
C조합기에서는 g1으로 출력하면서 다시 g1에서 입력을 받는다.
때문에, 항상 이전틱에서 값을 읽어오는 특성에 의해서 다른 변화가 없으면 틱이 계속해서 흘러도 g1에 원하는 내용이 남아있게되는 메모리 셀 역할을 한다.
S>R조건이 true이면 1을 계속해서 기억해두고, false이면 아무것도 출력하지 않는다.
*처음에 입력값이 100이면 r1에서는 R=1이 출력되어서 C조합기의 조건문은 false가 되어 출력은 0이된다.
그러다가 50으로 낮아지면 r1에는 아무것도 없기 때문에 메모리셀의 루프에 의해서 g1만 계속해서 읽어오게 된다. g1에도 아무것도 없으니 출력은 0이다.
그러다가 입력이 0으로 낮아지면 r1에서는 S=1이 출력된다. 그러면 S>R이 true가 되어서 C조합기가 g1으로 S=1을 내보내게 된다.
처음 입력이 10미만으로 떨어진 순간인 틱을 지나서 계속 낮은 상태로 있게되면 r1에서 S=1이 나오고, g1에서도 S=1이 나와서 C조합기는 S=2를 입력받게된다.
물론 출력은 S=1고정이라서 다음틱에 g1에서 읽는 값은 S=1이 된다.
그러다가 입력이 다시 50으로 높아지면 r1에는 아무것도 없지만 g1에는 1이 남아서 S>R이 true가 되어 출력은 1이 된다.
그러다가 다시 100까지 높아지면 S도 1, R도 1이 되어서 S>R이 false가 되어서 출력이 꺼지고, 이후에는 R만 1이 남게 되면서 출력은 계속 0이 된다.
r1=sum(R1);
g1=sum(G1);
최종출력=sum(출력);
tick++;
}
###night sensor###
태양전지판의 출력이 0이 되면, true를 출력하는 장치.
###설정내용###
A : 만약 R=0, R=1
B : S=R
C : 만약 R=S, N=1 ### N는 최종출력
###연결도###
r1 -> A -> r1, g1
g1 -> B -> r2
g1, r2 -> C -> 출력
###코드로 표현하면###
struct r1, r2, g1, 최종출력, 최초입력;
struct R1=[], R2=[], G1=[], 출력=[];
int tick=0;
while(true){
R1=[];
R2=[]
B1=[];
//A조합기
if( r1[R]==0 ) {
R1.0[R]=G1.0[R]=1;
}
else {
R1.0=G1.0=[];
}
//B조합기
R2.0[S]=g1[R];
//C조합기
if( r2[R]+g1[R] == r2[S]+g1[S] ) 출력.0[N]=1, else 출력.0=[];
r1=sum(R1);
r2=sum(R2);
g1=sum(G1);
최종출력=sum(출력);
tick++;
}
###일어나는 일###
*태양전지판의 전력이 0이되면, 무한토글을 하던 A조합기(조합기는 1kW를 필요로 한다!)에 전기가 부족해져서 C조합기에서의 비교결과가 다르게 된다.
struct r1, r2, g1, 최종출력, 최초입력;
struct R1=[], R2=[], G1=[], 출력=[];
int tick=0;
while(true){
R1=[];
R2=[]
B1=[];
//A조합기
if( r1[R]==0 ) {
R1.0[R]=G1.0[R]=1;
}
else {
R1.0=G1.0=[];
}
*A조합기는 자체루프를 돌면서 자기자신이 이전에 내놓은 값을 통해서 결과를 내놓는다.
이전 틱에 r1에 저장된 값이 1이면, 조건문이 false가 되어서 다음 틱에는 r1에 아무것도 없게되고,
그러면 그 다음틱엔 조건문이 다시 true가 되어서 r1에 1이 저장된다.
이 결과 매 틱마다 1과 0을 반복하는 토글기능이 이루어진다.
메모리 셀과 생긴건 똑같지만 변조한 출력이 자신의 조건문에 영향을 주는 것이 1틱마다 전환되는 것이다.
//B조합기
R2.0[S]=g1[R];
*단순한 비교를 위해 변수이름을 R에서 S로 변환하면서 값을 복사하는 것 말고도 숨겨진 기능이 있다.
A -> C 연결은 1단계이지만
A -> B -> C 연결은 2단계라는 것이다.
그러므로 C는 B를 통해서 1틱 이전의 A의 출력이 아니라 2틱 이전의 A의 출력을 읽어올 수 있다.
//C조합기
if( r2[R]+g1[R] == r2[S]+g1[S] ) 출력.0[N]=1, else 출력.0=[];
*C는 A의 출력과 1틱 이전의 A의 출력을 비교한다.
A가 01010..무한토글을 하는데, A의 출력과 B의 출력은 간단히 말해서 "반전"되어 있다.
예를 들어, A가 4틱동안 0101을 출력하면 B가 4틱동안 1010을 출력해서 4틱동안 계속해서 둘의 출력은 같지 않게 된다.
모든 조합기가 가동중이면 0101과 1010을 반복하기 때문에 C조합기의 조건문은 계속해서 false를 나타내게 된다.
*만약 깊은 밤이 되어서 축전지가 없는 태양전지판의 출력이 0이 되면 A조합기는 멈추게되고, A의 출력은 하나로 고정되게된다.
그러면 B는 A의 값을 그대로 복사해서 전달할 뿐이기 때문에 B의 출력도 A와 같은 출력으로 고정되게되고,
C의 조건문은 A출력==B출력이기 때문에 true를 출력하게 된다.
r1=sum(R1);
r2=sum(R2);
g1=sum(G1);
최종출력=sum(출력);
tick++;
}
팩토리오 코딩 재밌다 모두 코딩공부해보자!!
아 중간에 오타났네. B1이 아니고 G1
과제하고 게임하는데 왜 또 과제를 해야하지 - dc App
코드 써놓는거보단 그냥 시스템 해석하는게 더 편한건 왜지?
그래도 단순 래치를 신호기 1개로 해결한건 좀 괜찮네 ㅇㅇ 참고 하고 간다.
허...어..미 쉽뻘....
이거 해서 어디에 씀? 회로알못이라 어디에 써먹는지 모름
컴공은 이런거 업어도 존나잘이해하고 컴공아니면 이거봐도 먼소린지 머름.. - dc App
회로 1도 모르는데 위에 래치 이야기 해서 뭔지 찾아보니깐 RS래치는 작동조건 넣으면 그 값에서 왔다갔다 하면서 깜박이는거 방지할 때 유용하게 쓸 수 있을 것 같네 ㄳㄳ
개추