[디렉토리 이동]

cd 

예시) cd C:\       (띄어쓰기 등이 있는 경우는 "  " 로 감싸주기)

 

[파일 확인]

dir

예시) dir

 

(공통 옵션)

/s - 하위목록도 삭제

/q - 삭제여부 확인 x

 

[파일 삭제]

del

예시) del /s /q *.txt

 

[폴더 삭제]

rmdir

예시) rmdir /s /q C:\temp\....

MSBuild.exe 파일의 경로를 찾아줍니다.

 

 ex) 전 2019 Community 버전을 사용하고 있습니다.

    C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin

 

text 파일로 아래와 같이 작성을 해준 후 .bat 파일로 저장하면 완성입니다!

 

:msbuild 파일이 있는 곳으로 이동 (참고로 배치에서 : 은 주석!)
cd C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin

:빌드할 솔루션 지정
msbuild C:\Users\dlaeh\source\repos\WindowsFormsApp1\WindowsFormsApp1.sln

: 결과를 보고 싶으면 pause 명령을 통해 멈춰줍니다.
pause

 

해당 배치파일 실행한 결과!!

 

좀 더 옵션을 줄 수도 있습니다.

 

:msbuild 파일이 있는 곳으로 이동
cd C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin

:빌드할 솔루션 지정
msbuild C:\Users\dlaeh\source\repos\WindowsFormsApp1\WindowsFormsApp1.sln /t:Rebuild /p:Configuration="Release" /p:Platform="Any CPU"

:/t:Rebuild 		재빌드
:/p:Configuration="Release"   	디버그 혹은 릴리즈 혹은 사용자 지정 세팅
:/p:Platform="Any CPU"  	타겟 플랫폼 지정
:/v:quiet 			조용히 빌드하기 

: 결과를 보고 싶으면 pause 명령을 통해 멈춰줍니다.
pause

 

Configuration과 Platform 은 구성 관리자에서 추가도 가능합니다.

 

 

'기타 > 유용한 것' 카테고리의 다른 글

[cmd] 명령어 정리하기  (0) 2024.04.20
SFTP 구축 및 연결 (freeFTPd, WinSCP/FileZilla)  (0) 2023.04.09
NSIS 설치 파일 만들기  (0) 2022.08.18

 

 

SFTP 구축 및 연결.pdf
0.19MB

 

 

FTP (File Transfer Protocol)  :   파일 폴더 공유

SFTP (Secure File Transfer Protocol) :  암호화로 통신되는 파일 폴더 공유

 

SFTP 사용을 위해 간단히 정리해보았습니다.

 

서버는 freeFTPd(SFTP무료, FTP무료) 또는 Filezilla(SFTP 유료, FTP무료)

로 사용 되고,

 

클라이언트 (접속) 은 WinSCP / FileZilla 가능합니다.

c++ 랜덤 코드!

 

https://learn.microsoft.com/ko-kr/cpp/standard-library/random?view=msvc-170 

 

<random>

자세한 정보:

learn.microsoft.com

 

#include <iostream>
#include <random>

using namespace std;

int main()
{
	random_device rd;
	mt19937 gen(rd());
	uniform_int_distribution<int> distribution(0, 10); // 0 ~ 10
	
	for (int i = 0; i < 10; ++i)
	{
		cout << distribution(gen) << endl;
	}
}

NSIS : Nullsoft Scriptable Install System

 검색 창에 NSIS 를 치면 다운받아서 설치파일을 만들 수 있습니다.

인터넷 검색을 통해 기본적인 설치에 필요한 것들을 모아두었습니다.

절대 경로로 입력하거나 현재 .nsi 파일 위치를 기준으로 파일 등이 인식됩니다.

("License.txt" 같은 경우가 .nsi 파일과 함께 있는 경우입니다.)

#!define 명칭은 ${이름} 식으로 사용할 수 있습니다.
#주석은 " ; " , " # " , " /* */ " 입니다.

!define PRODUCT_FILENAME "MyProject"	# ${PRODUCT_FILENAME} 식으로 "MyProject" 문자열 사용이 가능합니다.
!define PRODUCT_NAME "Product"
!define PRODUCT_VERSION "22.08.10.1"
!define PRODUCT_PUBLISHER "MyHome"
!define PRODUCT_WEB_SITE "http://www.~~~.com"

#제어판에 삭제하기 등록하기 위한 레지스트리 경로입니다.
#!define PRODUCT_UNINST_ROOT_KEY "HKLM"

!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_FILENAME}"

!include "MUI.nsh"  	# Modern User Interface GUI 제공을 위해 사용해줍니다.
!include "LogicLib.nsh" 	# if, for 문 등을 사용하기 위해 선언 됩니다.

#!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"            #해당 경로 아이콘 사용 (기본값)
#!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"      #해당 경로 아이콘 사용 (기본값)

#각각의 순서도 중요합니다. 순서에 따라 인스톨 후 설정, 설정 후 인스톨 등이 진행될 수 있습니다.
!insertmacro MUI_PAGE_WELCOME          	         #환영메시지 (없으면 바로 설치 진행)
!insertmacro MUI_PAGE_LICENSE "License.txt" 	 #라이센스 파일이 있다면 등록하여 보여줍니다.

#!insertmacro MUI_PAGE_COMPONENTS 	#각 섹션마다 설치할지 말지 선택할 수 있게 보여줍니다.

!insertmacro MUI_PAGE_DIRECTORY		#파일 설치 위치 지정      $INSTDIR 이 됩니다.
!insertmacro MUI_PAGE_INSTFILES         #설치과정 페이지 (없으면 에러남)
!insertmacro MUI_PAGE_FINISH            #종료메시지 (없으면 설치 후 바로 종료)
!insertmacro MUI_LANGUAGE "korean"     	#언어 (가장 마지막에 써줘야 에러가 안난다고 합니다.)

#제어판에 등록할 이름 (아직 미사용)
Name "${PRODUCT_FILENAME} ${PRODUCT_VERSION}"

#프로그램 설치 파일 이름
OutFile "${PRODUCT_FILENAME}.exe"

#설치할 위치 $INSTDIR 을 통해 접근이 가능합니다.
InstallDir "C:\MyProject"

#설치 기본은 SilentInstall normal 이고 SilentInstall 모드면 백그라운드에서 진행되며
#트로이 목마로 인식된다고 합니다.
SilentInstall normal

#변수 선언 (변수 사용해보기 위해 선언했습니다.)
Var defaultPath

#Section + [옵션] + [섹션 이름] + [섹션 ID]
#https://wonsx.tistory.com/27?category=539749
Section "Install"

 StrCpy $defaultPath "$INSTDIR" #변수 defaultPath = $INSTDIR 로 설정해줍니다.
 
 #execwait 프로그램 실행 후 종료까지 기다립니다.
 #execwait ".\WindowsViewCapture.exe"

 SetOutPath "$defaultPath"   #Install 영역 설치 시 등록 된 파일들은 해당 폴더에 저장됩니다.
 SetOverwrite on               #덮어쓰기 모드

 #폴더 생성 (SetOutPath에 대해선 폴더가 자동으로 생성 됩니다.)
 # CreateDirectory "$defaultPath\Test1"

 #파일 등록  (.은 현재 위치 기준, 생략 해도 현재 위치 기준)
 File ".\Files\Test.exe"         # == "Files\Test.exe"

 #레지스트리 등록
/*
 HKCR or HKEY_CLASSES_ROOT
 HKLM or HKEY_LOCAL_MACHINE
 HKCU or HKEY_CURRENT_USER
 HKU or HKEY_USERS
 HKCC or HKEY_CURRENT_CONFIG
 HKDD or HKEY_DYN_DATA
 HKPD or HKEY_PERFORMANCE_DATA
 SHCTX or SHELL_CONTEXT
*/
 
 #shell open command 에 인자값 1개 받도록 입력 및 url protocol 생성
 WriteRegStr HKCR "${PRODUCT_FILENAME}\shell\open\command" "" "$\"$INSTDIR\Test.exe$\" $\"%1$\""
 WriteRegStr HKCR "${PRODUCT_FILENAME}" "URL Protocol" ""

 #실행 시 경고 메시지 뜨지 않게 설정해줍니다.
 WriteRegDWORD HKCU "Software\Microsoft\Internet Explorer\ProtocolExecute\${PRODUCT_FILENAME}" "WarnOnOpen" 00000000 

/* 파일이 있는 경우 설치 진행 or 취소 등
 
 iffileexists "경로" YES NO
 YES:
  ...
  goto END
 NO:
  ...
 END:
*/

 #제어판에서 삭제가 가능하도록 HKLM Uninstall 레지스트리를 등록해줍니다.
 WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\AppMainExe.exe"
 WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_FILENAME}"
 WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
 WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
 WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"

 #삭제파일을 만들어줍니다.
 WriteUninstaller "$INSTDIR\Uninstall.exe"

 #완료 시 닫기
 #SetAutoClose true

SectionEnd

Section "ShortCut"
 #바로가기 생성 CreateShortCut "바로가기 만들 위치.lnk" "바로가기 만들 파일"
 CreateShortCut "$DESKTOP\TestShortCut.lnk" "$defaultPath\Test.exe" #파일 이름 변수로 주고 하면 될듯
SectionEnd

Function un.onUninstSuccess
  HideWindow
  MessageBox MB_ICONINFORMATION|MB_OK "${PRODUCT_FILENAME}는(은) 완전히 제거되었습니다."
FunctionEnd

Function un.onInit
  MessageBox MB_ICONQUESTION|MB_YESNO "${PRODUCT_FILENAME}를(을) 제거하시겠습니까?" IDYES pass
   Abort
pass:
FunctionEnd

#언인스톨러는 추가 된 모든 파일들을 직접 입력해서 삭제해주면 됩니다.
Section un.Uninstall

 #파일 삭제해주기 (파일이 추가 된 만큼 혹은 폴더 채로 삭제해줍니다)
 Delete "$INSTDIR\Test.exe"
 Delete "$INSTDIR\Uninstall.exe"
 Delete "$DESKTOP\TestShortCut.lnk"

 #레지스트리 내용 삭제
 #커스텀 URI 등록 삭제
 DeleteRegKey HKCR "${PRODUCT_FILENAME}"
 
 #실행 시 경고 메시지 안뜨게 하는거 삭제
 DeleteRegKey HKCU "Software\Microsoft\Internet Explorer\ProtocolExecute\${PRODUCT_FILENAME}"
 
 #제어판에 보여지는 레지스트리 삭제
 DeleteRegKey HKLM "${PRODUCT_UNINST_KEY}"

 #폴더 삭제 RMDir /r "$INSTDIR" 을 통해 폴더의 모든 파일들을 삭제해줄 수도 있습니다.
 RMDir "$INSTDIR"
 
 #자동으로 종료
 SetAutoClose true

SectionEnd

C++은 포인터를 통해 메모리에 접근할 수 있고, 함수에 대한 메모리도 가리킬 수 있습니다.

 

   반환값 함수명 (매개변수)

 

반환 값과 매개변수가 같은 함수 포인터 변수를 선언해주면 됩니다.

 

Test1, Test2 를 접근하기 위해

void (*fp) (int, int);

 

선언을 통해 fp (함수 변수명)로 해당 함수를 부를 수 있게 됩니다!

 

#include <stdio.h>

void Test1(int value1, int value2)
{
	printf("======Test1======\n");
	printf("value1 : %d\n", value1);
	printf("value2 : %d\n", value2);
}

void Test2(int value1, int value2)
{
	printf("======Test2======\n");
	printf("value1 : %d\n", value1 + 10);
	printf("value2 : %d\n", value2 + 10);
}

int main()
{
	void (*fp)(int, int); //void ??? (int , int) 함수에 접근 가능합니다.

	fp = Test1;
	fp(10, 10);

	printf("\n");

	fp = Test2;
	fp(10, 10);
}

 

실행 결과

 

https://ko.wikipedia.org/wiki/RSA_%EC%95%94%ED%98%B8

 

RSA 암호 - 위키백과, 우리 모두의 백과사전

RSA 암호는 공개키 암호시스템의 하나로, 암호화뿐만 아니라 전자서명이 가능한 최초의 알고리즘으로 알려져 있다. RSA가 갖는 전자서명 기능은 인증을 요구하는 전자 상거래 등에 RSA의 광범위한

ko.wikipedia.org

위의 내용을 참고하였습니다.

 

RSA 방식 간단한 소개

공개키 <e, n>

개인키 <d, n>

암호화 작업 복호화 작업
메시지^d % n 메시지^e % n
메시지^e % n 메시지^d % n

d와 e는 서로 암호화 및 복호화에 필요하며 e만 공개하고

d는 개인키로 숨겨둬야 됩니다.

 

공개키와 개인키를 구하는 방법을 살펴보겠습니다.

사실 엄청나게 큰 소수를 선택하여 d를 계산해내지 못하게 해야되지만

지금은 작은 숫자를 통해 동작을 살펴보았습니다. 

 

소수 2개 (p, q)를 입력받습니다.  p = 23, q = 29

n = p * q 로 정의해줍니다. (n = 667)

오일러피 함수 (n) = (23 - 1) * (29 - 1) 을 얻고,

 오일러피 함수 결과와 서로소인 값을 하나 선택합니다. 해당 값이 공개키 e 값이 됩니다. e = 307을 선택하였습니다.

 

개인키 d를 구합니다. d는 e * d % n == 1 이 되는 d값을 구해주면 됩니다.

d = 2155를 선택하였습니다.

 

공개키와 개인키가 만들어졌습니다. 이제 메시지를 작성해봅니다.

이 때 n이 충분히 크지 않다면..! 아래 결과 내용을 읽어보시길..

"암호화할 메시지 입니다~~ !@#$$% 1234567" 까지가 메시지 입니다.

 

암호화 한 후 출력, 이 후 다시 복호화한 작업입니다.

 

 

기본 개념

 

1. 공개키와 개인키는 서로 암호화/복호화 작업에 필요한 키입니다.

2. 공개키 e는 외부에 공개하지만 d는 개인키로 알려져선 안됩니다. d는 복호화 작업에 쓰이는 중요한 키입니다.

 

키 생성 방법

1. 소수 2개 (p, q)를 고릅니다.

2. 둘의 곱 n = p * q 를 얻습니다.

3. 오일러phi (n) 값을 구합니다. n = 소수 * 소수 이므로

   eulerPhi = (p - 1) * (q - 1) 를 얻습니다.

(오일러피 함수 : 

https://ko.wikipedia.org/wiki/%EC%98%A4%EC%9D%BC%EB%9F%AC_%ED%94%BC_%ED%95%A8%EC%88%98)

 (오일러피 함수 (n)은 n보다 작고 n과 서로소인 (서로소: 최대 공약수가 1인 숫자) 숫자의 개수를 의미합니다.

오일러피 함수의 성질에 따라 두 소수는 (p - 1) * (q - 1) 로 정의됩니다.)

  •  phi(소수) = 소수 - 1
  •  phi(소수1 * 소수2) = phi(소수1) * phi(소수2) = (소수1 - 1) * (소수2 - 1)

4. eulerPhi 보다 작고 eulerPhi와 서로소인 정수 e를 찾아 선택합니다. (e가 공개키가 됩니다.)

5. d * e % eulerPhi == 1 인 d를 찾습니다. (d가 개인키가 됩니다.)

6. 최종적으로 키가 생성됩니다.

 <e, n> 공개키,    <d, n> 개인키

 

암호화 방법

 메시지를 e번 제곱해주고 n으로 나눈 나머지를 얻습니다.

 

복호화 방법

 메시지를 d번 제곱해주고 n으로 나눈 나머지를 얻습니다.

 

주의사항) n은 우리가 사용하는 문자 값보다 커야됩니다.

 n이 'A' (65) 보다 작다면 A라는 의미를 잃어버리기 때문입니다.

 

프로그램에선 숫자가 너무 커지므로 제곱할 때마다 n으로 나눠주고 있습니다.

코드가 좀 길어서 제가 다시 볼지 모르겠습니다 ㅋㅋ;

 

코드 흐름

1. InitPrime() : 에라토스테네스의 체를 통해 notPrime배열에 소수를 구해두기

2. 소수 p, q를 입력받기

3. 오일러피 값을 구합니다. eulerPhi = (p - 1) * (q - 1)

4. GetRelativePrime() : eulerPhi 에 서로수인 숫자를 구합니다. (최대공약수를 찾기 위해 GCD 가 쓰입니다)

5. 공개키 e 입력 받기

6. FindPrivateDKey() : 개인키 후보를 찾습니다.

7. 개인키 d 입력 받기

8. 문자열 입력

9. Encryption() : 암호화 및 출력

 (여기서 char 배열에서 int 배열로 바꿔서 저장합니다.

 char는 1byte (=8bit) 최대 255까지밖에 표현되지 않아 값을 잃어버리기 때문입니다.)

10. Decryption() : 암호를 복호화하여 출력

 

#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int MaxSize = 10000;
const int Size = 100;
const int LineLength = 14;

bool notPrime[MaxSize];
bool relativePrime[MaxSize]; //서로소
char input[100];
int encryptToInt[100];

vector<long long> dList;

void InitPrime()
{
	notPrime[0] = notPrime[1] = true;

	for (int i = 2; i * i <= MaxSize; ++i)
	{
		if (notPrime[i])
		{
			continue;
		}

		for (int j = i * i; j <= MaxSize; j += i)
		{
			notPrime[j] = true;
		}
	}
}

void PrintPrime(int enterLine, int size)
{
	printf("====소수 목록====\n");
	int line = 0;
	for (int i = 2; i < Size; ++i)
	{
		if (notPrime[i])
		{
			continue;
		}

		printf("%3d ", i);
		line++;

		if (line >= enterLine)
		{
			line = 0;
			printf("\n");
		}
	}
}

int GCD(int a, int b) //Greatest Common Divisor 최대 공약수 찾기
{
	while (b != 0)
	{
		int c = a % b;
		a = b;
		b = c;
	}

	return a;
}

void GetRelativePrime(int enterLine, int phi)
{
	int line = 0;
	for (int i = 1; i < phi; ++i)
	{
		if (GCD(i, phi) == 1)
		{
			line++;
			printf("%3d ", i);
			relativePrime[i] = true;
			
			if (line >= enterLine)
			{
				line = 0;
				printf("\n");
			}
		}
	}
}

void FindPrivateDKey(int e, int eulerPhi, int many)
{
	for (long long d = 1; dList.size() < many; ++d)
	{
		if (d * e % eulerPhi == 1)
		{
			dList.push_back(d);
			printf("[%d]번째 가능한 개인키 d = %lld [ %lld * %d %% %d = 1 ]\n", dList.size(), d, d, e, eulerPhi);
		}
	}
}

int Pow(int value, int e, int n)
{
	int v = value;
	for (int i = 1; i < e; ++i)
	{
		v = v * value % n;
	}
	return v;
}

void Encryption(int e, int n)
{
	char encryptForPrint[100] = { 0 };
	int length = strlen(input);

	for (int i = 0; i < length; ++i)
	{
		int value = Pow(input[i], e, n);

		//char는 1바이트로 8bit, 최대 2^8 (256) 까지밖에 표현이 불가능하여
		//값이 256을 넘으면 오버플로우 발생
		encryptToInt[i] = value; 
		encryptForPrint[i] = value;
	}

	printf("%s\n", encryptForPrint);
}

void Decryption(int d, int n)
{
	char decryptForPrint[100] = { 0 };
	int length = strlen(input);

	for (int i = 0; i < length; ++i)
	{
		decryptForPrint[i] = Pow(encryptToInt[i], d, n);
	}
	printf("%s\n", decryptForPrint);
}

int main()
{
	int p, q, n, e;
	long long d;

	InitPrime();
	PrintPrime(LineLength, Size);
	printf("\n\n두 개의 소수를 입력하세요.\n");
	
	while (true)
	{
		scanf("%d %d", &p, &q);
		if (notPrime[p] || notPrime[q])
		{
			printf("\n소수를 다시 입력하세요.\n");
			continue;
		}

		break;
	}

	n = p * q; //[중요] n보다 작은 값들에 대해서만 암호화가 가능하다!!! % n 으로 나누어주기 때문이다.

	int eulerPhi = (p - 1) * (q - 1);
	printf("\n오일러 피 함수 값 %d * %d = %d\n", (p - 1), (q - 1), eulerPhi);
	printf("====%d와 서로수인 수====\n", eulerPhi);
	GetRelativePrime(LineLength, eulerPhi);
	printf("\n\n");

	while (true)
	{
		scanf("%d", &e);
		if (relativePrime[e])
		{
			break;
		}
		else
		{
			printf("\n서로수인 수를 입력해야됩니다.\n");
		}
	}

	FindPrivateDKey(e, eulerPhi, 5); //5개를 구해보자
	printf("\n개인키를 입력하세요.\n");

	while (true)
	{
		scanf("%lld", &d);
		
		bool isContain = false;

		for (int i = 0; i < dList.size(); ++i)
		{
			if (dList[i] == d)
			{
				isContain = true;
				break;
			}
		}

		if (isContain)
		{
			break;
		}
		else
		{
			printf("\n올바른 개인키를 입력해야 됩니다.\n");
		}
	}

	printf("\n\n 공개키 [e = %d, n = %d], 개인키 [d = %lld, n = %d]\n\n", e, n, d, n);

	printf("100문자 이내로 평문을 작성해보세요.\n");
	printf("(단 n의 크기가 해당 문자를 나타내는 숫자보다 작다면 변환값을 잃게 됩니다.)\n");
	printf("ex) 'A' = 65, n = 42라면 65값을 잃게 됩니다.\n\n");

	getchar(); //버퍼에 엔터키 제거용
	gets_s(input);

	printf("\n평문을 암호화 합니다.\n");
	Encryption(e, n);

	printf("\n==============================================\n");

	printf("\n평문을 복호화 합니다.\n\n");
	Decryption(d, n);

	return 0;
}

 

https://ko.wikipedia.org/wiki/%EC%9C%A0%ED%81%B4%EB%A6%AC%EB%93%9C_%ED%98%B8%EC%A0%9C%EB%B2%95

 

유클리드 호제법 - 위키백과, 우리 모두의 백과사전

유클리드 호제법(-互除法, Euclidean algorithm) 또는 유클리드 알고리즘은 2개의 자연수 또는 정식(整式)의 최대공약수를 구하는 알고리즘의 하나이다. 호제법이란 말은 두 수가 서로(互) 상대방 수를

ko.wikipedia.org

 

유클리드 호제법으로도 불립니다.

GCD는 굉장히 간단한 코드라서 외워서 쓸 정도인데 막상 안보고 구현하려니 헷갈려서

유도 방식을 직접 써서 생각해보게 되었습니다.

 

GCD (21, 12)     (참고로 GCD(12, 21)을 해도 12 % 21 = 12로 21 % 12로 바뀜)

21 % 12 = 9        
    12 % 9 = 3    
        9 % 3 = 0

GCD (21, 12) = 3

 

위의 숫자들을 그대로 가져와서 써주면 됩니다.

#include <iostream>

using namespace std;

int GCD(int a, int b)
{
	while (b != 0)
	{
		int c = a % b;
		a = b;
		b = c;
	}

	return a;
}

int main()
{
	cout << GCD(21, 12);
}

 

추가적으로 a와 b의 최대 공배수를 구하는 방법은

a * b / GCD(a, b) 로 할 수 있습니다.

 

ex)

8 과 10의 최소 공배수 구하기

8 * 10 / GCD(8, 10)   ( GCD(8, 10) = 2 )

8 * 10 / 2 = 40

클록을 통해 현재 경과한 시간을 알 수 있습니다.

아래 코드에서 5초 동안 돌아가며 i가 증가되는 값을 볼 수 있습니다.

 

#include <iostream>
#include <ctime>

using namespace std;

int main()
{
	clock_t start = clock(); //ms 단위를 반환 합니다. 1s == 1000ms
	int i = 0;
	int second = 0;

	while (second < 5)
	{
		clock_t end = clock();
		i++;
		if (end - start >= 1000)
		{
			second++;
			start = end;
			cout << second << "초 경과 i 값은 " << i << endl;
		}
	}
}

 

실행 결과

 

네이버 지식인에서 어떤 사람이 올렸었는데 재밌어 보여서 완성해본 코드입니다.

목적지에 물건을 옮기는 게임인데 간단하게 만들어봤습니다.

 

#include <stdio.h>
#include <conio.h>  
#include <windows.h> 
#include <string.h>

enum Map { Blank = 0, Wall = 1, Block = 2, Goal = 3, Player = 4 };
enum KeyBoard { RIGHT = 77, LEFT = 75, UP = 72, DOWN = 80 };
const char icon[5][5] = { "..", "■", "★", "_G", "♬" };
const int StageCount = 1;
const int MaxRow = 10;
const int MaxCol = 10;

int gameOver = 0;
int currentStage[MaxRow][MaxCol];
int round;
int preIcon = 0;
COORD playerCoord;

int MAP[StageCount][MaxRow][MaxCol] = 
{
//1round
{
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,3,1},
{1,0,1,1,0,0,0,0,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,0,0,0,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,1,0,0,1},
{1,0,2,0,1,0,4,0,0,1},
{1,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
}
//next..
};

void gotoxy(int row, int col, const char* str)
{
	COORD Pos = { col * 2 + 1, row };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
	printf("%s", str);
}

void ShowMainMessage()
{
	for (int i = 0; i < 10; ++i)
	{
		gotoxy(5, 20 + i, "-");
	}
	for (int i = 0; i < 10; ++i)
	{
		gotoxy(10, 20 + i, "-");
	}

	gotoxy(7, 18, "게임 시작! (Press Any Key)");
}

void drawMap()
{
	for (int row = 0; row < MaxRow; row++)
	{
		for (int col = 0; col < MaxCol; col++)
		{
			int index = currentStage[row][col];

			if (index > Player)
			{
				gotoxy(row, col, "  ");
				continue;
			}

			gotoxy(row, col, icon[index]);
		}
	}
}

void initStageInfo()
{
	for (int row = 0; row < MaxRow; ++row)
	{
		for (int col = 0; col < MaxCol; ++col)
		{
			currentStage[row][col] = MAP[round][row][col];

			if (currentStage[row][col] == Player) 
			{
				playerCoord.Y = row;
				playerCoord.X = col;
			}
		}
	}
}

int CanMove(int row, int col)
{
	return currentStage[playerCoord.Y + row][playerCoord.X + col] != Wall;
}

int IsExistBlock(int row, int col)
{
	return currentStage[playerCoord.Y + row][playerCoord.X + col] == Block;
}

int IsGoal(int row, int col)
{
	return currentStage[playerCoord.Y + row][playerCoord.X + col] == Goal;
}

int CanPush(int row, int col)
{
	return currentStage[playerCoord.Y + row][playerCoord.X + col] == Blank || IsGoal(row, col);
}

void PrintState()
{
	gotoxy(15, 0, "현재 상태\n");
	for (int i = 0; i < MaxRow; ++i)
	{
		for (int j = 0; j < MaxCol; ++j)
		{
			printf("%d ", currentStage[i][j]);
		}
		printf("\n");
	}
}

void tryMove(int row, int col)
{
	if (CanMove(row, col))
	{		
		if (IsExistBlock(row, col))
		{
			//블록을 플레이어가 이동한 방향 + 1 만큼 밀어주기 위해 * 2를 해줌

			if (IsGoal(row * 2, col * 2))
			{
				gameOver = 1;
			}

			if (CanPush(row * 2, col * 2))
			{
				//민 블록을 그려준다.
				currentStage[playerCoord.Y + row * 2][playerCoord.X + col * 2] = Block;
				gotoxy(playerCoord.Y + row * 2, playerCoord.X + col * 2, icon[Block]);

				//현재 위치를 최근 아이콘으로 교체해준다.
				currentStage[playerCoord.Y][playerCoord.X] = preIcon;
				gotoxy(playerCoord.Y, playerCoord.X, icon[preIcon]);
				
				//플레이어 이동 및 갱신
				playerCoord.Y += row;
				playerCoord.X += col;
				currentStage[playerCoord.Y][playerCoord.X] = Player;
				gotoxy(playerCoord.Y, playerCoord.X, icon[Player]);
			}

			//테스트용
			PrintState();
			return;
		}

		//이동 전 기존 아이콘으로 현재 자리를 갱신한다.
		currentStage[playerCoord.Y][playerCoord.X] = preIcon;
		gotoxy(playerCoord.Y, playerCoord.X, icon[preIcon]);

		//최근 아이콘은 앞 칸의 아이콘
		preIcon = currentStage[playerCoord.Y + row][playerCoord.X + col];

		//플레이어 이동 및 갱신
		playerCoord.Y += row;
		playerCoord.X += col;
		currentStage[playerCoord.Y][playerCoord.X] = Player;
		gotoxy(playerCoord.Y, playerCoord.X, icon[Player]);

		//테스트용
		PrintState();
	}
}

int main()
{
	ShowMainMessage();

	//콘솔 버퍼 안보이게 설정
	CONSOLE_CURSOR_INFO ci = { 1, FALSE };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ci);
	getch();
	
	initStageInfo();
	drawMap();

	while (gameOver == 0)
	{
		int key = getch();
		if (key == 0xe0 || key == 0) //방향키는 두번의 입력으로 인식됩니다.
		{
			key = getch();

			switch (key)
			{
				case RIGHT:
					tryMove(0, 1);
					break;
				case LEFT:
					tryMove(0, -1);
					break;
				case UP:
					tryMove(-1, 0);
					break;
				case DOWN:
					tryMove(1, 0);
					break;
			}
		}
	}

	gotoxy(12, 0, "승리! (키를 눌러 종료해주세요.)");
	Sleep(1000);
	getch();
	return 0;
}

+ Recent posts