예전에 '온라인저지 구축기' 라는 글을 올린 적이 있었는데, HUSTOJ가 버전업이 계속 되었고, 설치방법에 대한 문의가 있어 다시 적어봅니다.


설치 OS : Ubuntu 16.04.2 LTS

HUSTOJ repo : https://github.com/zhblue/hustoj (2018년 2월 28일 버전)



1. git을 설치한다.

sudo apt-get install git 



2. git clone으로 저장소에서 파일을 복사해온다.

아래 명령어는 항상 최신 버전을 받아오기 때문에, 이전 버전이 필요하다면 github에서 이전 커밋을 찾아보아야 한다.

git clone https://github.com/zhblue/hustoj



3. 받은 파일의 trunk/install 경로에서 install-ubuntu16+.sh 파일을 실행한다.

여기서는 문제 발생을 위해 기본 설정을 따를 것이므로, mysql이나 nginx가 이미 설정되어 있는 환경에서는 충돌이 발생할 수도 있다. (위의 repo에서 Docker 이미지도 제공하고 있으므로, 도커 사용에 익숙하다면 해당 이미지를 이용하여 쉽게 설치할 수 있다.)

sudo bash ./install-ubuntu16+.sh



4. 설치 도중에 mysql을 설치하고, 비밀번호를 설정하는 창이 나온다. 비밀번호를 입력하여 설치를 계속한다.


5. 수 분을 기다리면 설치가 완료된다. 경우에 따라 경고 메시지가 뜰 수 있는데, 심각한 내용이 아니면 일단 넘어간다. judge 라는 리눅스 계정이 생성되고, /home/judge 라는 홈 디렉터리가 만들어진다. 이 경로에 들어가서 파일이 제대로 설치되있는지 확인한다.



6. ps -ef | grep judged 를 실행하여 judged 데몬이 제대로 실행되고 있는지 확인한다.



7. 브라우저를 열고 127.0.0.1 (원격 접속중이라면, 해당 서버의 IP) 으로 접속하여 페이지가 잘 나오는지 확인한다.



8. /home/judge/src/web/include/db_info.inc.php 을 수퍼유저 권한으로 열어서(sudo) 언어를 수정한다. 언어 설정과 관련되어 있는 'cn'(중국어)이 2개 있다 이것을 en으로 바꿔준다.

zh-CN 라고 되어있는 것은 en-US로 수정한다.



9. 이제 관리자 계정을 생성해야 하는데, 기본 관리자 계정이 없어서 아이디를 만들고 DB를 수정해야 한다. 상단의 Login 메뉴에서 회원가입을 한다.



10. mysql -u root -p로 mysql 클라이언트를 열고 4번에서 지정한 비밀번호를 입력한다.



11. use jol; 을 입력하여 데이터베이스를 선택한다.



12. INSERT INTO privilege(user_id, rightstr) VALUES('생성한 아이디', 'administrator'); 쿼리를 입력하여 유저권한을 지정한다.



13. exit를 쳐서 DB에서 빠져나온다.



14. 9번에서 만든 관리자 ID로 로그인한다. 문제와 테스트케이스를 만들고 저장한다. 추가적인 테스트케이스를 입력하라는 버튼이 나오는데, 이 페이지는 다음에 다시 들어갈 수 있다. 관리자 페이지와 문제 추가에 대한 설명은 생략한다.



참고) 테스트용 문제를 추가할 때, 입력 테스트케이스에 아무 숫자나 입력하고, 출력 테스트케이스에는 Hello 등의 간단한 문자열을 지정한다. 그러면 테스트용 코드를 작성할 때 간단하다. 테스트 케이스를 입력하지 않으면 채점이 되지 않을 수도 있다.



15. 관리자 페이지에서 빠져나와, 문제를 풀고 평가가 제대로 되는지 확인한다. Pending이 지속되지 않고, Accepted 혹은 Wrong Answer, Compile Error 등의 결과가 나오면 성공!


16. 관리 페이지의 문제 리스트에서 Reserved 되어 있는 문제의 status를 클릭하여 Available 상태로 만든다. 이 상태가 되면 관리자가 아닌 일반 유저도 문제를 볼 수 있게 된다.




※ Troubleshootings

- /home/judge/ 디렉터리 내에서 hustoj 관련 파일을 찾을 수 없을 때

install-ubuntu16+.sh 파일 실행 중에 실패한 것이다. 슈퍼유저 권한을 주지 않고 실행했거나, 기존에 설치되어 있던 mysql 또는 nginx 설정과 충돌했을 가능성이 있다. install 파일을 실행할 때 발생한 출력 메시지를 확인하여 에러를 수정한다.


- 웹 사이트가 뜨지 않을 때

에러 메시지에 따라 nginx나 mysql 설정을 확인한다. (구글링..)


- 코드를 제출했는데 pending 상태에서 무한히 대기할 때

ps -ef | grep judged 명령으로 judged 데몬이 실행중인지 확인한다. 실행중이라면 프로세스를 (kill -9 등으로) 죽이고 재실행해 본다. 실행중이 아니라면, 실행한다.(sudo service judged start)

문제가 해결되지 않으면 /home/judge/src/core/judged 경로로 들어가 해당 프로세스를 포그라운드로 실행하여 에러 메시지를 확인 후 조치한다. 파일 접근 권한 문제이거나 DB 접속 문제라면 관련 에러가 뜰 것이다.

만약 아무 에러도 뜨지 않는다면, 관리 페이지에서 테스트케이스 데이터를 확인해 본다.


- 입력 테스트케이스의 문자열 길이가 잘못 측정될 때

테스트케이스 추가페이지에서는 줄바꿈에 \r\n을 사용한다. 이 부분은 관리페이지의 내부 php 코드를 수정하여 캐리지리턴(\r)을 빼고 라인피드(\n)만 저장되도록 수정해야 한다. (이런 잔문제들이 많다..)




HUSTOJ를 사용하여 https://judge.zetagate.com을 운영하고 있었으나, 여러가지 문제가 많고, 확장성이 없다고 판단하여 새로 제작 중이다. https://github.com/ice-judge 아직 Github 저장소만 만들어 놓은 시작 단계다...



 Dovelet이나 BOJ 같은 사이트들을 풀어보면서 직접 문제들을 만들어 보고 싶었고, 알고리즘을 공부하는 사람들과 소규모 대회를 열어보기 위해 온라인저지(Online Judge)시스템을 구축하게 되었다.




DMOJ 설치


 DMOJ는 Django 기반으로 되어 있는 온라인저지 시스템으로, github 커밋이 꾸준히 올라오고 있고 현대적인 사이트 디자인이 특징이다. 설치 가이드에 따라 설치를 진행하였는데 마지막 단계에서 nginx 권한 관련 오류를 해결하지 못하여 진행하지 못하였다. 도커이미지도 제공되고 있어서 컨테이너를 실행해 보았더니 이번에는 Django 내부 코드에서 오류가 발생하여 포기.




HUSTOJ 설치



* 2018년 2월에 갱신되었습니다. 아래 글 보다는 이 글을 참고하세요.


 일단 구동이 되는 것을 찾다가 HUSTOJ를 설치해보기로 하였다. HUSTOJ는 교내 프로그래밍 대회에 사용되고 있고, CodeUp 및 여러 온라인저지에서 사용하고 있는 오픈소스 프로젝트이다. 채점기는 C++로 짜여져 있으며 웹페이지는 PHP로 구동된다. 설치할 때 공식 페이지 블로그 포스팅을 참고하여 진행하였다. 설치 과정은 아래와 같다.


1) install/install.sh에서 WEBBASE, APACHEUSER, DBUSER, DBPASS, core 디렉터리 경로, web 디렉터리 경로를 환경에 맞게 설정한다. subversion 관련 코드들은 삭제한다. 


2) install/judge.conf를 확인한다. OJ_HOST_NAME, OJ_USER_NAME, OJ_PASSWORD와 MySQL관련 설정들을 환경에 맞게 수정하면 된다.


3) web/include/db_info.inc.php 파일에서 원하는 설정을 한다. 이 부분은 설치 후에도 변경할 수 있다.


4) install.sh를 실행하여 설치를 진행한다. 이 프로젝트는 Ubuntu 14에서 테스트되었고, Ubuntu 16을 비추천한다고 하는데, 16에서도 잘 구동된다. php5 대신 php7을, apache대신 nginx를 이용하는 것은 install 디렉터리에 함께 있는 ubuntu16용 설치 sh파일을 참고한다. sh파일을 실행하면,

/etc/nginx/site-enabled에서 root은 /home/judge/src/web이 되고, php관련 location설정은

       location ~ \.php$ {

                include snippets/fastcgi-php.conf;

        #

        #       # With php7.0-cgi alone:

        #       fastcgi_pass 127.0.0.1:9000;

                fastcgi_pass unix:/run/php/php7.0-fpm.sock;

        }

와 같이 작성된다.




사이트 수정


 레이아웃을 비롯하여 회원가입, 관리자페이지, 채점기 등 많은 부분을 수정하였다. judge 기본 디렉터리에서 data에는 문제의 테스트케이스가 있고, src/core에는 채점 프로그램 관련 소스와 makefile이 존재한다.

 웹페이지는 src/web 디렉터리에 있는데, src/web에는 SQL에서 데이터를 받아오는 부분이 있고,  src/web/template/bs3에는 주로 뷰 관련 코드(html)가 들어 있다. 그러나 잘 분리되어 있지 않아 수정이 번거롭다.

 PHP와 SQL, html이 섞여 있어 구조적으로 알아보기 불편하고, SQL튜닝이 잘 되어있지 않아 데이터가 많아지면 상당한 오버헤드가 예상된다. 일단 이 프로젝트를 사용하여 회원탈퇴, 소스공유, 랭킹시스템 등 필수적인 기능을 구현할 것이다. 그리고 저지사이트 구축을 공부해볼겸 하여 기존의 코드를 버리고 프레임워크를 새로 만들어 보기로 계획하였다.


현재 진행중인 사이트는 여기다.





pitching velocity unit converter (mph - kph) 제작일기...



구글플레이에서 다운받기 :

https://play.google.com/store/apps/details?id=com.zetagate.pitchspeed





◎ 레이아웃 설정과정.


→ 메인 액티비티 레이아웃 xml 에서 ListView 배치.


→ String 배열 생성후 값 저장


→  ArrayAdapter<String> 객체 생성. 


→ 객체 생성 시 TextView 레이아웃 리소스가 @android:layout/simple_list_item_1 로 지정되어 있어서

  스타일을 자유롭게 변경 불가..


→ 프로젝트 디렉터리 내 layout폴더에 사용자정의 레이아웃 xml파일 생성 후 TextView레이아웃 정의.

  android:minHeight 으로 간격 조절.


→ 어레이어댑터 생성자에서 데이터(String[])도 역시 지정.


→ ListView객체에서 setAdapter로 어레이어댑터(텍스트뷰 레이아웃과 리스트 데이터) 설정




◎ 데이터 생성과정 (정수(integer)로만 출력되도록 처리).


→ mph 속력 * 1.609344 를 계산하여 소수점 이하 자리를 취하고 det이라 함.


→ det < 1-RATIO/2 일 시 mph속력 하나당 kph속력 하나 출력.


→ 1-RATIO/2 < det < RATIO/2 일 시 mph속력 하나당 kph속력 두 개 출력


→ else  올림 처리하여 kph속력 하나 출력.


제작자 페이지 : http://zetagate.com







private function onSelected($evt:Event):void {

var list:Array = _pathFile.getDirectoryListing();

for (var i:int = 0; i < _pathFile.length; i++) {

list[i].addEventListener(Event.COMPLETE, onFileLoaded);

            list[i].load();

     }

    }


private function onFileLoaded($evt:Event):void

{

trace(1);

 }


위와 같은 코드를 작성하고 실행했는데 1이 출력되지 않는 것이었다.

그런데 이렇게 짠 다른 프로그램은 잘 동작하는 현상..


이유는, 그 프로그램에서는 onFileLoaded함수에서 $evt인자를 받아 어떤 처리를 하는데,

여기선 list의 요소를 참조하지 않아서 객체가 못 쓰는 상태(객체의 모든 참조 제거)가 되어버린 것이었다..


결국 list배열을 멤버변수로 둬서 해결..




--------------------------------------------------------------------------  



* 맵 에디터 제작


인터페이스를 그리고 클래스화한다.

그리고 swc 내보내기.




빌더에서 프로젝트 속성에 들어가 Build Path에 swc를 추가한다.





코드에서 클래스를 생성하여 addChild하면

시험용으로 그려본 인터페이스가 화면에 출력됨.





그동안 FlashBuilder로 프로젝트를 진행하고 있었는데,

플래시플레이어11로 swf출력이 되지 않고, 이클립스가 약간 불편이 느껴지는 등

플래시빌더로 진행하기에 몇가지 문제점이 있어서 FlashDevelop으로 바꾸게 되었다.

무엇보다도 플래시디벨롭은 무료라는 장점이 컸다.

빌더는 어도비에서 학생과 무직자에게 무료로 주는 라이센스를 쓰고 있었지만 저작물을 이용하는 데 몇가지 제약이 있다. 



게임 내의 월드를 모델링하기 위한 알고리즘을 갈아엎고

새로 짰기 때문에 코드 역시 처음부터 다시 쓰게 되었다.

시점을 isometric 방식으로 고정시켜 놨을 때 보이는 타일들을 

x,y,z축을 두어 쌓는 방식으로, 3D이긴 하지만 현재 보이는 부분만  처리하게 되는 것이다.


플래시디벨롭으로 새로 시작하려고 할 때 문제발생!

http://www.tibyte.kr/145

해결.,


디벨롭에서는 swc파일을 프로젝트 폴더 안에 놓은 뒤

우클릭 메뉴에서 Add To Library를 체크하면 쓸 수 있다.







이미지 리소스가 담긴 바이너리 파일을 URLLoader로 읽어오는데,

urlLoader.dataFormat = URLLoaderDataFormat.BINARY;

을 써주지 않아서 text로 로딩되는 문제 발생. 수정완료.




인터페이스와 타일이미지 불러오기는 일단 해결..






작성중인 프로젝트의 버전관리 필요성을 느끼고

DVCS(Distributed Version Control System)가 대세라길래 무턱대고 Git을 선택하였다.

저장소 호스팅 업체로는 무료로 private 저장소를 만들 수 있는 Bitbucket을 사용하기로 했다.



git bash 실행 후

cd  프로젝트 경로

git init 

git remote add origin 원격 저장소 주소

git add 추가할 파일들(.을 입력하면 지정한 디렉토리의 모든 파일)
git commit -m 메시지
git push -u origin master

원격 저장소 비밀번호 입력





Bitbucket에 있는 설명대로 했더니 원격저장소로 전송은 잘 됐나..

이제 Git를 비롯한 소프트웨어 버전관리에 대해서 공부를 좀더 해봐야겠다.












 코딩을 하면서 각종 상황에 대한 테스트가 필요했기 때문에

Valve社의 게임에서 볼 수 있는 것과 비슷한 콘솔 창을 구현하기로 했다.  


 콘솔 창은 싱글턴 패턴으로 프로그래밍했는데

액션스크립트는 생성자 함수의 접근제한자로 private를 둘 수 없기 때문에

해당 클래스 파일의 패키지 외부에 클래스 하나를 더 두고

싱글턴 클래스 생성자의 매개변수로 그 클래스 타입을 넣어주어야 한다.

아래와 같은 모양이다.


package {

public class Singleton {

private static var instance...

public function Singleton(block:SingletonBlocker)

{

if (block == null) throw new Error...

}

public static function getInstance()...

}

}

class SingletonBlocker{}



 프로젝트의 클래스에서 콘솔 창에 뭔가를 표시하는 함수를 호출하면 

콘솔창이 없을 경우 새로 창을 띄우고 있으면 그 창에 내용을 출력한다.


 콘솔 창은 NativeWindow클래스를 사용하여 새 윈도우를 띄우게 되는데,

이 윈도의 크기가 원하는 대로 되지 않았다. 액션스크립트 도움말을 보면 

NativeWindow객체의 stage.stageWidth 나 Height속성을 조절하면 창 크기가 

그에 맞게 바뀐다고 하는데 전혀 그렇지가 않는 것이었다..


 해결책은 역시 도움말에 나와있었는데  

_mainWindow.stage.scaleMode = StageScaleMode.NO_SCALE;

_mainWindow.stage.align = StageAlign.TOP_LEFT;

이 두 구문이 있어야 제대로 창크기 조절이 된다.



코드를 컴파일후 실행시키니 제대로 출력이 나왔다.






 다음은 게임에서 사용할 월드 데이터 파일을 제작하는 간단한 툴을 만드는 것이었다.

FileStream클래스와 File클래스로 파일쓰기를 한다.


File객체를 만들 때, 파일쓰기 하려는 위치가 어플리케이션이 있는 폴더라면

var file:File = File.applicationDirectory;

와 같이 초기화해야 한다고 해서 그렇게 해 보니 보안문제로 오류가 났다.-_-;


이 경우에는 

var file:File = new File(File.applicationDirectory.nativePath);

file = file.resolvePath("하위폴더"+File.separator+파일이름+".확장자");

요렇게 하니까 되더라..


 그 다음 이렇게 해서 생성된 월드 데이터파일에 어플리케이션을 연결해 보기로 했다.

이 작업은 그리 어렵지 않게 할 수 있다.

if(NativeApplication.nativeApplication.isSetAsDefaultApplication("확장자")==false)

NativeApplication.nativeApplication.setAsDefaultApplication("확장자");

연결이 되어 있지 않으면 '이 어플리케이션'을 해당 file의 연결 프로그램으로 설정한다.

단, 응용 프로그램 설명자(xml파일)의 fileTypes노드에 파일의 정보가 선언되어 있어야 한다.


 빌드를 하니 128x128 아이콘 파일의 크기가 맞지 않는다는 오류가 계속 뜨는데

src폴더 내의 파일을 수정해도 빌드만 하면 다시 129x129크기의 파일로 바뀌어 버렸다.

bin-debug폴더에 들어있는 파일을 지우니 제대로 빌드가 되었다.



(▲ 데이터파일의 아이콘이 바뀐 모습. 실행하면 맵에디터가 열리고 해당 파일을 불러들인다.) 



하나 빼먹은 게 있어 추가로 적는데,

프로그램 연결은 연결프로그램으로 쓸 어플리케이션이 컴퓨터에 설치되어 있는 상태여야 한다. (디버그모드에서는 확인할 수 없다.)








 





 

 오래전부터 공책에 구상하고 있었던 게임이 있었는데 10월 넷째주부터 본격적으로 작업을 시작했다. 

만드려는 게임은 isometric 시점의 타일기반 rpg게임이다. 

플래시빌더를 써서 action script 3.0으로 코딩을 하는데 오랜만에 다시 해보는거라 적응이 잘 안되어 힘들다. 

우선 게임내의 지형을 처리/표시하는 클래스를 구현하기 시작했다. 지형 데이터파일과 이미지파일에서 각각 

리소스를 로드하여 화면에 표시하는 부분이다. 타일과 맵 데이터 클래스를 만들고, 파일에서 지형 데이터를

읽어들이는 클래스를 만들었다.

 화면 표시를 담당하는 클래스를 따로 만든 뒤 실행을 해 보았는데 흰 화면만 나타나는 것이었다.

한참을 살펴보아도 잘못된 부분을 찾을 수 없었지만 클래스들을 다시 훑어보다가 정작 메인클래스에는 

아무런 내용도 넣어두지 않았다는 사실을 깨닫고 황당하지 않을 수 없었다. 이러한 착오들을 자주 일으켰기

때문에 다시 겪지 않기 위해 이렇게 기록해두기로 하였다. 



보여질 때는 등각투상도(isometric view)로 보여지지만 맵 데이터는  


이런 식으로 직사각형의 모양을 갖는 2차원 데이터가 기록되어 있다.(기록된 상태는 1차원이겠지만..)

데이터에서 특정 x, y위치에는 어떤 타입의 타일정보가 들어있는가를 읽어와서 타일을 하나씩 화면에 붙인다.

간단한 식을 유도하여 타일들이 표시될 위치를 화면에 들어맞게 잡아준 뒤 결과를 출력해 보았다. 



타일들이 지형을 이루는 것을 보고 한숨을 돌렸다. 데이터대로 맵을 출력하는 걸 성공하긴 했으나 아직 

남은 일들이 아득하다. 그래픽, 세부기획, 구현해야 할 기능들 등등..

 그리고 이중for문을 쓸 때 변수초기화를 빼먹거나 String을 as uint로 캐스팅하려 하는 실수를 범한 상태라

앞으로 또 어떤 착오나 버그들이 나타날지 불안감이 엄습해 온다. 









 


  

+ Recent posts