Saturday, May 30, 2009

[PC]A Multiplication Game

간만에 solve했네요.
참조테이블을 이용하면 효율적입니다.^^

http://www.programming-challenges.com/pg.php?page=downloadproblem&probid=110505&format=html

문제요약
1부터 시작하여 2~9까지 임의의 수를 곱하는 것을 반복한다. 두명(stan, ollie)이 진행하는데 첫 순서는 stan이다. 특정 입력값보다 큰거나 같은 값을 부르는 사람이 승리한다.

#include <iostream>
#include <math.h>

typedef unsigned int UInt32;
typedef unsigned long long UInt64;

static const char* WINNER[2] = {"Stan wins.", "Ollie wins."};

int main()
{
	UInt32 input = 0;
	while(std::cin >> input)
	{
		for(int i=1; i<=10; ++i)
		{
			UInt64 stan = 9*pow((long double)18, i-1);
			UInt64 ollie = pow((long double)18, i);

			if(input <= stan)
			{
				std::cout << WINNER[0] << std::endl;
				break;
			}
			if(input <= ollie)
			{
				std::cout << WINNER[1] << std::endl;
				break;
			}
		}
	}
	return 0;
}

Thursday, May 21, 2009

[iditia]노드 상태 다이어그램

사용자 입력에 따른 노드 상태 다이어그램.

iditia_node_state_diagram

Undo/Redo를 구현하기 위해 단위테스트를 마치고,
iditia 본 프로그램에 적용하는 중 노드의 상태를 무시하고 입력을 받을 수 없었다.

이전에 작성한 이터레이션에서 계획되지 않은 태스크가 발생한 것이다. 이런 경우 HFSD 에서는 고객에게 사실을 알려야 한다고 주장한다. 그러나 현실에서는 그렇게 하지 못하는 전제가 있다. 아키텍트가 계획하지 못했던 것을 고객에게 알릴 수 있을까? 고객이 정보 방열판(Information radiator)을 주시하고 있다면 알려야 할 것이고, 고객이 이해 가능한 상황에 놓일 수 있을 것 같다.

Information radiator 

HFSD에 아래와 같은 멋진 항목이 나온다.

고객은 여러분이 어디에 있는지 알고 있습니다

여러분도 여러분이 어디에 있는지 알고 있습니다

이러한 것이 정보 방열판을 참조하므로서 가능한 것이다. 물론 정보 방열판으로 모두 해결되는 것은 아니다.

비록, 고객/설계/프로그램/테스트 1인4역이지만 원할한 커뮤니케이션(?)을 위해 정보 방열판 소프트웨어를 찾아보았다.

아직은 화이트보드에 포스트잇이 가장 좋은 듯 하다.

Saturday, May 16, 2009

메신저를 이용하여 트위터에 포스팅

구글톡(Google Talk)을 이용하여 트위터에 포스팅하기 위해서 찾던 중 http://ping.fm 을 통하여 트위터에 포스팅이 가능하다는 것을 알았다.

web-image-2f19faf0c20a3c763a9550b36d5cd70e

다른 메신저(MSN...)도 서비스 항목에 있는 것으로 보아 포스팅 가능하리라 생각된다.

  1. ping.fm 가입후 트위터 서비스에 가입한다.
  2. Services/Tools 항목에서 자신이 사용하는 메신저를 선택한다.
  3. 메신저 봇의 주소 및 인증 코드(Verification code)를 확인한다.
  4. 메신저 봇의 주소를 메신저에 추가한다.(참고로 구글톡 봇 주소는 pingdotfm@gmail.com 이었다)
  5. 메신저 봇에게 인증 코드를 전송한다.(메신저 봇 추가후 잠시후에 온라인상태가 된다.)

 

이후 메신저 봇에게 메시지를 작성하면 트위터에 포스팅된다.

Technorati 태그: ,,,

[PC]Where's Wardorf?

3n+1이후 2문제의 WA로 은근히 맘고생이였는데, 동현님 입/출력 처리를 보고 Solve하여 자신감이 붙었네요.

동현님이 사용한 8방향에 대한 참조테이블을 이용하는 방법같은 작지만 효율적인 기법에 대해서는 수련을 더 해야 할 듯.

그리고 스터디 시간에 잠시 이야기했지만, 보충하자면...

STL 경우 컨테이너 변경시 로직 변경을 최소화할 수 있는 것과 같이, 함수 입/출력을 잘 설계하면 자료 구조(1차원배열, 2차원배열 심지어 vector<string> 등등) 변경시 수정을 최소화 시킬 수 있을 것입니다.

단위테스트도 쉬워질 것이고요.

결국 입/출력 설계를 잘 하는 것이 테스트 가능한 프로그램을 만드는 것이고 재사용 가능한 모듈을 만들 수 있다는 것입니다.

HFSD 스터디랑 겹치고 있네요ㅡㅜ

#include <iostream>
#include <vector>
#include <string>
#include <string.h>

#define ONLINE_JUDGE

using namespace std;

#define MAX_INPUT 50

enum direction
{
 direction_right = 0,
 direction_rightdown,
 direction_down,
 direction_leftdown,
 direction_left,
 direction_leftup,
 direction_up,
 direction_rightup
};

char input[MAX_INPUT][MAX_INPUT] = {0x00};
char word[MAX_INPUT][MAX_INPUT] = {0x00};

char charbypos(int row, int col)
{
 return input[row][col];
}

void rightstring(int row, int col, int maxrow, int maxcol, string& out)
{
 for(int i=col; i<maxcol; ++i)
  out.push_back(charbypos(row, i));
}

void rightdownstring(int row, int col, int maxrow, int maxcol, string& out)
{
 int i, j;
 for(i=col, j=row; i<maxcol && j<maxrow; ++i, ++j)
  out.push_back(charbypos(j, i));
}

void downstring(int row, int col, int maxrow, int maxcol, string& out)
{
 for(int i=row; i<maxrow; ++i)
  out.push_back(charbypos(i, col));
}

void leftdownstring(int row, int col, int maxrow, int maxcol, string& out)
{
 int i, j;
 for(i=col, j=row; 0<=i && j<maxrow; --i, ++j)
  out.push_back(charbypos(j, i));
}

void leftstring(int row, int col, int maxcol, int maxrow, string& out)
{
 for(int i=col; 0<=i; --i)
  out.push_back(charbypos(row, i));
}

void leftupstring(int row, int col, int maxrow, int maxcol, string& out)
{
 int i, j;
 for(i=col, j=row; 0<=i && 0<=j; --i, --j)
  out.push_back(charbypos(j, i));
}

void upstring(int row, int col, int maxrow, int maxcol, string& out)
{
 for(int i=row; 0<=i; --i)
  out.push_back(charbypos(i, col));
}

void rightupstring(int row, int col, int maxrow, int maxcol, string& out)
{
 int i, j;
 for(i=col, j=row; i<maxcol && 0<=j; ++i, --j)
  out.push_back(charbypos(j, i));
}

void stringbypos(int row, int col, int maxrow, int maxcol, direction direct, string& out)
{
 switch(direct)
 {
 case direction_right:
  rightstring(row, col, maxrow, maxcol, out);
  break;
 case direction_rightdown:
  rightdownstring(row, col, maxrow, maxcol, out);
  break;
 case direction_down:
  downstring(row, col, maxrow, maxcol, out);
  break;
 case direction_leftdown:
  leftdownstring(row, col, maxrow, maxcol, out);
  break;
 case direction_left:
  leftstring(row, col, maxrow, maxcol, out);
  break;
 case direction_leftup:
  leftupstring(row, col, maxrow, maxcol, out);
  break;
 case direction_up:
  upstring(row, col, maxrow, maxcol, out);
  break;
 case direction_rightup:
  rightupstring(row, col, maxrow, maxcol, out);
  break;
 }
}

void positionbyword(char* word, int maxrow, int maxcol, int& x, int& y)
{
 for(int i=0; i<maxrow; ++i)
 {
  for(int j=0; j<maxcol; ++j)
  {
   if(word[0] == charbypos(i, j))
   {
    for(int d=0; d<=(int)direction_rightup; ++d)
    {
     string out;
     stringbypos(i, j, maxrow, maxcol, (direction)d, out);
     if(0 == strncmp(word, out.c_str(), strlen(word)))
     {
      x = i;
      y = j;
      return;
     }
    }
   }
  }
 }
}

void strlower(char* in, char*& out)
{
 int len = strlen(in);
 for(int i=0; i<len; ++i)
 {
  out[i] = in[i];
 }
}

#ifdef ONLINE_JUDGE

int main(int argc, char **argv)
{
 int casecount = 0;
 cin >> casecount;

 while(casecount--)
 {
  int row = 0;
  int col = 0;
  int count = 0;

  memset(input, 0x00, MAX_INPUT*MAX_INPUT);
  memset(word, 0x00, MAX_INPUT*MAX_INPUT);

  cin >> row >> col;

  for(int i=0; i<row; ++i)
  {
   char in[MAX_INPUT] = {0x00};
   cin >> in;
   int n = strlen(in);
   for(int j=0; j<n; ++j)
   {
    input[i][j] = tolower(in[j]);
   }
  }

  cin >> count;

  for(int i=0; i<count; ++i)
  {
   char in[MAX_INPUT] = {0x00};
   cin >> in;
   
   int n = strlen(in);
   for(int j=0; j<n; ++j)
   {
    word[i][j] = tolower(in[j]);
   }
  }

  for(int i=0; i<count; ++i)
  {
   int x = 0;
   int y = 0;
   positionbyword(&word[i][0], row, col, x, y);

   cout << x+1 << " " << y+1 << endl;
  }

  if(0 < casecount)
   cout << endl;
 }

 return 0;
}

#else

#include <gtest/gtest.h>
#pragma comment(lib, "gtest")

class testinput : public ::testing::Test
{
protected:
 ~testinput()
 {
 }
 virtual void SetUp()
 {
  strcpy(&input[0][0], "abcDEFGhigg");
  strcpy(&input[1][0], "hEbkWalDork");
  strcpy(&input[2][0], "FtyAwaldORm");
  strcpy(&input[3][0], "FtsimrLqsrc");
  strcpy(&input[4][0], "byoArBeDeyv");
  strcpy(&input[5][0], "Klcbqwikomk");
  strcpy(&input[6][0], "strEBGadhrb");
  strcpy(&input[7][0], "yUiqlxcnBjf");
 }
};

TEST_F(testinput, rightupdirection)
{
 string out;
 rightupstring(0, 0, 8, 11, out);
 ASSERT_STREQ("a", out.c_str());

 out = "";
 rightupstring(0, 10, 8, 11, out);
 ASSERT_STREQ("g", out.c_str());

 out = "";
 rightupstring(4, 0, 8, 11, out);
 ASSERT_STREQ("btykE", out.c_str());

 out = "";
 rightupstring(7, 0, 8, 11, out);
 ASSERT_STREQ("ytcAmalh", out.c_str());

 out = "";
 rightupstring(7, 8, 8, 11, out);
 ASSERT_STREQ("Brk", out.c_str());
}


TEST_F(testinput, updirection)
{
 string out;
 upstring(0, 0, 8, 11, out);
 ASSERT_STREQ("a", out.c_str());

 out = "";
 upstring(0, 10, 8, 11, out);
 ASSERT_STREQ("g", out.c_str());

 out = "";
 upstring(4, 10, 8, 11, out);
 ASSERT_STREQ("vcmkg", out.c_str());

 out = "";
 upstring(7, 5, 8, 11, out);
 ASSERT_STREQ("xGwBraaF", out.c_str());
}

TEST_F(testinput, leftupdirection)
{
 string out;
 leftupstring(0, 0, 8, 11, out);
 ASSERT_STREQ("a", out.c_str());

 out = "";
 leftupstring(0, 10, 8, 11, out);
 ASSERT_STREQ("g", out.c_str());

 out = "";
 leftupstring(4, 10, 8, 11, out);
 ASSERT_STREQ("vrODG", out.c_str());

 out = "";
 leftupstring(7, 10, 8, 11, out);
 ASSERT_STREQ("froDLaWD", out.c_str());

 out = "";
 leftupstring(7, 8, 8, 11, out);
 ASSERT_STREQ("BdiBmAbb", out.c_str());
}

TEST_F(testinput, leftdirection)
{
 string out;
 leftstring(0, 0, 8, 11, out);
 ASSERT_STREQ("a", out.c_str());

 out = "";
 leftstring(0, 10, 8, 11, out);
 ASSERT_STREQ("ggihGFEDcba", out.c_str());

 out = "";
 leftstring(4, 10, 8, 11, out);
 ASSERT_STREQ("vyeDeBrAoyb", out.c_str());

 out = "";
 leftstring(7, 5, 8, 11, out);
 ASSERT_STREQ("xlqiUy", out.c_str());
}

TEST_F(testinput, leftdowndirection)
{
 string out;
 leftdownstring(0, 0, 8, 11, out);
 ASSERT_STREQ("a", out.c_str());

 out = "";
 leftdownstring(0, 10, 8, 11, out);
 ASSERT_STREQ("grOqewBq", out.c_str());

 out = "";
 leftdownstring(4, 10, 8, 11, out);
 ASSERT_STREQ("vmhn", out.c_str());

 out = "";
 leftdownstring(0, 5, 8, 11, out);
 ASSERT_STREQ("FWAsyK", out.c_str());
}

TEST_F(testinput, downdirection)
{
 string out;
 downstring(0, 0, 8, 11, out);
 ASSERT_STREQ("ahFFbKsy", out.c_str());

 out = "";
 downstring(5, 10, 8, 11, out);
 ASSERT_STREQ("kbf", out.c_str());

 out = "";
 downstring(7, 10, 8, 11, out);
 ASSERT_STREQ("f", out.c_str());
}

TEST_F(testinput, rightdowndirection)
{
 string out;
 rightdownstring(0, 0, 8, 11, out);
 ASSERT_STREQ("aEyirwan", out.c_str());

 out = "";
 rightdownstring(0, 5, 8, 11, out);
 ASSERT_STREQ("Fldsyk", out.c_str());

 out = "";
 rightdownstring(0, 3, 8, 11, out);
 ASSERT_STREQ("DWaLDorf", out.c_str());
}

TEST_F(testinput, rightdirection)
{
 string out;
 rightstring(0, 0, 8, 11, out);
 ASSERT_STREQ("abcDEFGhigg", out.c_str());

 out = "";
 rightstring(0, 10, 8, 11, out);
 ASSERT_STREQ("g", out.c_str());

 out = "";
 rightstring(7, 10, 8, 11, out);
 ASSERT_STREQ("f", out.c_str());
}

TEST_F(testinput, accessinput)
{
 ASSERT_EQ('a', charbypos(0, 0));
 ASSERT_EQ('g', charbypos(0, 10));
 ASSERT_EQ('h', charbypos(1, 0));
 ASSERT_EQ('k', charbypos(1, 10));
 ASSERT_EQ('y', charbypos(7, 0));
 ASSERT_EQ('f', charbypos(7, 10));
}

int main(int argc, char **argv) 
{
 ::testing::InitGoogleTest(&argc, argv);
 return RUN_ALL_TESTS();
}

#endif

Tuesday, May 12, 2009

[iditia]2차 이터레이션 개발

최근 새로 시작한 스터디에서 "Head First Software Development" 책을 보고 있다. 1~3장까지 진도를 보고 iditia 2차 개발 이터레이션을 간략하게 수립하였다.  

 

_b_1622

 

2차 이터레이션

요구사항
1. 생성되는 노드의 위치 및 그와 연관된 노드의 위치 설정.
2. 작업의 취소 및 재 실행 지원(Undo/redo).
3. OpenGL 줌(zoom) 실행시 Font 크기 적절히 변경되도록.
4. 파일 열기 및 저장.
5. ToDoList 지원(Import/Export)

사용자 스토리
- 현재는 2차 iteration이므로 최초 사용자 스토리 작성시점을 추정하여,
   개략적인 사용자 스토리만 작성한다.

1. 마인드맵 수정.
  - 노드 생성시 다른 노드와 위치를 조절후 생성된다.
2. 작업의 취소 및 재실행.
  - 사용자는 작업을 취소하거나 재실행할 수 있다.
3. 화면 확대/축소.
  - 화면 확대/축소시 모든 요소들도 확대/축소되어야 한다.
4. 파일 열기 및 저장
  - 사용자는 파일을 선택하여 열고 수정후 저장할 수 있어야 한다.
5. ToDoList지원
  - ToDoList와 파일 호환성을 제공한다.

일정 추정
1. 4일
2. 3일
3. 2일
4. 1일
5. 2일

2차 이터레이션 기간 총 12일.

Friday, May 8, 2009

[PC]Contest Scoreboard

WA
#include 
#include  

using namespace std;

static const int MAX_PROBLEM	= 9;
static const int MAX_TEAM		= 100;
static const int MAX_CONTEST	= 10;

typedef struct _problem
{
	int minute;
	int	failed;
	int	submit;
	int solved;
}PROBLEM;

typedef struct _team
{
	int	order;
	PROBLEM problem[MAX_PROBLEM];
	int solved_count;
	int	solved_minute;
}TEAM;

typedef struct _contest
{
	TEAM	team[MAX_TEAM];
}CONTEST;

static CONTEST	contest[MAX_CONTEST];

static int		g_contest_order		= 0;
static int		g_team_order		= 0;
static int		g_problem_order		= 0;
static int		g_minute			= 0;
static char		g_result			= 0;

static const int MAX_FAILED_MINUTE = 20;

void save_succeeded(int contest_order, int team_order, int problem_order, int minute)
{
	if(contest[contest_order].team[team_order].problem[problem_order].solved > 0)
		return;

	contest[contest_order].team[team_order].problem[problem_order].minute = contest[contest_order].team[team_order].problem[problem_order].failed * MAX_FAILED_MINUTE;
	contest[contest_order].team[team_order].problem[problem_order].minute += minute;
	contest[contest_order].team[team_order].problem[problem_order].solved++;
	contest[contest_order].team[team_order].order = team_order;
	contest[contest_order].team[team_order].solved_minute += contest[contest_order].team[team_order].problem[problem_order].minute;
	contest[contest_order].team[team_order].solved_count++;
}

void save_failed(int contest_order, int team_order, int problem_order, int minute)
{
	contest[contest_order].team[team_order].problem[problem_order].minute += minute;
	contest[contest_order].team[team_order].order = team_order;
	contest[contest_order].team[team_order].problem[problem_order].failed++;
	contest[contest_order].team[team_order].problem[problem_order].submit++;
}

void save_failed_not_count(int contest_order, int team_order, int problem_order, int minute)
{
	contest[contest_order].team[team_order].order = team_order;
	contest[contest_order].team[team_order].problem[problem_order].submit++;
}

int is_solved(char result)
{
	switch(result)
	{
	case 'C':
		return 1;
	case 'I':
		return 0;
	default:
		return -1;
	}
	return -1;
}

void process(int contest_order, int team_order, int problem_order, int minute, char result)
{
	if(0 < is_solved(result))
	{
		save_succeeded(contest_order, team_order, problem_order, minute);
	}
	else if(0 == is_solved(result))
	{
		save_failed(contest_order, team_order, problem_order, minute);
	}
	else
	{
		save_failed_not_count(contest_order, team_order, problem_order, minute);
	}
}

int func_compare(const void *a, const void *b) 
{
	if(0 != ((TEAM*)b)->solved_count - ((TEAM*)a)->solved_count)
		return ((TEAM*)b)->solved_count - ((TEAM*)a)->solved_count;

	if(0 != ((TEAM*)b)->solved_minute - ((TEAM*)a)->solved_minute)
		return ((TEAM*)a)->solved_minute - ((TEAM*)b)->solved_minute;

	return ((TEAM*)a)->order - ((TEAM*)b)->order;
} 

void output_to_table(TEAM* in)
{
	qsort(in, MAX_TEAM, sizeof(TEAM), func_compare);
}

void output_table(TEAM* team)
{
	for(int i=0; i 0)
				submit = 1;
			if(team[i].problem[j].solved > 0)
			{
				solved++;
				minute += team[i].problem[j].minute;
			}
		}

		if(solved > 0)
			cout << team[i].order+1 << " " << solved << " " << minute << endl;
		else if(minute > 0 || submit > 0)
			cout << team[i].order+1 << " " << 0 << " " << 0 << endl;
	}
}

void output(int contest_order)
{
	output_to_table(&contest[contest_order].team[0]);

	output_table(&contest[contest_order].team[0]);
}

int main()
{
	memset(&contest, 0x00, MAX_CONTEST*sizeof(CONTEST));

	cin >> g_contest_order;

	int i=0;
	for(i=0; i> g_team_order >> g_problem_order >> g_minute >> g_result)
		{
			process(i, g_team_order-1, g_problem_order-1, g_minute, g_result);
		}
	}

	for(i=0; i

[PC]3n+1

#include 
#include 
#include 

using namespace std;

typedef unsigned int uint32;

class MaxCycle
{
private:
 int  max_;
 int  count_;
public:
 MaxCycle() : max_(0), count_(0)
 {
 }

 void operator()(uint32 ele)
 {
  count_ = 0;
  while(1 < ele)
  {
   ele = ele % 2 ? 3*ele+1 : ele / 2;
   ++count_;
  }

  if(max_ < count_+1)
   max_ = count_+1;
 }

 int max()
 {
  return max_;
 }
};

int main()
{
 int a, b;
 int s, len;

 while(cin >> a >> b)
 {
  if(a <= b)
  {
   s = a;
   len = b-a+1;
  }
  else
  {
   s = b;
   len = a-b+1;
  }

  vector coll;

  for(int i=s; i < s+len; ++i)
  {
   coll.push_back(i);
  }

  MaxCycle mc = for_each(coll.begin(), coll.end(), MaxCycle());

  cout << a << " " << b << " " << mc.max() << endl;
 }
 return 0;
}

Friday, April 17, 2009

DSA-주차장 관리 시스템

PGCS(Parking Garage Control System)

분할 스타일(Decomposition Style)

- 시나리오에 기반하여 명사 추출만 충실히 한 후, 종속관계를 취함.

- 하드웨어 은닉 모듈, 행위 은닉 모듈, 소프트웨어 결정 모듈 구분은 다음 기회에~

Driver

TicketMachine

Button

CardReader

ParkingGarage

StateDisplay

Ticket

Time

Gate

Loop

Car

Card

Cashier (The cashier is not part of the software system)

Fee

사용 스타일(Uses Style)

모듈의 필요성을 묻지도 않고 따지지도 않고 모두 추가함.

고객이 변심할 뿐이고, 내일이면 변경될 뿐이고, 단위테스트를 해야 할 뿐이고...

uses_style.jpg

일부 모듈을 정제하여 재작성한다. (Driver, Cashier, Car 모듈 삭제)

uses_style

일반화 스타일(Generalization Style)

입고(Entrance)

generalization_style

사용스타일의 모듈과 일반화스타일의 클래스와의 일반적인 관계 또는 매핑을 만들 수 있을까?

  • 사용스타일의 모듈은 일반화 스타일의 클래스로 확대되거나 축소된다.
  • 일반화스타일에서는 Loop관련 모듈이 삭제되었다.

계층화 스타일(Layered Style)

layered_style