프로젝트/개인 프로젝트

Central Dogma C프로그램(1)_코돈 입력 시 아미노산 출력

프리_ 2021. 11. 11. 12:11
반응형

시작하게 된 배경

 과제하던 중에 너무 고통스러워서 도피처를 찾고 있던 와중에 갑자기 Central Dogma가 생각났다. 그렇게 DNA, mRNA, Amino acid sequence를 결과로 나타내는 코드를 만들어 보고 싶어져서, 코드 작성을 시작했다.

목표

 DNA, mRNA, Amino Acid 셋 중 하나의 sequence를 입력받고, 입력한 값에 대한 다른 분자의 sequence를 출력받는다.

1. 시작 시 Sequence를 입력할 분자를 DNA, mRNA, Amino acid 중 하나를 선택한다.

2. DNA 주형가닥의 sequence를 입력 시, 그와 상보적으로 결합하는 DNA 가닥의 sequence, 주형가닥에서 전사되는 mRNA와 번역되는 Amino acid의 sequence를 출력한다.

3. mRNA의 sequence를 입력 시, Amino acid의 sequence를 출력한다.

4. 단, Amino acid의 sequence는 mRNA sequence 중 개시 코돈부터 종결 코돈까지만 번역하여 출력된다.

5. 코드는 가능한 효율적으로 작성하되, 효율을 중시하지는 않는다.

입력 Sequence 출력 Sequence
DNA 주형가닥 DNA, mRNA, Amino acid
mRNA Amino Acid
Amino acid  

용어

 여기서 사용된 용어는 다음 접은 글에서 확인하기 바란다.

더보기

 Central Dogma: 중심 원리. DNA, RNA, 단백질의 복제, 전사, 번역이 흘러가는 과정.

 DNA: 디옥시리보핵산.

 RNA: 리보핵산.

 mRNA: 메신저 RNA. DNA로부터 핵 내에서 전사되며, 특정한 단백질을 합성하기 위해 핵 바깥으로 나가 리보솜과 결합한다.

 Amino acid: 아미노산. 단백질을 구성하는 단위체.

 Replication: 복제.

 Transcription: 전사. DNA로부터 mRNA를 합성하는 것.

 Translation: 번역. mRNA로부터 단백질을 합성하는 것.

 Sequence: 서열.

 코돈: Codon. Amino acid를 지정하는 mRNA의 세 개의 염기 그룹.


과정

코돈 입력 시 Amino Acid 출력

 먼저 mRNA의 코돈을 입력받아 지정하는 Amino acid를 출력하는 코드를 작성해 보자. 먼저 코돈을 입력받을 장소를 만들어 주자.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
main()
{
	char N[4] = "\0";  /*코돈 염기서열 3개를 배정할 3칸 +1*/
}

 아래의 코돈표[각주:1]를 참고하여 코돈이 지정하는 Amino acid를 배열을 이용해 저장하자.

[표 1] 코돈표[각주:2]

[표 1] 코돈표

 코돈표는 코돈의 염기 3개와 코돈이 지정하는 Amino acid로 이루어진다. 그러므로 4차원 배열을 이용해보자. Amino acid는 문자이므로 4차원 배열을 이용하겠다. 4차원 배열의 형식은 (자료형) (배열의 이름)[X][Y][Z][W]으로 이루어진다. 우선 저장할 내용은 Amino acid의 이름이므로 자료형은 문자형인 char를 사용한다. 또한, W에는 (가장 긴 이름의 Amino acid의 글자 수+1)만큼의 값을 준다. 코돈 3자리 각각에 들어가는 염기인 아데닌(이하 A), 타이민(이하 T), 구아닌(이하 G), 사이토신(이하 C)을 기준으로 위치를 나누기 위해 X, Y, Z에는 모두 (4+1)의 값을 준다. 이때, X의 인덱스 값은 코돈의 첫 번째 염기, Y의 인덱스 값 코돈의 두 번째 염기, Z의 인덱스 값은 세 번째 염기에 따라 구분하는 지표가 된다. 마지막으로 배열의 이름은 codon_table_2라고 하자. 딱히 특별한 이유는 없다.

	char codon_table_2[4][4][4][5] = {
		{ {"F", "F", "L", "L"}, {"S", "S", "S", "S"}, {"Y", "Y", "stop", "stop"}, {"C", "C", "stop", "W"} },
		{ {"L", "L", "L", "L"}, {"P", "P", "P", "P"}, {"H", "H", "Q", "Q"}, {"R", "R", "R", "R"} },
		{ {"I", "I", "I", "M"}, {"T", "T", "T", "T"}, {"N", "N", "K", "K"}, {"S", "S", "R", "R"} },
		{ {"V", "V", "V", "V"}, {"A", "A", "A", "A"}, {"D", "D", "E", "E"}, {"G", "G", "G", "G"} }
	};

 위에서 선언한 배열을 보면 알 수 있겠지만 X, Y, Z의 인덱스 값이 0인 경우 해당하는 자리에 U를, 1인 경우 C를, 2인 경우 A를, 3인 경우 G를 배정하여 결정된 코돈이 지정하는 Amino acid를 저장한다. 이제 코돈을 입력할 수 있는 코드를 작성하자. 우선  프로그램에서 코돈을 입력하기 전에 입력 예시와 출력 예시를 보여줄 수 있도록 코드를 작성하자.

	printf("입력 예시: UUU (#주의# 코돈 입력은 반드시 대문자로 해주세요.)\n");
	printf("출력 예시: %c \n", codon_table_2[0][0][0][0]);

 입력받을 코돈은 문자열이므로 %s를 이용하여 값을 받는다.

	printf("U = 0, C = 1, A = 2, G = 3\n코돈 입력: "); /* 염기가 저장되는 인덱스 값 */
	scanf("%s", N); /* 코돈을 입력 받아 배열에 저장 */

 코돈의 첫 번째 염기는 N[0]에, 두 번째 염기는 N[1]에, 세 번째 염기는 N[2]에 저장된다. 배열에 값이 제대로 저장되었는지 확인하기 위해 다음 코드를 실행해보자

더보기

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
main()
{
	char N[4] = "\0";
	printf("U = 0, C = 1, A = 2, G = 3\n코돈 입력: ");
	scanf("%s", N);
    printf("%s", N); /* 값이 제대로 저장되었는 지 확인 */
}

입력: UAU

결과: UAU

 

 사실 이것만으로 판단하기에는 문제가 있다. %c를 이용해 각 자리마다 따로따로 출력되도록 하는 것이 더 신뢰도가 높다.


 이제 지정된 Amino acid를 찾아 출력하는 코드를 작성해보자. 우선 각 자리에 어떤 염기가 있는지 확인하는 코드를 작성하자. 배열 N의 인덱스 값을 i로 잡아주면 N[i]에 들어있는 값은 코돈의 i번째 자리에 위치하는 염기가 된다. 또한 temp라는 변수에 위에서 지정한 각 염기의 인덱스 값[각주:3]을 대입해준다. 변수 temp를 사용하는 이유는 후술 하겠다.

	int i, temp;
	i = 0;
		if(N[i] == 'U')
		{
			temp = 0;
		}
		else if(N[i] == 'C')
		{
			temp = 1;
		}
		else if(N[i] == 'A')
		{
			temp = 2;
		}
		else if(N[i] == 'G')
		{
			temp = 3;
		}
		else
		{
			printf("ERORR_CODE_%d잘못된 입력입니다.\n다시 입력해주십시오.\n", i);
			return main();
		}
        /* 특정 자리에 어떤 염기가 있는지 판별 */

 첫 번째 염기는 N[0], 두 번째 염기는 N[1], 세 번째 염기는 N[2]에 저장되므로 위 코드에서 i 값을 0부터 1씩 증가시켜 2까지 확인할 수 있다. 그러므로 반복문을 이용하여 조건에 맞춰 자동으로 염기의 종류를 판단하도록 하자.

	for(i = 0; i < 3; i++) /* 코돈 세 자리의 염기 종류 판별 */
	{
		if(N[i] == 'U')
		{
			temp = 0;
		}
		else if(N[i] == 'C')
		{
			temp = 1;
		}
		else if(N[i] == 'A')
		{
			temp = 2;
		}
		else if(N[i] == 'G')
		{
			temp = 3;
		}
		else
		{
			printf("ERORR_CODE_%d잘못된 입력입니다.\n다시 입력해주십시오.\n", i);
			return main();
		}
	}

 자, 염기의 종류를 판단했으니 이제 해당 염기에 따른 값을 특정 변수에 지정해주자. 변수에 대해 먼저 설명하자면 위 배열 codon_table_2의 X, Y, Z 자리에 들어갈 인덱스 값을 각각 변수 x, y, z를 이용해 지정해 준다. 앞서 언급했듯이 i의 값은 반복문의 횟수 역할도 하지만 코돈의 자리라는 의미가 더 크다. 다시 서술하자면 i의 값이 0, 1, 2라는 의미는 각각 코돈의 첫 번째 염기 자리, 두 번째 염기 자리, 세 번째 염기 자리이다. 그러므로 i의 값이 0, 1, 2일 때 판단한 염기와 동일한 염기가 각각 배열 codon_table_2의 X, Y, Z 위치에 들어가 Amino acid를 지정해주어야 한다. 여기서 앞서 선언한 변수 temp를 이용한다. 변수 temp는 염기의 종류에 따라 값이 결정된다. 또한, 그 값이 곧 배열 codon_table_2의 염기 종류에 따른 인덱스 값과 일치하므로 다른 처리를 하지 않고, temp의 값을 x, y, z에 대입해주면 된다. 다만 값을 대입하는 조건은 <i의 값이 0일 때 x에, i의 값이 1일 때 y에, i의 값이 2일 때 z에 temp의 값을 대입한다.>이다.

	int x, y, z;
			if(i == 0)
			{
				x = temp;
			}
			else if(i == 1)
			{
				y = temp;
			}
			else if(i == 2)
			{
				z = temp;
			}
			else
			{
				printf("코드에 오류가 있습니다.\n");
			}
			/* 판별한 염기에 지정되어 있는 인덱스 값 대입 */

 정상적으로 값이 저장되었는지 확인하는 단계를 가지기 위해 아래와 같은 코드를 작성했다. 변수 x, y, z는 0부터 3까지의 정수만을 값으로 가질 수 있으니 그 값이 아니면 앞서 작성한 코드에 문제가 있으면 오류 메시지를 출력하도록 코드를 작성했다. [각주:4] 이뿐만 아니라 프로그램에 입력하는 값이 잘못된 경우에도 이 오류 메시지를 출력하도록 작성했다. 오류 메시지가 출력된 이후, 프로그램이 처음의 코돈 입력으로 돌아가 다시 시작하도록 작성했다.

	if(x>3 || y > 3 || z > 3 )
	{
			printf("ERORR_CODE_123잘못된 입력입니다.\n다시 입력해주십시오.\n");
			return main();
	}
    /* 잘못된 입력 확인 +코드 오류 확인 */

 변수 x, y, z에 정상적인 값이 저장된 경우, 값의 인덱스 값을 출력하고, 아래에 코돈이 지정하는 Amino acid를 출력하도록 작성했다. Amin acid는 배열 codon_table_2에 문자 하나하나가 저장되므로 전체 글자를 하나하나 출력해주어야 한다. 이는 반복문을 이용해 해결했다. 이 과정이 잘못될 경우 역시 오류 메시지가 출력되도록 코드를 작성했다.

	int j;
	j = 0;
	else
	{
		printf("%d, %d, %d\n", x, y, z);
		printf("translation: ");
		while(codon_table_2[x][y][z][j] != '\0')
		{
			if(codon_table_2[x][y][z][j] != ' ')
			{
				printf("%c", codon_table_2[x][y][z][j]);
			}
			else
			{
				printf("ERORR_CODE_123잘못된 입력입니다.\n다시 입력해주십시오.\n");
			}
			j++;
		}
		printf("\n");
	}
    /* 코돈이 지정하는 Amino Acid 출력 +코드 오류 확인 */

프로그램 실행 및 종료 판단 코드

 여기까지만 작성해도 프로그램이 돌아가는 것에는 문제가 없다. 그러나 심심하므로 프로그램을 한번 더 실행하거나 종료하는 코드를 작성하고자 한다. 0을 입력하면 프로그램을 종료하고, 1을 입력하면 계속 실행하도록 프로그램을 작성하자. 우선 프로그램을 실행했을 때, 값을 입력받는 코드를 작성하자.

	int stop;
	printf("\n종료: 0, 계속 실행: 1 \n 입력: ");
	scanf("%d", &stop);

 if 구문을 사용하여 입력받은 값에 따라 다음 실행할 명령을 입력한다. 다만 0, 1이 아닌 값을 입력받을 경우, 오류 메시지가 출력되도록 작성한다.

	if(stop == 1)
	{
		return main();
	}
	else if(stop == 0)
	{
		exit(0);
	}
	else
	{
		printf("ERORR_CODE_stop잘못된 입력입니다.");
		exit(0);
	}

현재 단계에서 작성한 코드 결과물

더보기

현재 단계에서 작성한 코드 결과물

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
main()
{
	int i, j, temp;
	int x, y, z, w;
	int stop;
	stop = 2;
	j = 0;
	x = 5, y = 5, z = 5;
	char N[4] = "\0";
	char codon_table_2[4][4][4][5] = {
		{ {"F", "F", "L", "L"}, {"S", "S", "S", "S"}, {"Y", "Y", "stop", "stop"}, {"C", "C", "stop", "W"} },
		{ {"L", "L", "L", "L"}, {"P", "P", "P", "P"}, {"H", "H", "Q", "Q"}, {"R", "R", "R", "R"} },
		{ {"I", "I", "I", "M"}, {"T", "T", "T", "T"}, {"N", "N", "K", "K"}, {"S", "S", "R", "R"} },
		{ {"V", "V", "V", "V"}, {"A", "A", "A", "A"}, {"D", "D", "E", "E"}, {"G", "G", "G", "G"} }
	};
	printf("입력 예시: UUU (#주의# 코돈 입력은 반드시 대문자로 해주세요.)\n");
	printf("출력 예시: %c \n", codon_table_2[0][0][0][0]);
	printf("U = 0, C = 1, A = 2, G = 3\n코돈 입력: ");
	scanf("%s", N);
	for(i = 0; i < 3; i++)
	{
		if(N[i] == 'U')
		{
			temp = 0;
			if(i == 0)
			{
				x = temp;
			}
			else if(i == 1)
			{
				y = temp;
			}
			else if(i == 2)
			{
				z = temp;
			}
			else
			{
				printf("코드에 오류가 있습니다.\n");
			}
		}
		else if(N[i] == 'C')
		{
			temp = 1;
			if(i == 0)
			{
				x = temp;
			}
			else if(i == 1)
			{
				y = temp;
			}
			else if(i == 2)
			{
				z = temp;
			}
			else
			{
				printf("코드에 오류가 있습니다.\n");
			}
		}
		else if(N[i] == 'A')
		{
			temp = 2;
			if(i == 0)
			{
				x = temp;
			}
			else if(i == 1)
			{
				y = temp;
			}
			else if(i == 2)
			{
				z = temp;
			}
			else
			{
				printf("코드에 오류가 있습니다.\n");
			}
		}
		else if(N[i] == 'G')
		{
			temp = 3;
			if(i == 0)
			{
				x = temp;
			}
			else if(i == 1)
			{
				y = temp;
			}
			else if(i == 2)
			{
				z = temp;
			}
			else
			{
				printf("코드에 오류가 있습니다.\n");
			}
		}
		else
		{
			printf("ERORR_CODE_%d잘못된 입력입니다.\n다시 입력해주십시오.\n", i);
			return main();
		}
	}
	if(x>3 || y > 3 || z > 3 )
	{
			printf("ERORR_CODE_123잘못된 입력입니다.\n다시 입력해주십시오.\n");
			return main();
	}
	else
	{
		printf("%d, %d, %d\n", x, y, z);
		printf("translation: ");
		while(codon_table_2[x][y][z][j] != '\0')
		{
			if(codon_table_2[x][y][z][j] != ' ')
			{
				printf("%c", codon_table_2[x][y][z][j]);
			}
			else
			{
				printf("ERORR_CODE_123잘못된 입력입니다.\n다시 입력해주십시오.\n");
			}
			j++;
		}
		printf("\n");
	}
	printf("\n종료: 0, 계속 실행: 1 \n 입력: ");
	scanf("%d", &stop);
	if(stop == 1)
	{
		return main();
	}
	else if(stop == 0)
	{
		exit(0);
	}
	else
	{
		printf("ERORR_CODE_stop잘못된 입력입니다.");
		exit(0);
	}
}

코드의 사용

 이 코드를 바탕으로 코돈을 입력받아 Amino acid를 지정하는 함수를 작성할 것이다. 이는 최종적으로 작성할 Central Dogma 프로그램, 다시 말해 특정 Sequence를 입력받아 복제, 전사, 번역의 결과로 나타나는 Sequence를 출력하는 프로그램에서 사용할 것이다.


추가

 귀찮을만한데 코드 만들어와라고 하니 군말 없이 파이썬으로 코드를 만들어 온 친구에게 감사를 전한다.

https://com-king.tistory.com/29

 

파이썬 아미노산 번역

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455#made by enable7997 genetic_code = {"Phe":["UUU","UUC"],"Leu":["UUA","UUG"],"Ser":["UCU","UCC","UCA","UCG"],"Tyr":["UAU","UAC"],"Stop":["UAA","UAG","UGA"],

com-king.tistory.com

더 만들어오라고 시킬 거 없나


  1. 아래의 [표 2] Amino acid의 명칭과 약자, R group의 특징을 참고하길 바란다.

    [본문으로]

  2. [표 2] Amino acid의 명칭과 약자, R group의 특징

    [표 2] Amino acid의 명칭과 약자, R group의 특징

    [본문으로]

  3. U는 0, C는 1, A는 2, G는 3

    [본문으로]

  4. 실제로 여기까지 작성하고 코드를 실행하는 과정에서 컴파일은 문제가 없었으나 입력에 따른 결과가 제대로 나오지 않아 코드를 여러 차례 수정했다.

    [본문으로]

반응형