Drunkard's Walk Problem
주정뱅이의 마구잡이 걸음 문제
- 주정뱅이가 정중앙 기둥에서 시작하여 기둥으로부터 일정 거리를 벗어나기 위해 내딛는 걸음 수를 구하는 프로그램이다.
- 내딛는 한 발 한 발은 이전에 내딛은 걸음의 방향과 무관하게 매번 마구잡이로 걷는다.
- 벗어나고자 하는 거리와 보폭은 사용자로부터 입력받는다.
- 마구잡이식 걸음을 구현하기 위해 표준 라이브러리 함수 중 \(\texttt{rand()}\), \(\texttt{srand()}\), \(\texttt{time()}\) 함수를 사용한다.
- 주정뱅이의 걸음에 대한 방향을 제어하는 자료구조로 사용자 정의 클래스인 \(\texttt{Vector}\) 클래스가 정의되어 있는 \(\texttt{vect.h}\) 헤더파일을 포함시킨다.
vect.h
- 벡터값을 제어하는 \(\texttt{Vector}\) 클래스가 정의되어 있는 헤더파일이다.
- Computer Science에서 흔히 사용하는 컨테이너 \(\texttt{vector}\) 와는 다른 개념이다.
// vect.h
#ifndef VECTOR_H_
#define VECTOR_H_
#include <iostream>
namespace VECTOR {
class Vector {
public:
enum Mode {RECT, POL}; // 직교좌표계 모드와 극좌표계 모드
public:
// 좌표값 데이터 멤버
double x; // 직교좌표계 x좌표
double y; // 직교좌표계 y좌표
double mag; // 극좌표계 반지름 (magnitude)
double ang; // 극좌표계 각도 (angle)
Mode mode;
// 데이터 멤버들의 값을 설정하는 private 메서드
void set_mag();
void set_ang();
void set_x();
void set_y();
public:
// 초기화 함수 및 생성자, 파괴자
Vector();
Vector(double n1, double n2, Mode form = RECT);
~Vector();
void reset(double n1, double n2, Mode form = RECT);
// 데이터 멤버값 출력 함수
double xval() const {return x;}
double yval() const {return y;}
double magval() const {return mag;}
double angval() const {return ang;}
// 좌표계 설정 함수
void polar_mode(); // 좌표계를 극좌표계로 설정한다.
void rect_mode(); // 좌표계를 직교좌표계로 설정한다.
// 연산자 함수
Vector operator+(const Vector& b) const;
Vector operator-(const Vector& b) const;
Vector operator-() const;
Vector operator*(double n) const;
friend Vector operator*(double n, const Vector& a);
friend std::ostream& operator<<(std::ostream& os, const Vector& v);
};
}
#endif
vect.cpp
- \(\texttt{class Vector}\)의 메서드를 정의해놓은 파일이다.
// vect.cpp
#include <cmath>
#include "vect.h"
using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;
namespace VECTOR {
const double Rad_to_Deg = 45.0 / atan(1.0); // 1radian에 대한 degree값
void Vector::set_mag() {
mag = sqrt(x * x + y * y);
}
void Vector::set_ang() {
if (x == 0.0 && y == 0.0)
ang = 0.0;
else
ang = atan2(y, x);
}
void Vector::set_x() {
x = mag * cos(ang);
}
void Vector::set_y() {
y = mag * sin(ang);
}
Vector::Vector () {
x = y = mag = ang = 0.0;
mode = RECT;
}
Vector::Vector(double n1, double n2, Mode form) {
mode = form;
if (form == RECT) {
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (form == POL) {
mag = n1;
ang = n2 / Rad_to_Deg;
set_x();
set_y();
}
else {
cout << "Vector()에 전달된 제 3 매개변수가 잘못되었습니다.\n";
cout << "벡터값을 0으로 설정합니다.\n";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
Vector::~Vector() {
}
void Vector::reset(double n1, double n2, Mode form) {
mode = form;
if (form == RECT) {
x = n1;
y = n2;
set_mag();
set_ang();
}
else if (form == POL) {
mag = n1;
ang = n2 / Rad_to_Deg;
set_x();
set_y();
}
else {
cout << "Vector()에 전달된 제 3 매개변수가 잘못되었습니다.\n";
cout << "벡터값을 0으로 설정합니다.\n";
x = y = mag = ang = 0.0;
mode = RECT;
}
}
void Vector::polar_mode() {
mode = POL;
}
void Vector::rect_mode() {
mode = RECT;
}
Vector Vector::operator+(const Vector& b) const {
return Vector(x + b.x, y + b.y);
}
Vector Vector::operator-(const Vector& b) const {
return Vector(x - b.x, y - b.y);
}
Vector Vector::operator-() const {
return Vector(-x, -y);
}
Vector Vector::operator*(double n) const {
return Vector(n * x, n * y);
}
Vector operator*(double n, const Vector& a) {
return a * n;
}
std::ostream& operator<<(std::ostream& os, const Vector& v) {
if (v.mode == Vector::RECT) {
os << "(x, y) = (" << v.x << ", " << v.y << ")\n";
}
else if (v.mode == Vector::POL) {
os << "(m, a) = (" << v.ang << ", " << v.ang * Rad_to_Deg << ")\n";
}
else {
os << "Vector 객체의 모드 지정에 오류가 생겼습니다.\n";
}
return os;
}
}
main.cpp
- \(\texttt{main()}\) 함수가 정의되어 있는 파일이다.
// main.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "vect.h"
int main() {
using namespace std;
using VECTOR::Vector;
srand(time(0)); // rand() 함수는 Pseudo-Random적인 특성을 가지지만, srand()함수는 매번 Default Seed값을 초기화하므로 매번 다른 난수집합을 생성시킬 수 있다. ("난수 생성" 포스트 참고)
double direction;
Vector step;
Vector result(0.0, 0.0);
unsigned long steps = 0;
double target;
double dstep;
cout << "목표 거리를 입력하세요 (종료시, q 입력) : ";
while (cin >> target){
cout << "보폭을 입력하세요 : ";
if (!(cin >> dstep))
break;
while (result.magval() < target) {
direction = rand() % 360; // 주정뱅이는 0도에서 359도 중 한 방향으로 걸음을 내딛는다.
step.reset(dstep, direction, Vector::POL);
result = result + step;
steps++;
}
cout << steps << " 걸음을 걸은 후 현재 주정뱅이의 위치 : \n";
cout << result << endl;
result.polar_mode();
cout << " (극좌표)\n" << result << endl;
cout << "걸음당 기둥에서 벗어난 거리 = " << result.magval() / steps << endl;
steps = 0;
result.reset(0.0, 0.0);
cout << "목표 거리를 입력하세요 (종료시, q 입력) : ";
}
cout << "프로그램을 종료합니다.\n";
cin.clear();
while (cin.get() != '\n')
continue;
return 0;
}