2013년 12월 30일 월요일

마인크래프트 1.7.2, 1.7.3, 1.7.4 한글패치 버그

안녕하세요, kipa00입니다!

들어가기에 앞서, 다시 한 번 죄송합니다.


아직까지 마인크래프트 본연의 Java required version은 6u1입니다.
그럼에도 불구하고 제가 그 버전을 확 높여 버렸네요 7u45로...
오늘 class 분석하다 확인했습니다.

한글패치 버그 (Reported: 3 / Fixed: 2)


이곳은 계속 업데이트될 예정이니 한번씩 들어와서 확인해 보세요.
간편설치기 버그는 받지 않습니다. 애초에 만들 생각이 없어서 버그도 안 받아요
간편설치기 버그를 도와드리지 않는다는 말은 아니니 물어보실 건 물어보셔도 괜찮아요

해결 해결할 생각이 없음 해결되지 않음
확인 결과 버그가 아님 확인 결과 그런 버그가 없음

HGP001. (1.7.2, 1.7.3) 책에 한글로 글이 쓰이지 않습니다.
HGP002. (1.7.4) 쌍기역, 쌍시옷 받침이 입력되지 않습니다.
HGP003. (1.7.4) Shift + 화살표로 블럭 선택시 복사 붙여넣기가 되지 않습니다.
HGP004. (1.7.4) Tab을 눌렀을 때 플레이어 이름이 제대로 입력되지 않습니다.
HGP005. (1.7.4) Java required version이 Java 7u45가 되었습니다.

2013년 12월 29일 일요일

다른 게 아니고 이런 게 싫다는 말입니다.


'삭제하시기 바랍니다. 풀밥풀님이 허락을 하지 않았습니다.'?

솔직히 좀 화나네요. 나도 이제 말 가려서 해야겠다
전 글(링크는 이곳)에서 말했던 사람들 중에 속하는 사람입니다.
1.7.2, 1.7.3, 1.7.4 버전 한글패치는 제가 아는 건 현재(131229 오후 5:26)
제 한글패치(만든이 키파! 다시 강조합니다)밖에 없습니다.
출처명시는 프로그래머의 생명입니다. 이런 식으로 나오시면 배포 파일명도
HGPatch1.7.2_by_kipa00 이런 식으로 해 버리겠습니다. 확...



MCP 1.7.2 Beta가 나왔다네요.
이제 얼마나 많은 모드들이 쏟아질지 기대됩니다.
저는 언제나 한 발 앞서서 한글패치를 만들어 드리는 사람이 되겠습니다.
뭐 제가 너무 늦었다면 MCP를 쓰겠지만요...

2013년 12월 25일 수요일

여러분의 출처명시가 없다면 저는 closed-coder가 될 수밖에 없습니다.

글을 네이버로 퍼가실 때 출처를 달아주세요.
제 걸 사용하시고 감사인사도 안 하셔도 저는 괜찮지만
적어도 제가 만든 한글패치에 다른 사람의 이름이 찍히는 건
아니라고 생각합니다. 찔리는 분들이 몇 분 계실 거라 생각합니다.

수정된 class 파일을 빼내는 것을 막는 기술을 만들었습니다.
여러분들의 정확한 출처명시가 없다면 저는 제 코드를
점점 폐쇄적으로 만드는 수밖에 없습니다.
반드시 출처를 달아주세요.

출처를 다실 때는 제 네이버 블로그보다는
구글 블로그(?), 즉 이곳으로 달아주시기 바랍니다.
이곳의 주소는 http://kipa00.blogspot.com/입니다.
정 여의치 않으시면 "by kipa00" 혹은 "by 키파"라고만 달아주셔도
저는 매우 감사드립니다.

출처명시는 모든 비상업용 프로그램의 기본입니다.
뭐 저한테 기부를 해 주신다면 정말 감사드립니다만은
저뿐만 아니라 다른 모든 분들이 만드신 비상업용 프로그램도 마찬가지로
그 분 닉네임이나 블로그, 홈페이지 등으로 반드시 출처를 달아주세요.



한글패치에 관하여 간편설치기 제작자 분들께:
간편설치기는 반드시 저와 협의한 후에 만들어 주세요.
원래는 간편설치기도 자유롭게 만들 수 있도록 하려 했으나,
이제(1.7.5 혹은 1.8 이상부터) 제 한글패치의 간편설치기를
만드려고 제 파일을 분석 시도하는 순간부터 여러분은 멘붕하게 될 겁니다.

저는 경고했습니다.

2013년 12월 14일 토요일

마인크래프트 1.7.4 한글패치, 간편설치기

안녕하세요! kipa00입니다!

새 버전이 나왔습니다!

여기로 들어가서 받아주세요!


정말정말 죄송합니다.

1.


한글패치에 'Shift'를 글자로 인식하는 오류가 있었습니다. 덕분에 '깎아', '갔다', '됐다' 등의 낱말들이 모조리 '까ㄲ아', '가ㅆ다', '돼ㅆ다'로 처리되는 웃지 못할 사태가 벌어졌습니다. 최근에 'ㄸ', 'ㅃ', 'ㅉ', 받침이 없는데도 억지로 끼워넣으려다 이상한 문자가 되는 (예: '아ㅃ' -> '앃') 사태가 있어서 한글패치 모듈을 전부 재정비했는데, switch - case - default로 정리하는 과정에서 문제가 생긴 것으로 보입니다. 해당 오류는 업데이트되었으니 다시 다운받아주세요. 번거롭게 해 드려 정말 죄송합니다.
최초 발견자인 '즈윙'님께도 늦었지만 감사드립니다.

2.


기존 Java required version인 6u1을 7u45로 갈아엎어버렸네요; 6u23에서 작업한 것으로 바꾸었습니다. 근데 간편설치기는 고치기 귀찮네. 안 고쳐야지
여러분 간편설치기 너무 믿지 마세요.
제 자각이 늦긴 했지만 문제를 빨리 발견해주신 '상상'님께 감사드립니다.

풀밥풀님께: 포스팅 언제나 감사드립니다. 패치파일을 포스팅하실 때 이 내용을 꼭 같이 올려 주시기 바랍니다.

주저리주저리

놀먹이라는 커뮤니티에서 활동하고 돌아다니고 있는데, 반(半)리더인 SecondMk님께 하고 싶은 말이 있습니다. 진심으로 존경합니다. 완전. 언제나 그렇게 열성적이고 끊임없는 일관된 태도이신지.

본론

이번에도 한글패치를 만들었습니다. 급하게 만드느라 여러분들의 반영사항을 싸그리 싹싹 무시했을 뿐만 아니라 하나도 반영하지 못했을 뿐만 아니라 버그까지 만들어버려서 너무 죄송한 마음입니다.

그래서 죄송한 마음에 역시나 여러분들의 반영사항을 싸그리 싹싹 무시하고 버그 하나를 해결했습니다. 'ㅏ', 'ㅑ', 'ㅣ'를 입력하면 뒷 글자가 사라지는 Mojang의 고질적 버그를 해결했습니다.

수동설치와 간편설치가 있습니다. 간편설치기 만들었더니 네이버 잡놈이 '악성코드' 처리해서 갖다 버렸지만, 네이버를 이용하지 않고도 대중적으로 배포할 수 있게 되어 다시 만들 수 있습니다!

수동설치는 여기로! 간편설치(7u45 required)는 여기로!

이스터 에그

와... 아직 아무도 못 찾았나요? 숨겨 놓은 게 찾기 힘들긴 하구나...
이스터 에그 관련 내용입니다.

언제나 풀밥풀님께 감사한 말씀 드립니다!

2013년 12월 6일 금요일

개인적으로

시도해 보지도 않고 코드만 들고 오면서 "도와주세요 ㅠㅠ"하는 애들이 너무 싫다.
적어도 "이게 이런 역할을 해서 이러한 동작을 한다" 정도는 알고 코드를 짜는 게 아닌가?
그러고도 안 된다면 전체 코드에 대해서 묻지 말고 단편적인 코드 하나에 대해서
요점만 정확하게 물어보는 것이 적어도 예의 아닌가?

나한테 코드 전체를 들고 오는 사용자들이 싫다.
그런 사람들은 자신의 창조물을 자신의 힘으로 만들 수도 없을뿐더러,
만들 자격 또한 없다.

2013년 11월 28일 목요일

마인크래프트 한글패치 1.7.2, 1.7.3

여러분, 한글패치계 1인자 kipa00입니다!

이제는 책에도 한글로 글 쓸 수 있습니다!

much features를 위해 도와주신 우마공 분들과 언제나 자발적인 포스팅을 해 주시는 풀밥풀님께 감사의 말씀을 드립니다.

주저리주저리

사실 이 한글패치를 배포할까 말까 생각을 많이 했었습니다. 제 지인들에게 일부 배포되어 있는 상태였습니다. 저랑 제 주위 사람들만 편할 수는 없다고 생각하여, 기능을 조금 더 넣어 튼실하게 만든 다음 배포하려고 했습니다. 그래서 열심히 개발을 했죠(...)

결론: 알 게 뭐야

다운로드 링크 및 설치법

1.7.2 간편설치기가 나왔습니다! 원클릭 설치! 1.7.2 간편 설치기의 다운로드 링크는 이곳입니다.
1.7.2를 깔고 싶지만 불행하게도 Mac OS, Ubuntu, Solaris 등... 이라면 다운로드 링크는 이곳입니다.
1.7.3 간편설치기가 나왔습니다! 블해님이 제작해 주셨습니다. 여기
1.7.3 수동설치는 이곳입니다.
설치법은 해당 경로(맥의 경우 ~/Library/Application Support/.minecraft/versions) 아래에 압축을 풀어 넣으시면 지 알아서 다 합니다.

사용법

런처를 실행시킨 후 Edit Profile에 들어가면 Use version의 체크박스에서 Release HGPatch1.7.2 혹은 Release HGPatch1.7.3을 눌러줍니다. 그리고 게임을 실행시키면 끝!

잘 써 주시기만 하면 그것으로 감사할 따름입니다. :)
곧 간편설치기도 개발할 예정이니 기대하세요

검색어유입 증가

마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치
마인크래프트 한글패치 1.7.2
마인크래프트 한글패치 1.7.3
마인크래프트 1.7.2 한글패치
마인크래프트 1.7.3 한글패치
마인크래프트 한글패치

2013년 7월 11일 목요일

C++ 언어 강의. 1 - 자료형과 변수

정작 C++ 언어를 강의하는 곳은 잘 없더군요 :P

C 언어도 모르시는 분들께: C++ 언어를 하기 위해서는 그 밑바탕이 되는 C 언어를 몰라도 됩니다. 왜냐하면 90% 이상이 C++ 언어에 그대로 왔기 때문이에요. 저는 그 모든 것을 설명할 겁니다. C++ 언어를 하기 위해서는 컴파일러가 필요합니다. 설치하고 와주세요. 오늘 강의는 컴파일러를 이용하지 않기 때문에 지루할 수도 있습니다.

C 언어를 잘 하시는 분들께: 순서가 좀 많이 이상하죠? 저는 원리 위주로 설명할 거에요. 이 부분은 사실상 C 언어와 동일합니다. 이미 다 알고 계실 거라 생각합니다.

C++ 언어를 잘 하시는 분들께: 이 강좌는 초반부에는 C++를 전혀 모르는 사람에게 초점을, C++를 알게 되면 reinterpret_cast 같은 C++ 언어에서만 나타나는 특징을 상세하게 공부할 예정합니다.


우리 컴퓨터는 숫자를 전부 2진수로 저장합니다. 사람이 숫자를 쓸 때는 그냥 쓰면 되죠. π = 3.1415926535897932384626... 하지만 컴퓨터는 저장할 수 있는 메모리에 한계가 있기 때문에 숫자를 더욱 더 엄격하게 나누어서 저장합니다. 우리가 3이라고 쓰면 그건 정수이고 3.14라고 쓰면 그건 유리수입니다. 그런데 컴퓨터는 정수 3을 쓴 자리에다 (정수가 아닌) 유리수인 3.14를 쓸 수는 없습니다. 왜냐하면 엄격하기 때문이지요.

이렇게 엄격한 컴퓨터를 따라 C++ 언어도 엄격합니다. 프로그램의 특성상 조건에 맞는 여러 변수가 필요한데, 실제로 필요한 것이 정수뿐이라면 그 변수를 애초부터 유리수라고 정의할 필요가 없습니다. 심지어 컴퓨터는 화면에 표시할 문자열도 변수로서 가지고 있어야지만 동작합니다. 이러한 정수, 실수, 문자열과 같은 것을 자료형이라고 합니다.

우리 C++ 언어에서는 정수를 int, 실수를 float 또는 double, 문자열을 string이라고 합니다(실수 자료형 중에서 float는 double보다 표현 범위가 좁습니다. π를 예로 들면 double에서는 14자리를 표현할 수 있고 float는 7자리까지만 정확하게 표현할 수 있습니다.).

C++ 언어에는 명령문이 있습니다. '이러이러한 것을 해라' 하고 명령하는 문입니다. C++ 언어는 다른 것과 이들을 구별하기 위해 모든 명령문의 끝에는 ;(세미콜론)을 붙이라는 규칙을 세웠습니다. 명령문 자체에는 ;이 없지만 명령문이 혼자 쓰였다면 반드시 끝에 ;을 붙여야 합니다. 또한 아무것도 없는 코드는 아무것도 하지 말라는 명령문이기 때문에,  
1: ;
는 '아무것도 하지 말고 넘어가시오'라는 뜻입니다. 이것은 나중에 빛을 발할 것입니다.

변수는 자료형으로 표현되는 값을 저장하는 것입니다. 우리는 그 값을 얼마든지 바꿀 수 있습니다(물론 예외사항이 있긴 합니다.). C++에서의 변수 선언은 이렇습니다:
1: <자료형> <변수이름>
여러 개의 변수를 한꺼번에 선언하고 싶으면
1: <자료형> <변수이름1>, <변수이름2>, ...
이런 식으로 입력하면 됩니다. 이들이 명령문이라서, 끝난 이후에는 반드시 ;을 붙여야 합니다. 이를테면 정수형 score을 선언하는 것은 다음과 같습니다:
1: int score;
정수를 선언하는 것이 당연하듯이 실수를 선언하는 것도:
1: double pi;
이렇게만 선언해 주면 됩니다. 이 때 pi에는 어떤 값이 들어갈까요? 아무 값도 들어가지 않습니다. 대부분의 컴파일러들은 0을 넣어줍니다. 하지만 Microsoft 컴파일러의 경우 모든 바이트를 204로 채우기 때문에 -92, 559,631,349,317,830, 736,831,783,200,707, 727,132,248,687,965, 119,994,463,780,864.000000이라는 괴상한 값이 나옵니다. 따라서 변수에는 적절한 초기화가 필요합니다. 변수는 선언과 동시에 초기화가 가능합니다:
1: double pi = 3.14159265358979;
이렇게 하면 실수 pi를 선언하는데 그 값을 3.14159265358979인 π 값으로 한다는 것입니다. 이제 우리는 알고 있는 자료형으로 여러 변수를 선언할 수 있습니다:
1:  int a, b, cplusplus = -1;
2: double pi = 3.14159265358979;


이 시간에서는 자료형과 변수의 개념과 변수의 선언 방법에 대해서 배웠습니다. 배운 것을 정리해 보겠습니다(빨간색으로 된 것을 이어붙입니다.).
엄격한 컴퓨터를 따라 C++ 언어도 엄격합니다. 정수, 실수, 문자열과 같은 것을 자료형이라고 합니다. C++ 언어에서는 정수를 int, 실수를 double이라고 합니다. 명령문이 '이러이러한 것을 해라' 하고 명령하는 문입니다. 명령문 자체에는 ;이 없지만 명령문이 혼자 쓰였다면 반드시 끝에 ;을 붙여야 합니다. 변수는 자료형으로 표현되는 값을 저장하는 것입니다. C++에서의 변수 선언:
1: <자료형> <변수이름>
변수에는 적절한 초기화가 필요합니다. 초기화:
1: double pi = 3.14159265358979;
이상으로 마치겠습니다. 궁금한 점이 있으시면 댓글을 달아 주세요. 수고하셨습니다.
많이많이 퍼뜨려주세요(물론 링크를요)!

2013년 3월 26일 화요일

마인크래프트 한글패치 1.5.1

여기에 있다구요오오

상위 트래픽 소스가 아니면 거들떠보지도 않는 검색엔진이 미워 죽겠음.
그래서 트래픽 올리기 위한 검색어 입력!

제발 무시해 주세요.
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치
마인크래프트 한글패치 1.5.1
마인크래프트 1.5.1 한글패치

2013년 3월 10일 일요일

NWC 구조 연구 - 개요

명심! 언제든지 바뀔 수 있는 문서입니다. 혹시 공동연구를 하실 분이나 아이디어 제공해 주실 분은 k2pa00@gmail.com으로 메일 보내주세요.

2013년 3월 10일자까지 문서

NWC는 비트플립이 전부 다더군요.

맨 뒤 4바이트는 여러 가지 상황에 따라서 수가 바뀝니다. 이 중 앞의 2자리는 (아직까지는) 불규칙합니다. 뒤의 2자리는 총 원소의 개수인 것 같은데... 음의 위치에 따라서도 달라집니다(높아질수록 1씩 줄어듦). 이 4자리의 숫자는 비교적(?) 불규칙하게 나타납니다. 그리고 앞의 규칙적인 부분까지는 다 정확하게 써도 이 부분이 틀리면 망합니다. 파일이 깨져버린단 말이에요.
정말 깊이 연구해야 하는 부분입니다. 따라서 저는 이 부분을 Checksum(체크섬)이라고 부르기로 했습니다. 높이나 이런 거에서 차이나는 걸 봐서 다 더한 값이라고 예상해서, sum(합)이라는 말을 붙였습니다. 아직까지 완전 불규칙한 앞의 2바이트를 Upper Checksum, 그나마 덜 불규칙한 뒤의 2바이트를 Lower Checksum이라고 부르겠습니다.

4분 온음표 노트는 60 26 XX 2F(가온다까지), 60 E6 XX 5E(가온다 초과)입니다. XX 부분은 바이트 플립 되어 있습니다. 가온바와 가온나는 NWC에서 나타내는 방법이 따로 있지만, 저는 읽는 게 목적이 아니라 쓰는 게 목적이고, 꼭 저 두 음을 그 방법으로 나타내지 않아도 잘 되었습니다. 그런 고로 나중으로 미루거나 하겠습니다.

오늘은 이상! 연구가 완전히 완료가 된 부분은 개요가 아닌 곳에 따로 쓰겠습니다.

P. S. 공동연구자 너무너무너무너무 필요해요! NWC 파일 구조에 관해 관심있는 분이라면 누구든 환영합니다.

2013년 2월 22일 금요일

마인크래프트 키파의 한글패치

룻트님 한글패치 오류 고쳐주려 하다가 아까워서 배포합니다.
제 한글패치는 한글패치 본연의 기능에만 신경썼습니다. 그래서 한글을 입력하는 부분은 룻트님 것보다 좋을지도 모르나, 기능은 정말 허접합니다. 다양한 기능을 원하시면 룻트님 한글패치를 사용하세요.

다운로드 (1.4.7)
다운로드 (1.5.1)

링크를 누르면 낯선 화면이 보입니다. 당황하지 마시고 파일(F)의 다운로드(S)를 눌러주세요. 다운로드가 바로 시작됩니다. rar 파일입니다. 절대로 알집으로 풀지 마세요. 제 윈컴(윈7) 기준으로 안 됩니다. WinRAR나 다른 좋은 압축 소프트웨어를 사용하세요.

수동 설치입니다. 저는 자동 설치같은 거 안 하구요, 자동 설치기 만들어주시려고 하시는 분들 정말 감사합니다. 그러나 이런 모드같은 거 배포할 때는 출처를 명확하게 알려주세요. 프로그래머에게 버그 리포트는 생명입니다. 버그가 엉뚱하게 설치기를 만든 사람에게 보고되는 어이없는 사례가 적지 않으니, 배포할 때는 꼭 출처를 밝혀주세요. 저뿐만 아니라 다른 프로그래머들이 써도 된다고 한 거 전부요. 출처는 kipa00.blogspot.com(이곳)이나 정 여의치 않으면 네이버 블로그(kipa00.blog.me)로 남기셔도 됩니다. 아! 네이버의 폐해란!

국민 대다수가 네이버를 쓰고 있다는 사실이 한심하군요. 물론 저도 씁니다만... 저도 한심하군요. 참... 아직까지 네이버를 끊지 못한다니...

2013년 2월 12일 화요일

세종대왕님이 정말로 존경스럽습니다.

우리는 그냥 평소에 이렇게 말하고 쓰고 읽고 (한글을) 듣고 하는데, 제가 실용적인 한글 압축 알고리즘을 만드려고 연구를 하던 도중에 놀라운 사실을 발견했습니다.

웬만한 일상한국어에서는 받침이 없는 글자가 전체의 60% 이상을 차지합니다.

덕분에 '받침 플래그를 추가해도 괜찮을 것 같다'는 생각이 들었습니다. 받침 플래그 1비트를 추가하면 오히려 압축이 더 될 것 같습니다.
그리고 메신저에서는 통신어를 잘 쓰니까, 모음 있나 없나 플래그도 추가하면 안... 되겠지요? 그건 좀 그렇네요. 왜냐하면 'ㅋㅋ'나 'ㄴㄴ', 'ㅌㅌ'등을 위해서 나머지 98%가 1비트씩 희생하면 안 되니까요.

근데 경어체를 실험 안 해 봤네요;; 반어체에서는 확실히 60% 이상이더라구요.

추신: 이 글귀를 포함해서, 여기 있는 글자들 중 받침이 없는 글자는 전체의 53.3%입니다. 경어체에서는 약간 줄어드는군요. 그래도 50% 이상이니 뭐...

2013년 2월 4일 월요일

NWC 구조 연구를 시작합니다.

그 어떤 곳에 찾아봐도 없어서, 제가 직접 연구하기로 했습니다.
NoteWorthy Composer(이하 NWC) 파일의 구조를 샅샅이 파헤치도록 하겠습니다.

제가 학교에서 30분간 파헤쳤는데 NWC의 스트링 구조를 알겠습니다. 정확하게 안 건 아니니 다른 데 쓰지 마시고 '그러려니' 하고 봐 주세요.
"ABCDEFG"라는 스트링은
1. 아스키 코드로 모두 변환한다. 41 42 43 44 45 46 47
2. +0x30 71 72 73 74 75 76 77 (이게 약간 애매하단 말이에요.)
3. 각각의 바이트의 비트 순서를 스왑한다. 8E 4E CE 2E AE 6E EE
이렇게 됩니다. 근데 널 문자도 없고, string의 길이를 어떻게 구하는지 몰라서 잘 모르겠습니다.

올리디버거를 사용할 수 있다면 작업 속도가 훨씬 빠를 텐데;; 기술이 없네요...

2013년 1월 20일 일요일

한글 입력 이론 (2)

지난번에 한글을 바꾸는 원리에 대해 제대로 설명하지 못한 것 같아서
개요를 짚고 넘어갑니다. 여기에는 버퍼도 포함합니다.

1. 주어진 스트링을 input라 하자.
2. 버퍼 스트링 buffer와 결과물 ret를 빈 스트링으로 선언
3. for i = 0부터 input.length()-1까지 반복
4. buffer에 input[i]를 붙인다
5. if buffer에 분할이 필요하면(아래 버퍼스트링이 변환 후 2글자 이상이 된다면)
(분할된 문자열 앞부분을 buffer.front 뒷부분을 buffer.back이라고 하면)
6. buffer.front를 한글로 변환해서 ret에 붙인다
7. buffer = buffer.back(버퍼에 남은 뒷부분을 저장한다)
8. endif
9. endfor
10. 버퍼에 남은 문자열을 한글로 변환해서 ret에 붙인다.
11. 결과물: ret

이해가 안 되시나요? 일반적인 한글 입력과 완전히 똑같은 의미입니다.
해설을 하자면,
5에서 '분할이 필요하면'이란 것은 지난번에 봤듯이 'rksk' 같은 걸 입력했을 때
'k'와 's' 사이에서 끊어야 ('가|나') 한다는 겁니다. 끊어야 할 필요가 없을 때는
버퍼에 데이터를 계속 추가(4번)하고, 끊어야 할 때는 끊어서 앞부분을 한글로 변환('가')
해서 붙이고(6번) 남은 'sk'를 buf에 저장(7번)한다는 겁니다.

분할이 필요 역할을 하는 함수가 needSeperating입니다.
이 함수는 분할이 필요할 경우 분할할 곳의 위치를,
아닐 경우 0을 리턴합니다.
한글로 변환 역할을 하는 함수가 assemble입니다.
전체적인 역할을 하는 함수를 translate라고 하면, 우리는 이제
translate의 코드를 짤 수 있습니다. 여러분이 한 번 해 보세요.


.

.

.

코드는 다음과 같습니다.

아, 참고로 저는 UTF-8에서 코드를 썼기 때문에 wstring 대신 string을 쓴 겁니다. wstring의 코드가 필요하시면 직접 변환(1분도 안 걸립니다.)하시거나 저한테 달라고 해 보세요.

1:  string translate(string input) {                        // 1
2:     int i, len = (int)input.length(), temp;
3:     string buffer, ret;                                 // 2
4:      for (i=0; i<len; ++i) {                             // 3
5:          buffer += input[i];                             // 4
6:          if ((temp = needSeperating(buffer))) {          // 5
7:              ret += assemble(buffer.substr(0, temp));    // 6
8: 
            buffer = buffer.substr(temp);               // 7
9: 
        }                                               // 8
10: 
    }                                                   // 9
11: 
    ret += assemble(buffer);                            // 10
12: 
    return ret;                                         // 11
13: 
}
14: 


#include <string>과 using namespace std;는 당연히 되어 있을 거라 생각하고
짠 코드입니다. 제가 저 위에서 얼마나 친절하게 설명을 했는지
보이시죠? 그냥 그대~로 코드를 짜면 됩니다.

이제 needSeperating의 코드를 봅시다. needSeperating은 특수문자가 보이면
'어, 끊어야 할 곳이네?'하고 끊어버립니다. 입력 원리를 그대로 적용하기 때문에 그렇습니다.
이건 지난 시간에 아~주 철저하게 설명을 했으니, 넘어가고 코드만 보겠습니다.

#define INT char
int needSeperating(string input) {
    int i, len = (int)input.length();
    int last = -1, temp;
    INT *arr;   // 0 : 자음(초성/종성 불확실) 1 : 모음

                // 2 : 확실한 종성 (다른 것과 조합 가능)
                // 3 : 자음(종성)과 조합 가능한 모음
                // 4 : 조합 불가능한 종성(포화상태)
    arr = (INT *)malloc(sizeof(INT) * len);
    for (i=0; i<len; ++i) {
        if (isJaum(input[i])) {
            *(arr + i) = 0;
        } else if (isMoum(input[i])) {
            *(arr + i) = 1;
        } else {                //특수문자가 보이면,
            if (i == 0) {       //첫번째에 특수문자가 있을 경우
                free(arr);      //메모리 관리
                return 1;       //1을 리턴한다. [1]
            } else {            //아닐 경우
                free(arr);      //메모리 관리
                return i;       //끊어야 할 곳을 리턴한다.
            }
        }
    }
    //여기서부터 i를 거치고 난 value 0은 확실한 초성이 된다.
    //검사를 하다 확실히 끊어야 할 상황이 되면 return
    for (i=0; i<len; ++i) {
        temp = *(arr + i);
        if (last == -1) {
            last = temp;
        } else {           //이전 거, 다음 거, if 문 처리가 막 보이죠?
            if (last == 0 && temp == 0) {
                free(arr);
                return i;
            } else if (last == 0 && temp == 1) {
                *(arr + i) = 3;
            } else if (last == 1 && temp == 0) {
                free(arr);
                return i;
            } else if (last == 1 && temp == 1) {
                if (!isAssemblableMoum(input.substr(i - 1, 2))) {
                    free(arr);
                    return i;
                }
            } else if (last == 2 && temp == 0) {
                if (!isAssemblableJaum(input.substr(i - 1, 2))) {
                    free(arr);
                    return i;
                } else {
                    *(arr + i) = 4;
                }
            } else if (last == 2 && temp == 1) {
                free(arr);
                return i - 1;
            } else if (last == 3 && temp == 0) {
                *(arr + i) = 2;
            } else if (last == 3 && temp == 1) {
                if (!isAssemblableMoum(input.substr(i - 1, 2))) {
                    free(arr);
                    return i;
                } else {
                    *(arr + i) = 3;
                }
            } else if (last == 4 && temp == 0) {
                free(arr);
                return i;
            } else if (last == 4 && temp == 1) {
                free(arr);
                return i - 1;
            }
            last = *(arr + i);
        }
    }
    free(arr);
    //검사를 해도 끊을 게 없다면 return 0
    return 0;
}


[1] 왜 1을 리턴할까요? 0을 리턴하면 '끊을 곳이 없다'라는 사인이 될 뿐만 아니라, 이미 끊어져 있는 부분을 또 끊어요? 말이 안 되죠. 그리고 특수문자 다음엔 어떤 것이 오든 그대로 2글자가 됩니다. (ex ' g' -> ' ㅎ')

컬러링 힘들었음 ㅠㅠ
isJaum, isMoum, isAssemblableJaum, isAssemblableMoum
(Assembleable인지 Assemblable인지 모르겠음)이라는 4개의 함수가 선언 없이 사용되었는데요, 이 함수들의 코드는 다음과 같습니다. 저 긴 코드에 비하면 진짜 간단해요 :D
bool isJaum(char input) {
    return (strchr("rRseEfaqQtTdwWczxvg", input) != NULL);
}
bool isMoum(char input) {
    return (strchr("koiOjpuPhynbml", input) != NULL);
}

bool isAssemblableJaum(string input) {
    string ok[] = {"rt", "sw", "sg", "fr", "fa", "fq", "ft", "fx", "fv", "fg", "qt"};
    int i;
    for (i=0; i<11; ++i) {
        if (input == ok[i]) {
            return true;
        }
    }
    return false;
}
bool isAssemblableMoum(string input) {

    string ok[] = {"hk", "hl", "ho", "nj", "nl", "np", "ml"};
    int i;
    for (i=0; i<7; ++i) {
        if (input == ok[i]) {
            return true;
        }
    }
    return false;
}

네. 이거에요. 그냥 레퍼런스 관리가 귀찮아서 함수화한 겁니다. 물론
저 Assemblable 시리즈는 약간 코드가 길지만 _로 분리해서 find로
훨씬 더 쉽게 할 수 있었어요. 다만 처리 속도가 길어지므로 pass

assemble은 합치는 건데요, 단일 한글(ex 'ㄱ', 'ㄴ', ..., 'ㅏ', 'ㅑ', ... 'ㅚ')은 받아서
바로 처리해주고, 완성 한글이라면 (ex '가', '한', '수')
맨 앞 한글자는 무조건 초성으로 하고
이후에 나오는 자음은 종성이,
이후에 나오는 모음은 중성이 되는 거죠. 두말 않고 코드를 보겠습니다.

string assemble(string input) {
    if (input.length() == 1) {   //길이가 1일 경우 무조건 단일
        string origin = "rRseEfaqQtTdwWczxvgkijuhynbmloOpP";
        string change

        = "ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅑㅓㅕㅗㅛㅜㅠㅡㅣㅐㅒㅔㅖ";
        int i, len = (int)origin.length();
        for (i=0; i<len; ++i) {
            if (origin[i] == input[0]) {
                return change.substr(i * 3, 3);     //UTF-8은 한글이 3칸이에요.
            }
        }
        return input;
    } else if (input.length() == 2 && isAssemblableMoum(input)) { // [1]

        string origin = "hkhlhonjnlnpml";
        string change = "ㅘㅚㅙㅝㅟㅞㅢ";
        int i, len = (int)origin.length() / 2;
        for (i=0; i<len; ++i) {
            if (input == origin.substr(i * 2, 2)) {
                return change.substr(i * 3, 3);       //UTF-8은 한글이 3칸이에요.
            }
        }
    } else {
        int cho = JaMoValue(input.substr(0, 1), 0), jung, jong;
        int unicode = 0xAC00;
        string ret;
        char UTF8Value[4];
        string temp = input.substr(1);
        int i;

        // 종성을 찾을 때까지 돌려서 중성/종성을 끊을 위치를 찾는 겁니다.
        for (i=0; i<input.length(); ++i) {
            if (isJaum(temp[i])) {
                break;
            }
        }
        jung = JaMoValue(temp.substr(0, i), 1);
        jong = JaMoValue(temp.substr(i), 2);
        temp = "";
        unicode += (cho * 588 + jung * 28 + jong);       //UTF16BE 형태
        UTF8Value[0] = 0xE0 + (unicode >> 12);
        UTF8Value[1] = 0x80 + ((unicode % 4096) >> 6);
        UTF8Value[2] = 0x80 + (unicode % 64);
        UTF8Value[3] = 0x00;
        ret.assign(UTF8Value);                           //UTF-8 형태
        return ret;
    }
    return input + "_";     //변환하지 못할 것을 대비해 끊을 곳만이라도 표시
}


[1] 종성, 중성 없이 초성만으로 ㄳ, ㄶ 만드는 건 잘못된 알고리즘입니다. 실제로 이렇게 쓰이는 경우가 거의 없어서 표준에서 뺐습니다. 저건 사실이지만 구현할 수도 있고 구현하기 귀찮다고는 말 못 해

간단하죠?
여기서 아무 선언 없이 쓰인 JaMoValue는 string과 int를 받습니다.
int가 0이면 초성 순서를, 1이면 중성 순서를, 2이면 종성 순서를 리턴합니다.
순서는 다음과 같습니다.


초성

01 23 45 67 89 1011 1213 1415 1617 18

중성

01 23 45 67 89 10
11 1213 1415 1617 1819 20

종성

X
0 1 2 3 4 5 6 7 8 9 10 11 12 13
14 15 16 17 18 19 20 21 22 23 24 25 26 27


표가 뒤죽박죽인 건 귀차니즘 때문에 소수점 안 쓴 거니 이해해주세요 :D
네. 보시다시피 한글 순서 그대로에요.
완성자의 조합 규칙은 이렇습니다.
44032 + (초성순서) * 588 + (중성순서) * 28 + (종성순서)
저 위에서 사용된 게 보이죠. 다시 얘기하지만
int형이 0이면 초성 순서, 1이면 중성 순서, 2면 종성 순서를
리턴합니다. 그렇다면 코드가 어떻게 짜여질지 눈에 선하게 보이죠?
물론 여기서는 한글로 했지만 내부적으로는 영어를 썼으므로
전부 영어로 (초성의 경우 'r=0 R=1 s=2 e=3 E=4'...) 해야겠죠.
코드는 다음과 같습니다.

int JaMoValue(string input, int value) {
    if (input.length() == 1) {
        string origin;
        if (value == 0) {
            origin = "rRseEfaqQtTdwWczxvg";
        } else if (value == 1) {
            origin = "koiOjpuPh///yn///bm/l";
        } else if (value == 2) {
            origin = "/rR/s//ef///////aq/tTdwczxvg";
        }
        int i, len = (int)origin.length();
        for (i=0; i<len; ++i) {
            if (origin[i] == input[0]) {
                return i;
            }
        }
    } else if (input.length() == 2) {

        string origin;
        //초성은 무조건 한 글자이므로 value 0 나오는 게 이상하죠.
        if (value == 1) {
            origin = "//////////////////hkhohl////njnpnl////ml";
        } else if (value == 2) {
            origin = "//////rt//swsg////frfafqftfxfvfg////qt";
        }
        int i, len = (int)origin.length();
        for (i=0; i<len; ++i) {
            if (origin.substr(i * 2, 2) == input) {
                return i;
            }
        }
    }
    return 0;
}


이해하셨나요? 여기까지 코드를 작성하고, 모든 함수에 대한 Prototype을 쓰신 다음,
main을 알아서들 쓰시고 컴파일해 보세요.
wstring으로 코드 바꾸는 건 메일하면 해 드립니다. :D
저는 메인을 이렇게 썼습니다: 이건 예제니 굳이 복붙하실 필요 없어요.

int main(int argc, char* argv[]) {
    string temp;
    while (1) {
        getline(cin, temp);
        cout << translate(temp) << endl;
    }
}


오늘은 어떻게... 강의 좀 잘 쓴 것 같나요?
너무 어렵게 설명한 건 아닌지... 약간 걱정이 됩니다.
다음 시간에는 진짜로 한글 입력 이론을 하겠습니다.
이건 string에서 data를 읽어서 buffer 처리를 한 것에 불과해요 :D

컬러링 잘못된 거 있으면 댓 달아주세요. 이게 댓 달면 메일이 오네 ㄷㄷ

2013년 1월 16일 수요일

2013년 1월 14일 월요일

2013년 1월 9일 수요일

현재 만들고 있는 리듬게임

여기에 swf가 링크가 제대로 안 되고
fps 나오는 것도 막장이라(저는 fps를 전부 120으로 맞춥니다.)
일단은 파일 다운로드 방식이어야겠네요.

다운로드

현재 버전은 1.1입니다.


저 링크 막 거는 사람 아니니까 믿으세요.
네이버 링크지만 광고 없고, 저런 건 받을수록 서버 과부하만 주니 지향해야 됩입니다.

리플레이가 없습니다.

실행법

플래시 플레이어가 있어야 됩니다. 하나 까시고
더블클릭하면 바로 실행됩니다.

조작법

오직! 숫자키 패드만 씁니다. (없으신 분은 위 숫자열을 누르셔도 되는데, 비추천.)
바깥쪽에서 다가오는 동그라미에 안쪽 동그라미가 일치하게 될 때,
안에 적힌 숫자눌러주세요!
그럼 됩니다.

그리고 상당히 매니악하게 되었는데
이유 분석을 해 보자면,

1. 누르는 순서가 숫자 순서가 아닙니다.
2. 공간 배열이 숫자 키패드와 다릅니다.

이 2가지 점 때문에 테스트할 때도 막 X뜨고 그랬어요.

플레이해보시고, 개선할 사항이나 지원할 것(금전적인 지원도 감사하구요, 그래픽/프로그래밍 알고리즘 등 어떤 것도 괜찮습니다.) 있으면 댓글을 달아요! 저 메일 그렇게 자주 못 봐요.

2013년 1월 3일 목요일

마인크래프트 정돌로 조작

보이는 것만 정돌로 바뀌는 겁니다.
아무리 이렇게 많이 바꿔도 새로고침 누르면 다시 되돌아옵니다.
로그인은 반드시 해야 하며, 여기에 회원가입한다고 돈 들어가는 거 아니니까 그냥 하세요.

중간에 인터셉트해서 (예: WireShark) 데이터 바꾸는 방법으로 할 수도 있는데 프록시 깔기 귀찮아서 그냥 했습니다.

MacBook Air와 Chrome을 사용했습니다. IE는 개발자 환경(F12)이고
FireFox 쓰시는 분들은 다 알 거라 생각합니다.
Safari는 없는 듯 합니다. 크롬 깔길 정말 잘 했네 ㅋ