Google Code Jam을 하기 위한 기반 클래스Google Code Jam을 하기 위한 기반 클래스

Posted at 2008. 12. 27. 16:39 | Posted in 프로그래밍 언어/Ruby
일단 Google Code Jam은 인풋파일의 형태가 보통

[처리해야 할 인풋 개수]
[인풋 1]
[인풋 2]
...

이런 식이고 출력형태는

Case #1: [값]
Case #2: [값]
...

이런 식이다.

어떤 문제를 풀던간에 파일 처리는 기본적으로 해야 하는 부분이기 때문에
이 부분을 처리해 주는 클래스를 하나 만들었다.

file_reader.rb
class FileReader
def initialize(&algorithm)
@fin = File.open("input/" + $0.split(".")[0] + ".txt")
@fout = File.new("input/" + $0.split(".")[0] + "_out.txt", "w")
@num_of_inputs = @fin.gets # read value meaning # of inputs
@algorithm = algorithm
end
def process_per_line
line_cnt = 1
@fin.each_line do |line|
result = @algorithm.call(line)
@fout.print "Case ##{line_cnt}: #{result}\n"
print "Case ##{line_cnt}: #{result}\n"
line_cnt += 1
end
end
def destroy
@fin.close
@fout.close
end
end

인풋, 아웃풋 파일 이름은 이 클래스가 사용되는 파일 이름을 사용한다.
예를 들어 이 클래스가 test.rb 에 include/require로 불려진다면 input/output file은
input/test.txt, input/test_out.txt 가 될 것이다.
그리고 문제를 풀 파일을 하나 생성하여 다음과 같이 위 클래스를 사용한다.
아래는 제대로 문제를 푼 것이 아니다;;

Round1A_numbers.rb
require 'file_reader.rb'

file_reader = FileReader.new do |line|
inner_val = (3 + Math.sqrt(5))**line.to_i
inner_val = inner_val.floor % 1000
result = ""
case inner_val
when (0..9)
result += "00"
when (10..99)
result += "0"
end
result + inner_val.to_s
end
file_reader.process_per_line
file_reader.destroy

FileReader.new 뒤의 do-end 블록이 FileReader 클래스의 @algorithm이 되고,
process_per_line 메서드를 호출하면 @algorithm 에 구현된? 메서드의 블록으로 파일의 each line을 파라미터로 넘긴다.
즉 FileReader.new 뒤의 블록에 파일 한 줄을 읽어 문제를 처리하는 알고리즘을 구현하면 된다.
그리고 블록의 마지막에 결과를 위치시킨다.

저런 FileReader.new do - end 가 FileReader의 initialize(&algorithm) 의 algorithm으로 넘겨져 쓰이는 것을
뭐라고 부르는 지는 잘 모르겠다.
이게 closure인가-_-?;;

루비는 시작한지 며칠 안 돼서 루비의 특징을 살린 코드라고는 절대 할 수 없는 코드지만;
C++에서는 경험하지 못했던 것들이라 언어 자체가 흥미롭고 재밌다.
//

왜 자바스크립트의 String에는 trim이 없는가!!왜 자바스크립트의 String에는 trim이 없는가!!

Posted at 2008. 12. 25. 17:12 | Posted in 프로그래밍 언어/Javascript
왜 없지-_-;

String에 trim 함수를 추가해 주자;

String.prototype.trim = function()
{
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
}

앞의 replace가 left-trim이고 뒤의 replace가 right-trim이다.

white space로 시작하는 문자열이면 그 white space를 ""로 치환,

white space로 끝나는 문자열이면 그 white space를 "'로 치환.
//

C99에서 정의한 변수 선언, 동적배열C99에서 정의한 변수 선언, 동적배열

Posted at 2008. 12. 24. 18:27 | Posted in 프로그래밍 언어/C/C++/MFC
소스코드는 다음과 같다.

  1 #include <stdio.h>
  2
  3 int main()
  4 {
  5     int size;
  6     printf("숫자입력 : ");
  7     scanf("%d", &size);
  8     int arr[size];
  9     printf("출력해염\n");
 10     int i=0;
 11     for(i=0; i<size; i++)
 12         arr[i] = i;
 13     for(i=0; i<size; i++)
 14         printf("%d->%d\n", i, arr[i]);
 15     return 0;
 16 }

소스코드가 어려운 건 아니니까 출력결과는 넘어간다.

중요 포인트는

1. 소스 중간에 변수를 선언할 수 있다는 것. ( line 8,10 )
2. 배열 선언 시 그 크기를 변수로 지정해 줄 수 있다는 것 ( line 8 )

툴을 VS6을 써서 C를 배웠다면 저런 건 안 된다고 배웠겠지만;

99년 지정된 표준에서는 됨니다.

근데 VS2005랑 2008에서는 왜 안될까?
에러를 보면 위에 중요 포인트라고 짚은 것 때문에 안 되는 것이다.
컴파일러 옵션에서 뭘 설정해 줘야 할지도 모르겠다.

gcc에선 위의 코드가 잘 돌아간다.
//

CTime 사용하기CTime 사용하기

Posted at 2008. 11. 28. 01:15 | Posted in 프로그래밍 언어/C/C++/MFC
현재 timestamp 얻기
CTime time = CTime::GetCurrentTime();
__int64 timestamp = time.GetTime();

timestamp로부터 연월일시분초 얻기 (월만 얻어본다)
CTime time2 = timestamp; // operator=(__int64)
int month = time2.GetMonth(); // +1 같은거 안 해도 된다.

//

CMap::Lookup 메서드 살펴보기CMap::Lookup 메서드 살펴보기

Posted at 2008. 11. 28. 00:05 | Posted in 프로그래밍 언어/C/C++/MFC
먼저 CMap 클래스의 형태는 다음과 같다
template< class KEY, class ARG_KEY, class VALUE, class ARG_VALUE >class CMap
: public CObject

그리고 Lookup 메서드의 형태는 다음과 같다.
BOOL Lookup(
ARG_KEY key,
VALUE& rValue
) const;

Lookup 메서드는 CMap 변수가 key 값이 할당되어 있는지를 찾는 함수이다. 예를 들면

typedef struct Info{
Info(){ i=0; }

int i;
} Info;


CMap<
int, int, Info, Info> map;
map.InitHashTable(
257); // 왜 하필 257? msdn 예제에서 257 쓰길래;
Info info;

info.i =
10;
map[
0] = info;

이후 다음과 같이 Lookup을 사용한다.
Info tmp;
map.Lookup(0, tmp); // return true;
map.Lookup(1, tmp); // return false;

Lookup 함수가 true를 리턴했다면 tmp 변수는 map[0]에 저장된 변수와 같은 값을 갖게 된다.
cout << map[0].i << endl; // 10 출력
cout << tmp.i << endl; // 10 출력

여기서 중요한 점은 map.Lookup(0, tmp); 에서의 tmp 변수와
map[0]에 저장된 값은 같으나 다른 변수이다.
어떤 단어를 써야 할지 모르겠어서 '변수'라고 썼다. 설명이 허접하니 예제를 보자
map.Lookup(0, tmp);
tmp.i = 1;
cout << map[0].i << endl; // 여전히 10 출력

즉, Lookup의 두 번째 파라미터로 들어간 tmp 변수에는 map[0]과 같은 데이터가 들어가 있지만
메모리의 다른 위치에 존재한다는 것이다.


추가.
CMap에 포인터를 저장하는 방식이라면 다음과 같이 되겠다.
(조금은 억지로 만든 예제이기 때문에 실제로 이렇게 코딩하면 안 된다;;)
CMap<int, int, Info*, Info*> map;
map.InitHashTable(257);
Info info;
info.i = 10;
map[0] = &info;

Info* tmp;
map.Lookup(0, tmp);
tmp->i = 1;

cout << map[0]->i << endl; // 1 출력

포인터니까 당연히 1이 출력된다. 특이한 거 아니다.
추가. 부분의 예제는 아무 의미 없는 예제다;;
굳이 쓰자면;
class A
{
public:
~A()
{

POSITION pos = m_Map.GetStartPosition();
int key;
Info* value;
while( pos )
{
m_Map.GetNextAssoc(pos, key, value);
delete value;
}
m_Map.RemoveAll(); // 이렇게 removeall 만 한다고 되는게 아니다.
// Method() 에서 동적할당 한 형태이므로 다 남아있다.
// RemoveAll() 하기 전에 하나하나 다 delete 해야 한다.
}
void A()
{
 m_Map[0] = new Info;
m_Map[11] = new Info;
}
void Increase()
{
Info* tmp;
m_Map.Lookup(11, tmp);
tmp->i++;
}
private:
CMap<int, int, Info*, Info*> m_Map;
}

그지같은 예제다.
소멸자에 주석으로 달아놓은 문제는 C++에서 new 로 동적할당하고
포인터를 stl 저장소에 넣었을 때 주의점이다.

//