2020년 8월 3일 월요일

[매크로] 오토핫키를 이용해 텔레그램 봇으로 메시지 보내기

오토핫키를 이용해 알림을 보낼 수 있지 않을까 고민하게 되었습니다.

모니터링 하고 있지 않아도 특정 조건을 만족하면 확인할 수 있도록요.

일단 텔레그램 봇을 만들어봅시다.


1. 텔레그램 봇

 
텔레그램 봇을 만드는 이유는 텔레그램 봇 API를 이용해 내게 문자를 보내기 위해서 입니다. 카카오톡 봇도 가능하다고는 하는데 공식적이지는 않아 텔레그램 봇을 이용하였습니다.

텔레그램 봇은 휴대폰이나 컴퓨터에서 만들 수 있습니다. 만들기 위해 botfather와 채팅을 해야합니다.(이 놈도 봇입니다.) 핸드폰에서는 대화창의 오른쪽 위의 펜노트 버튼을 누르고 botfather를 검색해야합니다.


컴퓨터에서는 Microsoft store에서 telegram을 설치한 뒤 로그인을 하고 botfather를 검색하면 됩니다.




컴퓨터 텔레그램으로 설명하겠습니다. 시작을 눌러주세요.



botfather와 관련된 명령어들 설명이 나옵니다. /newbot을 입력합니다.



그러면 botfather가 bot의 이름을 적으라고 합니다. 저는 newbot_20200818로 입력했습니다.


botfather은 bot 이름에 Bot이나 _bot을 추가로 입력하라고 합니다. 저는
newbot_20200818_bot으로 간단하게 입력했습니다.


마침내 봇이 만들어졌습니다. 빨간색 칸에 있는 t.me/newbot_20200818_bot을 누르면 내가 만들어진 봇의 채팅창으로 들어가집니다. 보라색 칸에 있는 숫자와 영어는 API를 이용할 수 있는 token입니다.





2. 오토핫키


사실 오토핫키로 텔레그램 봇을 이용하는 코드는 잘 찾지 못했습니다. 다행히 한 외국인 분이 구현해 놓은 것을 찾았습니다. 원리는 이렇습니다. 텔레그램 봇은 결국 텔레그램 API를 이용하는 것이기 때문에 API를 이용하는 json 파일을 다운받으면서 실행시키는 원리였습니다. (이해하는데 시간이 좀 걸렸습니다.) 

이제 오토핫키 코드를 이용하기 위해 위에서 얻은 Token과 ChatID가 필요합니다. ChatID은 봇과의 채팅을 시작한 뒤 https://api.telegram.org/bot얻은Token/getUpdates을 인터넷 창에 입력하면 아래와 같이 ChatID을 얻을 수 있습니다. "chat": {"id": 다음에 있는 빨간색 부분이 ChatID입니다.


오토핫키 코드는 아래와 같습니다.

Telegram_MsgBox(Text)
{
	TelegramBotToken := 얻은Token
	TelegramBotChatID := 얻은ChatID
	
	loop 3
	{
		UrlDownloadToFile https://api.telegram.org/bot%TelegramBotToken%/sendmessage?chat_id=%TelegramBotChatID%&text=%Text%, %A_ScriptDir%\check.rups
		sleep 1000
		ifexist %A_ScriptDir%\check.rups
		{
			break
		}
		if A_index = 3
		{
			MsgBox, 16,, something went wrong with sending
		}
	}
	filedelete %A_ScriptDir%\check.rups
}

Telegram_MsgBox("Event!!!")

Telegram_MsgBox 함수를 이해해야합니다. 함수안의 'UrlDownloadToFile'은 API json 파일을 다운받으면서 채팅을 보내게 됩니다. 오토핫키가 있는 폴더에 잠깐 저장했다가 'filedelete' 코드로 지우는 원리입니다. 안타깝게도 한글은 되지 않습니다. 이참에 영어를 쓰시면 됩니다. 작은 이모티콘 코드도 있는데 불필요한 것 같아 따로 적지 않겠습니다.

Telegram_MsgBox("Event!!!")는 함수 실행문 입니다.


3. 오토핫키 실행


실행해보면 다음과 같이 메세지가 오는 것을 확인할 수 있습니다. 이제는 굳이 계속 확인안해도 되겠죠?



※ 참고문헌
https://devlog.jwgo.kr/2018/03/09/telegram-bot-api-response-json/

2020년 6월 3일 수요일

[잡담] conda 환경에서 PyTorch 설치 및 이용시 필요한 명령문들

아나콘다][케라스] 개발환경 설치 및 WIN32 응용프로그램 오류Windows 10 환경에서 CUDA 개발환경 구축하기 | Pacientes's DevlogWHAT IS PYTORCH? | Pacientes's Devlog

<컴퓨터 사양 및 설치 버전>
GPU : GeForece RTX 2080 Ti Gaming D6 11GB
ANACONDA : ANACONDA3
CUDA : CUDA Toolkit 10.2(Visual Studio 2015)
PyTorch install command : conda install pytorch torchvision cudatoolkit=10.2 -c pytorch


1. conda 가상환경 추가 및 삭제

(1) 가상환경 추가
    conda create --name 가상환경이름 python=x.x(버전)

(2) 가상환경 삭제
    conda remove --name 가상환경이름 --all


2. conda 가상환경 활성화 및 비활성화

(1) 가상환경 활성화
    activate 가상환경이름

(2) 가상환경 비활성화
    deactivate 가상환경이름


3. jupyter notebook kernel 추가 및 삭제

(1) 추가하려는 가상환경을 activate
    activate 가상환경이름

(2) ipykernel 라이브러리 다운
    conda install ipykernel

(3) 커널 추가
    python -m ipykernel install --user --name=가상환경이름

(4) 커널 삭제
    jupyter kernelspec uninstall 가상환경이름


4. 패키지 추가 및 삭제

(1) 패키지 추가
    conda install 패키지이름

(2) 패키지 삭제
    conda uninstall 패키지이름


5. pytroch cuda 이용 확인

(1) python  실행
    python

(2) pytorch import 후 확인코드 입력
    import torch
    torch.cuda.is_available()
    (torch.cuda.is_available() 실행시 True로 나와야 cuda를 이용함. False로 나온다면 cuda
    pytorch 버전을 확인해 맞춰야하거나 가상환경을 삭제한뒤 새로 만들어하면 True로 나옴) 


6.  pytorch 예제

(1) 기본 예제
https://tutorials.pytorch.kr/beginner/pytorch_with_examples.html

(2) 이미지 분류 예제


# 참고문헌

https://niceman.tistory.com/85

https://medium.com/@shistory02/jupyter-notebook-kernel-%EC%B6%94%EA%B0%80-%EB%B0%8F-%EC%82%AD%EC%A0%9C-6aa557a30ce4

https://stackoverflow.com/questions/43664444/how-can-l-uninstall-pytorch

2020년 5월 24일 일요일

[잡담] 엔비디아 리스크 요인 3가지에 대한 개인적인 의견

2020.5.24 아시아 경제 기사

“엔비디아, 향후 실적에 대한 자신감이 돋보이는 가이던스”

1. 코로나 19 이후 데이터센터 투자의 정체

향후 몇 년간의 매출을 코로나 19로 인해 얻었음은 인정하나 기술의 발전으로 인해 데이터센터 업그레이드 수요가 있을 것이라 예상함.
일시적인 매출 감소는 있을 것이라 생각.


2. 수요처의 직접 전산 가속기 개발

구글과 같은 기업은 가능할지 모르겠지만 구글 또한 'A100' 출시로 엔비디아의 데이터센터를 이용하기로 계획. 테슬라는 자체 칩을 개발중.


3. 자율주행차의 정보처리 관련 헤게모니 변동

네이버에서 헤게모니의 뜻은 '가장 통상적인 의미에서 한 집단·국가·문화가 다른 집단·국가·문화를 지배하는 것을 이르는 말.'로 이 기사에서는 자율주행차 알고리즘의 변화를 뜻한다고 생각함. 과연 딥러닝보다 더 좋은 모형이 나올 것인가? 통계학자로서 나오기 매우 힘들다고 생각함.


※ 참고기사

[잡담] 젠슨 황 엔비디아 CEO, GTC2020 기조연설 요약


2020.5.14 매일경제 기사

예년 같았으면 이런 형태로 GTC가 열렸었겠지만...


1. 데이터 센터(서버)

코로나 판데믹 사태 이후 모든 일이 원격으로 이루어짐
시장조사기관 가트너 - 향후 전체 인력의 48%가 원격근무(기존 30%)

 엔비디아는 이전에 서버용으로 들어갔던 GPU 아키텍쳐인 볼타(Volta - 2017년 5월 발표)를 20배 정도 성능으로 압도하는 새로운 설계방식 `A100`을 이날 발표했음. 젠슨 황 CEO는 "이건 세계에서 가장 거대한 7나노 공정의 반도체"라고 소개했음.

엔비디아의 A100 칩을 활용한 서버를 활용해 데이터센터를 구축하겠다고 한 기업으로는 18개 정도가 있음. 알리바바, 아마존웹서비스, 바이두, 시스코, 델, 구글, HP, 마이크로소프트 애저, 오라클 등.

구글은 최근 1분기 실적 발표를 통해 `오피스용 부동산은 사지 않아도 데이터센터 투자는 늘릴 계획이다'

DGX A100라는 서버장비를 내놓았는데, 엔비디아의 설명에 따르면 `세상에서 가장 발달된 인공지능 시스템`이라고 함. 미국 에너지부 산하 아르곤 국립연구소에서 이 시스템을 가지고 코로나19 바이러스와 관련된 연구를 진행하고 있음.

이 회사가 개발하고 있는 로보틱스 소프트웨어 플랫폼인 `아이작`이라는게 있는데 BMW가 이 플랫폼을 활용해서 공장을 가동하기로 이번 GTC2020에서 발표함. "BMW의 30개 공장에서는 56초 마다 1대씩 차량을 만들어 냄.


2. 자율주행차

현대자동차가 협력하고 있는 `포니AI`라는 자율주행차 기술 회사, 현대차와 협력 중인 전기차 플랫폼 회사인 `카누` 등이 모두 엔비디아의 자율주행 솔루션을 활용하겠다고 이번 GTC2020에서 발표함. 완성 전기차를 만드는 회사인 `패러데이퓨처`도 엔비디아의 솔루션을 쓴다고 이날 밝힘.

엔비디아는 자율주행에 필수적인 ADAS를 구동하는 프로세서 `자비에`를 만들고 있음. 특히 `레벨4` 이상의 자율주행에서는 이 `자비에` 칩이 다른 경쟁사 제품에 비해 우월한 성능을 자랑하는 것으로 알려져 있음.


3. 코로나로 인한 영향

젠슨 황 CEO는 "게이밍, 워크스테이션, 데이터센터 등은 오히려 긍정적 영향권에 들어와 있다"고 답함 `닌텐도 스위치`(동물의 숲)에 엔비디아의 칩이 들어가고 있음.


※ 참고기사






2020년 5월 21일 목요일

[잡담] 한혜진의 100벌 챌린지 명언


내가 자기 전에 누워서 하는 생각이

현실이 되려면 정말 많은 사람의 도움이 필요하다는 것과

결과물로 가는 과정 중에 궤도가 조금 수정되어도

본래의 취지만 훼손되지 않는다면

일의 마무리를 꼭 한 번 지어보는 것이 좋겠다

- 한혜진의 100벌 챌린지 -

2020년 5월 19일 화요일

[잡담] 매일 새겨야하는 주식투자 명언1




1. 투자자는 깊이 생각하지 않고 행동을 취하는 것보다
    아무 행동도 취하지 않고 깊이 생각하는 것이 더 낫다

2. 주식시장에서 바보보다 주식이 많으면 주식을 사야할 때고,
    주식보다 바보가 많으면 주식을 팔아야 할 때

3. 일단 우량주 몇 종목을 산 다음, 수면제를 먹고 몇 년 동안 푹 자라

4. 투자에서 얻은 돈은 고통의 대가로 받은 돈
    즉, 고통 자금이다

5. 이자율이 낮으면 이것저것 생각하지 말고 다이빙처럼
    주식시장에 점프하라

6. 개(주식가치)를 데리고 산책을 나갈 때, 개가 주인(기업가치)보다 앞서거니 뒤서거니 
    할 수는 있어도 주인을 떠날 수는 없다 - 코스톨라니의 개

7. 주식 시장의 90%는 심리학이 재배한다

8. 주식 투자는 부와 파산 사이를 오가는 위험한 항해다

9. 두 번 이상 파산하지 않은 사람은 투자자라고 불릴 자격이 없다

10. 성공적이 투자는 100번 중 51번 이기고 49번은 잃는다

11. 단기간에 부자가 되는 3가지 방법이 있다.
      부유한 배우자를 만난다,
      유망한 사업아이템을 갖는다,
      주식투자를 한다!

2019년 5월 3일 금요일

[R 강의] 그림의 label에 있는 수식을 바꿔가며 그리기

 논문에 넣을 그림을 그리는 경우 수식 표현을 이용하곤 합니다. R에서는 expression 함수를 이용해 수식을 만들고 그림에 넣습니다.
 예를 들어 1부터 10까지 1씩 증가하는 데이터를 생성한 뒤 이 값을 제곱하여 그리는 코드와 그림은 아래와 같습니다. y축 lab이 잘 안보여서 cex.lab로 크기를 크게 했는데 그림의 마진이 작아 잘려버려서 par(mar=c(아래 축 마진, 왼쪽 축 마진, 위 축 마진, 오른쪽 축 마진))으로 마진을 조정했습니다. 값을 늘리면 마진이 커져 그림이 작아집니다.

x<-1:10
par(mar = c(5, 5, 5, 5))
plot(x,x^2,type="l",ylab=expression(x^2),cex.lab=2)

<마진에 대한 이해를 돕기위한 그림>


 한 개만 그릴 때는 상관은 없지만 여러개의 그림을 경우 문제가 발생합니다. for 문을 이용해 5차까지 계산하고 y축 label을 expression(x^i)로 하여 x의 1차, x의 2차, ... , x의 5차로 표현하려고 하면 모든 그림의 y축 label은 x의 i차로 출력이 되버립니다.

for(i in c(1:5)){
  
  plot(x,x^i,type="l",ylab=expression(x^i),cex.lab=2)
  
}

 각각의 그림마다 다르게 출력하고 싶다면 expression 함수가 아닌 bquote 함수를 이용해야 합니다. ylab=bquote(x^.(i))로 바꾸면 우리가 원하는 결과를 얻을 수 있습니다. 수식을 그대로 쓰돼 i부분을 ( )로 감싼뒤 앞에 .을 넣으면 for 문의 i를 이용하게 됩니다.

for(i in c(1:5)){
  
  plot(x,x^i,type="l",ylab=bquote(x^.(i)),cex.lab=2)
  
}

 아래 첨자도 마찬가지로 위의 방법을 이용하시면 됩니다. 나중에 여러개의 수식이 이용된 그림을 그릴 때 이용하면 시간절약에 많은 도움이 됩니다.


※ 참고문헌
http://r.789695.n4.nabble.com/use-expression-in-a-loop-td856907.html
https://bookdown.org/ndphillips/YaRrr/plot-margins.html

2019년 4월 6일 토요일

[매크로] 오토핫키로 두더지게임 점수 올리기

 프로그램에 대한 흥미유발을 위해 매크로 프로그램을 가르치다보니 한 학생이 '중독성 게임에 있는 두더지 게임을 매크로로 해보고 싶어요' 한 적이 있습니다. 곧 바로 중독성 게임 사이트로 들어가서 게임의 원리를 살펴보았습니다. 게임 원리는 간단했습니다. 두더지가 나오는 순간 마우스로 클릭하면 점수가 올랐습니다.


 맨 처음으로 생각한 방법은 두더지의 눈을 캡처해서 눈이 보일 때 누르는 간단한 방법이었습니다. 오토핫키의 ImageSearch 함수를 이용하면 됩니다. 주의할 점은 두더지의 눈을 어느정도 나왔을 때 캡처를 해야하고 변하지 않는 부분을 특징적으로 캡처를 해야합니다. 저는 아래의 그림과 같이 캡처를 했습니다.


 코드는 아래와 같습니다. ifWinExist 함수로 크롬창이 있는지 확인한 뒤 WinActivate 함수로 두더지 게임 웹사이트 창을 활성화 시킵니다. ImageSearch 함수로 두더지눈 그림을 찾아서 두더지 눈을 찾으면 클릭하게 하는 코드입니다.
0::

loop{
     
  IfWinExist,ahk_exe chrome.exe
  {
   WinActivate,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
   {
     
   }
  }
   
  ImageSearch,XX,YY,0,0,A_ScreenWidth,A_ScreenHeight,*100 두더지눈.png
   
  IF ErrorLevel=0
  { 

   MouseClick,,XX,YY
   
  }

}

9::ExitApp
 실행 결과는 아래 동영상과 같습니다.


 그렇다면 이 방법이 최선일까요? 점수를 더 올리기 위해서는 어떻게 해야할까요? 아래 글을 보시기 전에 고민을 해보셨으면 합니다.






























 정답은 9곳을 계속 누르고 있으면 됩니다. 첫 번째 구멍부터 아홉 번째 구멍까지 계속 순서대로 누르는 방법입니다. 코드는 아래와 같습니다. (좌표는 제 컴퓨터 좌표이니 수정해야 합니다.)
0::

loop{
     
  IfWinExist,ahk_exe chrome.exe
  {
   WinActivate,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
   {
     
   }
  }
   
  MouseClick,,202,587
  MouseClick,,365,587
  MouseClick,,530,587
  
  MouseClick,,202,706
  MouseClick,,365,706
  MouseClick,,530,706
  
  MouseClick,,202,820
  MouseClick,,365,820
  MouseClick,,530,820

}

9::ExitApp
 실행결과는 아래 동영상과 같습니다.


 이 방법대로면 점수가 높아져야하지만 별로 높아지지가 않습니다. 마우스 이동 속도가 느리기 때문입니다.


 마우스를 이동하지 않고도 누르는 방법이 있습니다. 이와 같은 클릭 방법을 비활성화 클릭이라고 하며 ControlClick 함수를 이용하면 됩니다. ControlClick,X좌표,Y좌표,클릭하려는 창 이름 형태로 입력하면 됩니다. 코드는 아래와 같습니다.(좌표는 제 컴퓨터 좌표이니 수정해야 합니다.)
0::

loop{
     
  IfWinExist,ahk_exe chrome.exe
  {
   WinActivate,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
   {
     
   }
  }
  
  ControlClick, X202 Y587,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
  ControlClick, X365 Y587,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
  ControlClick, X530 Y587,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome

  ControlClick, X202 Y706,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
  ControlClick, X365 Y706,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
  ControlClick, X530 Y706,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome

  ControlClick, X202 Y820,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
  ControlClick, X365 Y820,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome
  ControlClick, X530 Y820,> 두더지 - 게임엔젤 게임랜드 > 중독성게임 - Chrome

}

9::ExitApp
 실행 결과는 아래 동영상과 같습니다.


 점수가 약 4배 정도가 올랐습니다. 너무 빠르게 누르게 되어 두더지를 두 번씩 때리게 되었고 점수가 비정상적으로 높아졌습니다. 결론적으로 두더지를 아주 학살해버렸습니다.


※ 참고문헌
http://fg.gameangel.com/10300000000002 두더지게임 사이트
https://secretgd.tistory.com/236

2019년 3월 28일 목요일

[R 강의] 369 게임 박수치기

R을 이용해 369게임 규칙에 맞게 박수치도록하는 방법을 알려드리려고 합니다.
R에 익숙해지려면 함수을 많이 써봐야하는데 뭔가 재밌는 주제를 선택하고 싶었고 게임 정답 맞추는 것을 생각하게 되었습니다.

만들기 전 생각을 해봅시다.
1. for 문을 이용해서 1부터 시작해 값을 1씩 증가시키면 되고
2. 증가시킨 숫자들 중 3, 6, 9가 들어가 있는지 확인하고
3. 있다면 '박수'를 치게 만들면 됩니다.


숫자들에서 3, 6, 9가 있는지 확인한다면 제가 주로 쓰는 함수는 strsplit입니다.
strsplit(문자,split="분리하려는 구분자")이므로 strsplit(as.character(숫자),split="")으로 두면 숫자가 문자로 바뀐 뒤 각각 분리 됩니다.

분리되고 나면 list가 되기 때문에 unlist를 해주면 백터가 됩니다.

정리하면
unlist(strsplit(as.character(i),split=""))
정리된 코드를 number_split에 저장하겠습니다.
number_split<-unlist(strsplit(as.character(i),split=""))

이제 number_split에서 3, 6, 9가 있는지 확인을 해야합니다.
저는 number_split가 3인지 6인지 9인지 확인할 것이고 확인한 뒤에는 논리 연산자가 되기 때문에 더하면 3, 6, 9가 있는 갯수가 됩니다.

정리하면
sum(number_split==3 | number_split==6 | number_split==9)
정리된 코드를 have369에 저장하겠습니다.
have369<-sum(number_split==3 | number_split==6 | number_split==9)

마지막으로 if문을 이용해 have369가 0이상이면 박수가 출력되게 하고 아니면 그냥 숫자가 출력되도록 하겠습니다.

이제 for 문을 이용해 숫자를 1씩 증가하게 하면 되는데 출력되는 속도가 너무 빠르므로 for 문 안에 시간을 약간 주려고 합니다. Sys.sleep(0.1)을 하면 0.1초의 간격을 준다는 의미입니다. for문 맨 마지막에 넣겠습니다.

최종 코드는 다음과 같습니다.
# 3,6,9 game
number<-1000

for(i in c(1:number)){

  number_split<-unlist(strsplit(as.character(i),split=""))
  have369<-sum(number_split==3 | number_split==6 | number_split==9)

  if(have369>0){

    print("박수")

  }else{

    print(i)

  }

  Sys.sleep(0.1)

}

2019년 3월 4일 월요일

[잡담] 프렌즈 레이싱 30수정 뽑기(카트 바디) 시뮬레이터

 전에 프렌즈 레이싱 수정 뽑기를 몇 번 정도해야 자신의 카트를 업그레이드 할 수 있는지 계산해주는 시뮬레이터를 제작해서 배포했습니다. 곰곰히 생각보니 전에 제작한 시뮬레이터가 충분히 도움이 되지만 뽑기의 재미를 넣지 못한 것 같습니다. javascript를 공부하는데 시간이 걸렸지만 실제 뽑기와 비슷한 시뮬레이터를 만들게 되었습니다.

시뮬레이터 주소 : http://168.131.81.91:3838/Friend%20Racing%20each/

고급 재료박스[10회][카트바디] 그림을 누르면 뽑기가 시작됩니다.







한번 더뽑기를 누르시면 뽑기를 다시 진행합니다. 재미를 추가하기 위해 SS 재료와 S 재료가 얼마나 뽑혔는지에 따라 라이언 동영상과 문구를 넣었습니다.

재밌게 이용해주시면 감사하겠습니다. 내 차가 Max가 될 때 까지 뽑기는 계속된다...






2019년 3월 1일 금요일

[R 강의] leaflet heatmap 그림 그리기

해양학과 학생의 요청으로 이 글을 쓰게 되었습니다.

보통 해양학과에서는 한반도와 환경변수를 같이 그릴 때 Surfer라는 프로그램을 이용한다고 합니다. 제가 확인해봐도 R의 기본 그림보다는 훨씬 예쁜 그림이 그려집니다. 문제는 Surfer를 이용해 반복적으로 그림을 그릴 때 직접 클릭을 해야해서 시간이 많이 소요됩니다. R을 이용해 Surfer 만큼 예쁜 그림을 빠르게 그리는 방법을 설명하려고 합니다.

지도 그림은 r shiny에서 자주 이용되는 leaflet을 이용하여 그리겠습니다. leaflet를 이용하면 providers에 저장되어 있는 이름을 이용해 원하는 지도 디자인을 선택할 수 있어 편리합니다. leaflet과 leaflet.extras 패키지를 설치 한 뒤 아래의 코드를 실행해봅시다.

library(leaflet)
library(leaflet.extras)

m<-leaflet(quakes) %>% addProviderTiles(providers$CartoDB) %>%
  setView(lng=179,lat=-20,zoom=4) %>%
  addHeatmap(lng = ~long, lat = ~lat, intensity = ~mag,blur = 20, max = 50, radius = 15)
m
leaflet과 leaflet.extras 패키지를 활성화 한 뒤 leaflet 함수를 이용하여 그림을 그립니다. 처음에 leaflet 안에 그리려는 데이터를 넣습니다. leaflet(데이터)  quakes는 내장되어 있는 데이터 셋으로 지진이 발생한 위도, 경도, 관련 변수들이 포함되어 있습니다.
다음으로 옵션을 추가하기 위해 %>%를 써준 뒤 addProviderTiles(providers$지도 디자인 이름)을 적습니다. 느낌적으로 지도 디자인을 정해주는 함수임을 알 수 있습니다.

그 다음으로 setView 옵션을 하나 더 추가 합니다. setView(lng=경도 값, lat=위도 값,zoom=확대 축소 정도)  setView을 추가하면 그림 파일을 만들었을 때 Viewer 탭에 있는 그림과 다르게 출력되는 것을 방지해줍니다.

마지막으로 addHeatmap은 heatmap을 그리는 함수로 addHeatmap(lng = ~데이터에서 경도 변수 이름, lat = ~데이터에서 위도 변수 이름, intensity = ~데이터에서 그리려는 변수 이름,blur = 숫자값, max = 숫자값, radius = 숫자값)  형식에 맞게 적어줍니다.

설정한 그림을 m이라는 변수에 저장했기 때문에 m을 실행하면 Rstudio Viewer 탭에 그림이 출력되는 것을 확인할 수 있습니다.



그린 그림을 png 파일로 저장해야하는데 기본적인 png 함수로는 Viewer 탭에 있는 그림을 저장할 수가 없습니다. 해결 방법은 Viewer 탭에 있는 그림을 html로 저장한 뒤 html을 다시 읽어 그림 파일로 저장하면 됩니다. 이 과정에 필요한 패키지인 htmlwidgets과 webshot을 설치합시다.

library(htmlwidgets)
library(webshot)

saveWidget(m, "m.html", selfcontained = T)
webshot("m.html", file = "m.png")
htmlwidgets과 webshot 패키지를 활성화 한 뒤 saveWidget 함수를 이용하여 Viewer 탭의 그림을 html 파일로 저장합니다. saveWidget(저장하려는 그림,"파일 경로 및 이름",selfcontained=T)  selfcontained를 F로 하면 html 파일과 관련된 폴더까지 생성되기 때문에 T로 설정합시다.

webshot으로 html 파일을 그림 파일로 생성합니다. webshot("그림 파일로 생성하려는 html 파일 경로 및 이름",file="생성하려는 그림 파일 경로 및 이름")  Viewer 탭에 있는 그림과 똑같은 그림을 얻었습니다!

PhantomJS not found. You can install it with webshot::install_phantomjs(). If it is installed, please make sure the phantomjs executable can be found via the PATH variable.
webshot 함수를 실행했을 때 다음과 같은 에러 메세지가 출력된다면 webshot::install_phantomjs()을 실행해줍니다. 파일을 추가로 다운받은 뒤 실행하면 정상적으로 작동합니다.



거의다 왔습니다. 그림을 반복적으로 생성하는 방법만 배우면 됩니다.
quakes$date<-rep(1:10,each=100)

for(i in c(1:10)){
  
  data_temp<-subset(quakes,quakes$date==i)
  
  m<-leaflet(data_temp) %>% addProviderTiles(providers$CartoDB) %>%
    setView(lng=179,lat=-20,zoom=4) %>%
    addHeatmap(lng = ~long, lat = ~lat, intensity = ~mag,blur = 20, max = 10, radius = 15)
  
  saveWidget(m, "m.html", selfcontained = T)
  
  plot_name<-sprintf("%s.png",i)
  webshot("m.html", file = plot_name)
  
  print(i)
  
}
quakes 데이터에 반복한 숫자를 넣어 date라는 변수를 만들어줍니다. 날짜에 따라 그림을 그리기 위해서 임으로 생성했습니다. 위 코드를 설명하면 아래와 같습니다.

1. Subset 함수를 이용해 날짜가 1일 때 데이터를 생성합니다.
2. 생성한 데이터를 이용해 그림을 그립니다.
3. 생성한 그림을 html 파일로 저장합니다.
4. sprintf 함수를 이용하여 1.png라는 이름을 생성해 plot_name에 저장합니다.
5. webshot 함수를 이용해 1.png 그림을 생성합니다.
6. 이 과정을 날짜가 10일 때까지 반복합니다.

다르게 그려진 10개의 그림을 확인할 수 있습니다. addHeatmap의 blur, max, radius를 변화시키면서 그림을 수정해보시길 바랍니다.


※ 참고문헌
https://rpubs.com/bhaskarvk/leaflet-heatmap
https://gis.stackexchange.com/questions/168886/r-how-to-build-heatmap-with-the-leaflet-package
https://stackoverflow.com/questions/31336898/how-to-save-leaflet-in-r-map-as-png-or-jpg-file
https://www.imsbio.co.jp/RGM/R_rdfile?f=webshot/man/webshot.Rd&d=R_CC

2019년 2월 17일 일요일

[잡담] 프렌즈 레이싱 강화 시뮬레이터

 레이싱 게임 어플 1위인 프렌즈 레이싱을 플레이 하다보면 내 차량을 최대로 업그레이드 하려면 돈을 얼마나 써야하는지 얼마나 더 플레이를 해야할지 알고 싶을 때가 있습니다. 상점의 다이아몬드 뽑기를 통해 차량 업그레이드에 필요한 고급재료를 얻을 수 있기 때문에 뽑기를 몇 번 정도해야 내 차량을 최대로 업그레이드 할 수 있는지 알 수 있도록 시뮬레이터를 제작하였습니다.

 사용법을 설명드리면 http://168.131.81.91:3838/Friend%20Racing/ 사이트에 들어가면 아래와 같은 화면이 나옵니다.

1. 현재 강화수치에서는 업그레이드 하려는 차량의 등급과 업그레이드 정도를 숫자로 입력하면 됩니다.

2. 보유하고 있는 재료 수에는 각 항목별로 가지고 있는 재료를 숫자로 입력하면 됩니다.

3. 마지막으로 다이아몬드 뽑기 시뮬레이션에서 다이아몬드 뽑기 횟수를 숫자로 입력하시고 다이아몬드 보유 개수 또한 숫자로 입력하시면 됩니다.

 전부다 입력하신 뒤 50강화까지 계산을 눌렀다면 맨 위에 있는 결과 탭을 누릅니다. 다이아몬드 뽑기로 각 등급이 몇개가 뽑혔는지 알 수 있으며 [필요한 재료 - 뽑기로 얻은 재료]에서는 어느 재료가 더 필요하고 어느 재료가 남는지를 확인할 수 있습니다.

 결과 창 오른쪽에는 카트 강화시 필요한 콘, 필요한 상위 등급 재료를 콘으로 모두 강화할 경우 필요한 콘을 알려줍니다. 또한, C등급으로 환산할 경우 더 필요한 재료도 출력됩니다.

 마지막으로 다이아몬드 뽑기시 필요한 현금을 계산해주며 일주일 마다 다이아몬드를 몇 개를 얻어야 무과금 유저들이 재료를 모두 얻을 수 있을지 계산해줍니다.

  카트 강화와 재료 강화시 필요한 콘을 다이아몬드로 구매시 필요한 현금도 계산하였는데 여러번 확인해본 결과 재료를 모두 얻을 때까지 다이아몬드로 뽑기를 하는 것이 훨씬 효율적입니다.


※ 참고문헌
강화재료 : https://m.cafe.naver.com/ArticleRead.nhn?clubid=29487554&menuid=32&articleid=57686&query=강화






2019년 2월 10일 일요일

[매크로] 오토핫키 중급 - ui 만들기

매크로를 이용하다 보면 매크로가 잘 작동하는지 확인하고 싶을 때가 많습니다. 계속 작동하고 있는지 몇 번이나 작동했는지 확인하기 위해선 ui를 만들어야 합니다. 아주 간단한 ui를 만들어 봅시다.

ui를 만드는 방법은 간단합니다. gui, add, text나 Button, x좌표, y좌표, w폭, h높이, 이름으로 만들 수 있습니다. text면 글씨만 입력됩니다. Button은 클릭할 수 있는 버튼을 만듭니다.마지막으로 gui, Show를 해줘야 ui가 출력됩니다.
gui, add, text, x57 y10 w80 h20, 매크로
gui, add, text, x65 y30 w50 h20 vA, 0초
gui, add, Button, x20 y50 w110 h20, 시작
gui, add, Button, x20 y80 w110 h20, 종료
gui, Show
return
저는 매크로라는 ui 이름과 시작, 종료 버튼을 만들었습니다. 한가지 더 0초라는 text를 만들었는데 h높이 이름 사이에 vA를 하나 더 붙여줬습니다. 이렇게 한 이유는 A라는 위치를 설정해 두고 A를 특정한 값으로 계속 변화시키기 위해서 입니다. 저는 매크로 실행 시간을 알고 싶어서 시간의 변화를 A에 넣으려고 합니다.

이 코드 다음에 return을 넣어야합니다. return 문을 만나면 처음으로 다시 돌아가게 됩니다. return을 적지 않으면 Button을 누르지 않더라도 다음 코드가 바로 실행되어서 Button의 의미를 상실하게 됩니다.

이제 시작 Button을 눌렀을 때 실행되는 코드를 작성해야 합니다.
Button시작:
{
     time:=0
  
     loop{
  
        time:=time+1
        sleep,1000
     
        guicontrol,,A,%time%초

     }
  
}
Button시작:{ }을 하면 위의 시작 버튼을 눌렀을 때 가로 안의 코드가 실행됩니다.

A라는 위치에 시간변화를 표현하기 위해서 처음값이 0인 time 변수를 생성합니다. 그 다음 loop{ } 문을 적은 뒤 안에 time:=time+1을 적어 time을 1씩 증가하게 하고 sleep,1000을 적어 1초의 시간 간격을 넣습니다.

A라는 위치를 계속 변화 시키기 위해서는 gui,,A,%time%초로 작성해야 합니다. A 위치를 %time%초로 변화 시킨다는 의미이며 문자가 아닌 문자 안의 값으로 표현하기 위해서 %time%로 코드를 작성해야 합니다. %%를 넣지 않는다면 'time초'가 출력됩니다.

종료 Button을 눌렀을 때 종료되는 코드를 작성해봅시다.
Button종료:
{
 
  ExitApp
  
}
Buttion종료:{ }안에 App을 종료하는 코드인 ExitApp을 넣으면 됩니다.

간단한 오토핫키 ui 최종 코드는 아래와 같습니다.
gui, add, text, x57 y10 w80 h20, 매크로
gui, add, text, x65 y30 w50 h20 vA, 0초
gui, add, Button, x20 y50 w110 h20, 시작
gui, add, Button, x20 y80 w110 h20, 종료
gui, Show

return

Button시작:
{
 
     time:=0
  
  loop{
  
      time:=time+1
      sleep,1000
     
      guicontrol,,A,%time%초

     }
  
}

Button종료:
{
 
     ExitApp
  
}
제작한 매크로 ui에서 시작 Button을 누르면 아래 동영상과 같이 정상적으로 작동하는 것을 확인할 수 있습니다.


※ 참고문헌
https://elderlykims.tistory.com/ 킴영감 이야기
http://blog.naver.com/PostView.nhn?blogId=geforce_radeon&logNo=221111050583&redirect=Dlog&widgetTypeCall=true&directAccess=false

2019년 2월 6일 수요일

[R shiny] interactive mapping 그림 상단 navbarPage에 이미지 넣기

interactive mapping 그림을 그리다 보니 navbarPage 함수를 이용하여 그림 위쪽에 shiny app의 이름과 탭을 만들게 되었다. App을 더 꾸미고 싶다보니 이름 부분에 이미지를 넣고 싶었지만 쉽게 고칠 수 없었다.


html에서 margin 부분을 수정해야 한다는 것을 직감적으로는 알고 있었지만 코드를 몰라 한참을 헤메였고 stack overflow에서 해결 방법을 찾게 되었다.


(1) 첫 번째로 shiny app의 ui.R과 server.R가 있는 폴더에 이름이 www인 폴더를 생성한다. www 폴더에 빨간 부분에 넣을 이미지 파일을 넣는다.

(2) 두 번째로 ui의 fluidPage 안에 아래의 style 코드를 입력한다. 
tags$style(".img {
             margin-left:-15px;
             margin-right:-15px;
             margin-top:-15px;
             }"),
이름이 img인 style을 생성한다는 의미이다. 이 style은 margin을 수정하도록 되어있다.

(3) 세 번째로 ui.R에서 navbarPage 부분의 title을 title=div(class="img",img(src='이미지 파일 이름',height=이미지의 높이, width=이미지의 폭))로 바꿔준다. class="img" 부분이 두 번째에서 만든 style을 적용한다는 의미다. 여러 개의 이미지를 적용시켜보니 동영상 이미지(gif)도 가능했다.


최종 코드는 아래와 같다.
1. ui.R
library(shiny)
library(leaflet)

ui <- fluidPage(
  
  title="ebichu",
  
  tags$style(".img {
             margin-left:-15px;
             margin-right:-15px;
             margin-top:-15px;
             }"),
  
  # navbarPage(title="map",position = c("fixed-top"),
  navbarPage(title=div(class="img",img(src='ebichu.gif',height=51, width=51)),position = c("fixed-top"),
    
    tabPanel("tab",
      
      leafletOutput("map",height=800)
    
    )
                          
  )
  
)
2. server.R
library(shiny)
library(leaflet)

server <- function(input,output, session){
  
  output$map <- renderLeaflet({
    
    data<-data.frame(longitude=sample(seq(127,129,0.1),100,replace=T),latitude=sample(seq(35,38,0.1),100,replace=T),value=sample(1:100,100,replace=T))
    
    m <- leaflet(data=data) %>%
         setView(lng=128, lat=37 , zoom=6) %>%
         addProviderTiles(providers$CartoDB.Positron) %>%
         addCircles(lng=data$longitude,lat=data$latitude,popup=as.character(data$value),radius=data$value*100,fillColor="blue",stroke=FALSE,fillOpacity=0.4) %>%
         addLegend("bottomleft",colors="blue",title="Color",labels=c(">1000"))
    
  })
  
}
에비츄 캐릭터를 좋아해서 에비츄 동영상 파일을 넣어보았다. 에비츄 동영상 파일을 넣은 shiny app은 https://inziwiduk.shinyapps.io/ebichu/에서 확인할 수 있다.

※ 참고문헌
https://stackoverflow.com/questions/24705431/how-can-i-insert-an-image-into-the-navbar-on-a-shiny-navbarpage
https://stackoverflow.com/questions/24705431/how-can-i-insert-an-image-into-the-navbar-on-a-shiny-navbarpage
https://stackoverflow.com/questions/45307615/r-shiny-image-without-padding-stretched-across-page-using-css
https://stackoverflow.com/questions/19434991/adding-local-image-with-html-to-a-shiny-app

2019년 1월 29일 화요일

[R shiny] interactive mapping 그림 legend customizing

 전에 interactive mapping 그림 만들기에 대한 글을 올린적이 있다. legend의 이름과 색깔, label 이름을 바꾸는 방법만 소개하였고 사각형을 다른 모양으로 바꾸는 방법은 설명하지 않아 설명하려한다.

 결론부터 말하자면 legend의 모양을 바꾸기 위해서는 html 코드를 작성하여 R 함수에 넣어야한다. html 코드는 도형 모양 부터 라벨까지 일일이 다 만들어야하고 위치도 각각 설정해야한다.

html 코드를 만드는 함수는 아래와 같다.

# addLegendCustom

addLegendCustom<-function(map,colors,labels,sizes,shapes,borders,ms,ml,mt,opacity = 0.4){

  make_shapes<-function(colors,sizes,borders,shapes,ms) {

    shapes<-gsub("circle", "50%", shapes)

    shapes<-gsub("square", "0%", shapes)

    paste0(colors,"; width:",sizes,"px; height:",sizes,"px; border:1px solid ",borders,"; border-radius:",shapes,";margin-left:",ms,"px",";margin-top: 7px;")

  }

  make_labels<-function(sizes,labels,ml,mt) {

    paste0("<div style='display: inline-block;height: ",sizes,"px;margin-top:",mt,"px;line-height: ",sizes, "px;margin-left:",ml,"px;'>",labels,"</div>")

  }

  legend_colors<-make_shapes(colors, sizes, borders, shapes,ms)
  legend_labels<-make_labels(sizes, labels,ml,mt)

  return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity,position="bottomleft",title="Abundance"))

}
addLegendCustom 함수는 addLegendCustom(legend를 입력할 지도,도형의 색,도형의 label,도형의 크기,도형의 모양,도형 테두리 색,도형의 왼쪽 마진,label의 왼쪽 마진,label의 위쪽 마진)으로 구성되어있다.

(1) make_shapes
addLegendCustom 함수 안에 있는 make_shapes 함수는 도형을 만들고 위치를 설정하는 함수이다. make_shapes(도형의 색,도형의 크기,도형의 테두리 색,도형의 모양,도형의 왼쪽 마진)으로 구성되어있다.

안의 코드를 살펴보면 gsub 함수를 이용하여 shapes가 circle인 경우 50%, 사각형인 경우 0%으로 바꿔준다. html에서는 'border-radius: 50%' 입력시 원을 표현해준다. 'border-radius: 0%'는 사각형이다. paste0을 살펴보면 'border-radius:' 다음에 shapes 백터를 붙여 html 코드를 만든다.

paste0는 백터 순서대로 값을 붙여주는 함수이다. 예를 들면 아래와 같다.
> paste0(1:12, c("st", "nd", "rd", rep("th", 9)))

 [1] "1st"  "2nd"  "3rd"  "4th"  "5th"  "6th"  "7th"  "8th"  "9th"  "10th" "11th" "12th"
1:12에서 첫 번째 값 1, c("st", "nd", "rd", rep("th", 9))에서 첫 번째 값 'st'를 붙여서 1st를 만든다. 1:12에서 두 번째 값 2, c("st", "nd", "rd", rep("th", 9))에서 두 번째 값 'nd'를 붙여서 2nd를 만든다... 12까지 만들어준다.

paste0 안에 있는 코드를 세분화해서 설명하면 아래와 같다.
여기서 주의 할 점은 width와 height의 크기가 같지 않으면 타원이 표현된다. 위 html 코드를 변형시키면서 원하는 도형의 모양과 위치를 설정하면 된다.

(2) make_labels
make_labels 함수는 label을 만들고 위치를 설정하는 함수이다. paste0 안에 있는 코드를 세분화해서 설명하면 아래와 같다.
마찬가지로 위 html 코드를 변형시키면서 원하는 도형의 모양과 위치를 설정하면 된다.

(3) 마무리
각 변수의 값을 설정했을 때 make_shapes와 make_labels로 생성한 html 코드는 아래와 같음을 확인할 수 있다.

1) make_shapes으로 생성한 html 코드
# addLegendCustom variable
colors <- c("red","blue","blue","blue","white")
labels <- c("1000","100","10","1","1>")
sizes <- (c(log(1000+1),log(100+1),log(10+1),log(1+1),log(0.5+1))+1)*4
shapes <- c("circle","circle","circle","circle","circle")
borders <- c("red","blue","blue","blue","black")
ms<-c(0,5,9,12.5,13)
mt<-c(7,7,8,0,0)
ml<-c(0,9,18,25,23)

> legend_colors
[1] "red; width:31.6350191172609px; height:31.6350191172609px; border:1px solid red; border-radius:50%;margin-left:0px;margin-top: 7px;"    
[2] "blue; width:22.460482067365px; height:22.460482067365px; border:1px solid blue; border-radius:50%;margin-left:5px;margin-top: 7px;"    
[3] "blue; width:13.5915810911935px; height:13.5915810911935px; border:1px solid blue; border-radius:50%;margin-left:9px;margin-top: 7px;"  
[4] "blue; width:6.77258872223978px; height:6.77258872223978px; border:1px solid blue; border-radius:50%;margin-left:12.5px;margin-top: 7px;"
[5] "white; width:5.62186043243266px; height:5.62186043243266px; border:1px solid black; border-radius:50%;margin-left:13px;margin-top: 7px;"
2) make_labels로 생성한 html 코드
> legend_labels
[1] "<div style='display: inline-block;height: 31.6350191172609px;margin-top:7px;line-height: 31.6350191172609px;margin-left:0px;'>1000</div>"
[2] "<div style='display: inline-block;height: 22.460482067365px;margin-top:7px;line-height: 22.460482067365px;margin-left:9px;'>100</div>"  
[3] "<div style='display: inline-block;height: 13.5915810911935px;margin-top:8px;line-height: 13.5915810911935px;margin-left:18px;'>10</div>"
[4] "<div style='display: inline-block;height: 6.77258872223978px;margin-top:0px;line-height: 6.77258872223978px;margin-left:25px;'>1</div>" 
[5] "<div style='display: inline-block;height: 5.62186043243266px;margin-top:0px;line-height: 5.62186043243266px;margin-left:23px;'>1></div>"
마지막으로 addLegend의 colors에 legend_colors, lables에 legend_labels를 입력하고 설정사항을 추가하면 완성이다.
return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity,position="bottomleft",title="Abundance"))
생성한 함수를 이용하여 맵에 legend를 그리려면 addLegend가 있던 곳에 addLegendCustom 함수를 입력하면 된다.
m <- leaflet(data=data) %>%
     setView(lng=128, lat=37 , zoom=6) %>%
     addProviderTiles(providers$CartoDB.Positron) %>%
     addLegendCustom(colors,labels,sizes,shapes,borders,ms,ml,mt)

최종 코드는 아래와 같다.
1. ui.R
library(shiny)
library(leaflet)

ui <- fluidPage(
  
  leafletOutput("map",height = 800)
  
)
2. server.R
library(shiny)
library(leaflet)

server <- function(input,output, session){
  
  output$map <- renderLeaflet({
    
    # addLegendCustom
    addLegendCustom<-function(map,colors,labels,sizes,shapes,borders,ms,ml,mt,opacity = 0.4){
      
      make_shapes<-function(colors,sizes,borders,shapes,ms) {
        
        shapes<-gsub("circle", "50%", shapes)
        shapes<-gsub("square", "0%", shapes)
        paste0(colors,"; width:",sizes,"px; height:",sizes,"px; border:1px solid ",borders,"; border-radius:",shapes,";margin-left:",ms,"px",";margin-top: 7px;")
        
      }
      
      make_labels<-function(sizes,labels,ml,mt) {
        
        paste0("<div style='display: inline-block;height: ",sizes,"px;margin-top:",mt,"px;line-height: ",sizes, "px;margin-left:",ml,"px;'>",labels,"</div>")
        
      }
      
      legend_colors<-make_shapes(colors, sizes, borders, shapes,ms)
      legend_labels<-make_labels(sizes, labels,ml,mt)
      
      return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity,position="bottomleft",title="Abundance"))
      
    }
    
    ######################################################################
    
    # addLegendCustom variable
    colors <- c("red","blue","blue","blue","white")
    labels <- c("1000","100","10","1","1>")
    sizes <- (c(log(1000+1),log(100+1),log(10+1),log(1+1),log(0.5+1))+1)*4
    shapes <- c("circle","circle","circle","circle","circle")
    borders <- c("red","blue","blue","blue","black")
    ms<-c(0,5,9,12.5,13)
    mt<-c(7,7,8,0,0)
    ml<-c(0,9,18,25,23)
    
    ######################################################################
    
    m <- leaflet(data=data) %>%
         setView(lng=128, lat=37 , zoom=6) %>%
         addProviderTiles(providers$CartoDB.Positron) %>%
         addLegendCustom(colors,labels,sizes,shapes,borders,ms,ml,mt)
    
  })
  
}

결과를 확인해보면 짜임새 있게 구성된 legend를 확인할 수 있다.










※ 참고문헌
https://stackoverflow.com/questions/52812238/custom-legend-with-r-leaflet-circles-and-squares-in-same-plot-legends
https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
https://www.w3schools.com/css/tryit.asp?filename=trycss_inline-block_span1

2019년 1월 28일 월요일

[매크로] 오토핫키 기초

 제가 매크로에 관심을 가지게 된 계기는 리니지m이 출시될 쯤 입니다. 리니지m 특성상 사냥하는 곳에서 서로를 죽일 수 있었기 때문에 죽지 않기 위해 매크로를 이용하는 유저들이 많았습니다. 매크로를 이용하는 유저들을 막기위해 엔씨소프트는 불법 프로그램을 이용한 유저들에게 경고를 주거나 영구정지를 했었습니다. 이와 같은 상황에서 저는 유저들이 왜 매크로를 이용하는지 어떤 구조로 작동하는지를 이해하고 싶었고 매크로에 입문하게 되었습니다.

 매크로를 만들기 전 매크로를 만드는 이유를 명확히해야 합니다. 대부분 매크로를 제작하는 이유는 반복 작업을 컴퓨터가 대신하길 원하는 것입니다. 게임을 예로들면 '내가 직접 플레이하지 않아도 레벨업을 하고 싶다'가 이유가 됩니다. 아니면 '내가 직접 플레이하지 않아도 게임재화를 많이 벌고 싶다'가 될껍니다. 만드는 이유를 명확히해야 매크로를 만들 때 우왕좌왕하지 않을 뿐만 아니라 매크로를 제작하는데 시간이 오래 걸리지만 제작해서 얻는 이점을 생각하여 중간에 포기하지 않을 것입니다.

 매크로 프로그램 중 오토핫키를 이용하는 이유는 구글 검색시 스트립트를 직접 작성하여 만들 수 있는 매크로 프로그램이었기 때문입니다. 저는 R 프로그램을 많이 다뤄봐서 그런지 오토핫키 명령문에 적응한 뒤로는 많이 어렵지 않았습니다. 혹시 R 프로그램 부터 배우다가 장벽을 느끼신 분들을 오토핫키로 프로그램에 대한 흥미를 느끼시고 다시 돌아가시는게 좋다고 생각합니다.

 지금부터 알려드리는 오토핫키 명령문은 매크로를 만드는데 아주 기초적인 것들 입니다. 몇 개 안되지만 이 정도만 알아도 원하는 매크로를 만들 수 있습니다.

1. 매크로 시작과 종료
0::

Msgbox,ok

9::ExitApp
 매크로를 처음 만들 때 시작과 종료 키를 만들지 않으면 매크로를 시작을 했을 때 종료를 할 수 없는 난감한 상황이 발생합니다. 다른 코드를 적을 때도 위 코드를 이용하겠습니다. 0::은 키보드 숫자 0을 누르면 매크로가 시작되게 합니다. 맨 앞에 넣어야하며 0대신 자신이 하고 싶은 키를 넣으셔도 상관없습니다. 9::ExitApp은 키보드 숫자 9를 누르면 매크로가 종료되게 합니다. 맨 끝에 넣어야하며 9 대신 다른 키를 넣어도 됩니다.

 Msgbox,ok는 매크로가 시작되면 ok를 출력합니다. ok 대신 다른 문장을 넣어도 됩니다.


작성한 코드를 실행하려면 아래의 빨간색 단축키를 누르면 됩니다.


스크립트가 저장 안되어 있다면 저장 창이 뜹니다.


바탕화면에 오토핫키 폴더를 하나 생성합니다.


오토핫키 폴더에 스크립트를 example로 저장합니다.


저장이 완료되면 편집기 아래 그림과 같은 빨간색 부분이 생깁니다.


0을 누르면 매크로가 시작되어 ok라는 MsgBox가 생깁니다. 확인을 누르기 전까지 다음 코드로 넘어가지 않습니다.


Msgbox의 확인을 누르면 코드가 모드 실행되어 매크로가 종료됩니다. 편집기 아래 창에 종료 메시지와 매크로 실행시간이 출력됩니다.


2. MouseClick
영어 그대로 마우스 클릭입니다.
0::

MouseClick,,x좌표,y좌표,클릭횟수

9::ExitApp
 내가 누르고 싶은 x좌표와 y좌표를 입력하면 됩니다. x좌표와 y좌표는 SciTE4AutoHotkey 도구 단축키에 있는 Active Window Info를 누르면 확인할 수 있습니다.



 Mouse Position 부분을 보시면 Absolute, Relative, Client 3가지 항목이 있습니다. Absolute는 윈도우 화면 전체에서의 좌표를 나타내고, Relative는 선택한 창에서의 좌표, Client는 선택한 창에서 내부 화면 영역의 좌표를 의미합니다. 대부분 창 안에서 클릭하므로 Relative를 주로 씁니다. 내가 클릭하고 싶은 위치에 마우스 커서를 올렸을 때 Relative에 적힌 좌표값을 위의 코드에 적으면 됩니다.(좌표는 왼쪽 위가 시작점이므로 0,0입니다.)


3. MouseClickDrag
 마우스 드래그도 가능합니다.
0::

MouseClickDrag,right or left(마우스키를 의미),처음 x좌표,처음 y좌표,마지막 x좌표,마지막 y좌표,드래그 속도(0~100)

9::ExitApp
 right or left 부분에서 마우스 오른쪽 키를 누르고 드래그 하도록 할지 왼쪽 키를 누르고 드래그 하도록 할지 정할 수 있습니다. 다음으로 마우스를 드래그 할 때 처음에 누르는 위치와 드래그가 끝나는 마지막 좌표를 입력해야 합니다. 마지막으로 드래그의 속도를 1~100 중에서 정해주면 됩니다.

4. Send
0::

Send,입력하고 싶은 문자

9::ExitApp
 매크로를 이용하여 글씨를 입력하고 싶을 때 Send를 이용합니다. 커서가 있는 위치에 Send, 다음에 입력한 문자 그대로가 입력됩니다. Send 코드 전에 커서 위치를 누르는 MouseClick 코드를 추가하는게 좋습니다.

5. Sleep
0::

Sleep,숫자

9::ExitApp
 Sleep은 얼마정도 간격을 두고 코드를 실행하고 싶을 때 이용하는 명령문 입니다. 1000이 1초를 의미하기 때문에 숫자가 5000이면 5초 뒤에 다음 코드로 넘어 간다는 의미입니다.

6. 특정 문자에 값을 저장
0::

A:=1

9::ExitApp
 :=을 이용하여 특정 문자에 값을 저장할 수 있습니다. 위 코드는 A에 1을 저장한다는 의미입니다.

0::

A:="안녕"

9::ExitApp
 문자를 저장하고 싶을 때는 ""를 써야 합니다.


0::

A:="안녕"
B:=A

9::ExitApp
 A에 저장되어 있는 값을 B라는 문자에 저장하고 싶을 때 :=를 이용하면 됩니다.

0::

A:="안녕"
MsgBox,%A%

9::ExitApp
 A에 저장되어 있는 값을 MsgBox로 출력하려면 %%를 써야 합니다. 적지 않으면 A가 출력됩니다.

7. loop
0::

loop,반복횟수
{

  break

}

9::ExitApp
 반복을 하고 싶을 때는 loop를 이용하면 됩니다. loop 다음에 있는 { } 안에 코드를 넣어야 반복합니다. loop 다음에 ,반복횟수를 적어주면 반복횟수 만큼 반복합니다. ,반복횟수를 적지 않으면 loop 문을 계속 반복하게 됩니다. loop를 멈추고 싶을 경우 break를 넣어주시면 break를 만나는 순간 loop 문이 종료됩니다.

8. if
0::

if(조건1)
{

}
else if(조건2)
{

}
else
{

}

9::ExitApp
 조건문을 넣고 싶을 때는 if를 이용하면 됩니다. 조건1을 만족하면 조건1 { } 안에 있는 코드를 실행하고 조건1이 만족하지 않으면 조건2가 맞는지 확인합니다. 조건2가 만족한다면 조건2 { } 안에 있는 코드를 실행하고 조건2가 만족하지 않으면 else { } 안에 있는 코드를 실행하게 됩니다.

쉽게 설명하면 위와 같지만 자세히 설명하자면 조건1 부분이 참(True)일 경우 { } 안에 있는 코드가 실행됩니다. 그렇다면 조건을 어떻게 만드는지 알아야합니다. 보통 2개의 값을 비교할 때는 아래와 같은 연산자를 이용하시면 됩니다.

(x > y)   ;x가 y보다 큰가?

(x < y)   ;x가 y보다 작은가?

(x = y)   ;x와 y가 같은가?

(x != y)   ;x와 y가 같지 않은가?

(x <> y)   ;x와 y가 다른가?

(x >= y)   ;x가 y보다 크거나 같은가?

(x <= y)   ;x가 y보다 작거나 같은가?
조건을 여러개 중첩하고 싶을 때는 AND(&&)와 OR(||)를 이용합니다. |는 키보드의 Back space 옆에 있는 \와 shift로 적을 수 있습니다.(\+shift)

(x > 0 AND x < 10)   ;x가 0과 10 사이인가?

(x > 0 && x < 10)   ;x가 0과 10 사이인가?

(x = 1 OR x = 2)   ;x가 1 아니면 2인가?

(x = 1 || x = 2)   ;x가 1 아니면 2인가?
9. ImageSearch
0::

ImageSearch,캡처를 찾았을 경우 x좌표,캡처를 찾았을 경우 y좌표,0,0,A_ScreenWidth,A_ScreenHeight,*이미지정확도값 캡처.png

IF ErrorLevel=0
{

}

IF ErrorLevel=1
{

}

9::ExitApp

 내가 캡처해둔 그림과 똑같은 이미지를 찾고 싶을 때 ImageSearch 함수를 이용해야 합니다.(캡처는 보조프로그램에 있는 '캡처 도구'를 이용하면 됩니다) 이미지를 찾았다면 '캡처를 찾았을 경우 x좌표'와 '캡처를 찾았을 경우 y좌표'에 이미지 위치가 저장됩니다.

 0,0,A_ScreenWidth,A_ScreenHeight는 이미지를 전체 화면에서 찾는다는 의미입니다. 0,0 부분에 100,100을 넣는다면 x좌표가 100이고 y좌표가 100인 부분부터 찾게 됩니다. A_ScreenWidth,A_ScreenHeight은 화면의 최대폭과 최대 높이를 의미하는데 이부분에 다른 값을 넣는다면 해당 위치까지 이미지를 찾게 됩니다. 대부분 전체 화면에서 찾기 때문에 그대로 이용해도 상관없습니다.

 '*이미지 허용값'은 캡처 이미지와 완벽하게 같은 이미지를 찾을 수 없기 때문에 어느 정도의 허용값을 준다고 이해하시면 됩니다. 저는 보통 50~100의 값을 이용하며 값이 작을 수록 캡처와 거의 같은 이미지를 찾게되고 값이 클수록 캡처와 약간 다른 이미지를 찾을 수 있게 됩니다. 자신이 찾고 싶은 이미지가 잘 찾아질 때까지 값을 변경해봐야 합니다.

 다음으로 캡처.png와 같이 쓰고 싶다면 스크립트가 저장된 위치에 캡처.png 파일이 있어야 합니다. 스트립트가 바탕화면 오토핫키 폴더에 있으므로 같은 곳에 넣습니다. 캡처.png 파일이 스크립트가 저장된 위치가 아니라 다른 곳에 있다면 모든 경로를 다 적어야합니다. 예를 들어 C:\Users\user\Desktop\캡처.png 같이 적어야합니다. 되도록이면 폴더를 하나 만들어서 스크립트와 이미지를 같이 저장해두는게 좋습니다.

 마지막으로 IF ErrorLevel=0 { }은 그림을 찾았을 경우 { } 안에 있는 코드를 실행하고 IF ErrorLevel=1 { }은 그림을 찾지 못했을 경우 { } 안에 있는 코드를 실행합니다.

 매크로를 실행했을 때 이미지를 찾지 못한다면 찾으려는 화면에 커서를 두고 실행했는지 확인하시길 바랍니다. 그래도 안된다면 허용값을 더 크게 해보시기 바랍니다.

※ 주의할 점

(1) 캡처한 이미지 확장자 명이 jpg면 작동하지 않습니다. png나 bmp 파일로 저장하는게 좋습니다. 

(2) 이미지는 가능한 작게 특징이 잡히도록 캡처해야 합니다. 캡처하려는 이미지의 배경이 바뀌는 경우 배경를 제외해서 캡처해야합니다.
크롬 아이콘을 예를 들어 설명하면 배경까지 캡처하는 것 보다 가운데의 특징적인 부분만 캡처하는 것이 좋습니다.

(X)
 (O)

(3) 캡처한 이미지의 사이즈를 바꾸면 안됩니다. 예를 들어 앱플레이어의 사이즈가 바뀌면 기존에 캡처한 이미지를 못찾을 수도 있습니다.

10. WinActivate
0::

IfWinExist,ahk_exe notepad.exe
{
  WinActivate,제목 없음 - 메모장
  {

  }
}

9::ExitApp
 메모장을 예를 들어서 설명하겠습니다. 메모장에 커서를 두고 Active Window Info를 확인하면 Window Title, Class and Process 부분에 메모장의 이름, 메모장의 클래스 이름, 메모장의 프로세스 이름으로 구성되어 있는 것을 확인할 수 있습니다.


 ifWinExist,프로세스는 프로세스가 실행되어 있다면 { }안의 코드를 실행하는 함수 입니다.
ifWinExist, 뒤에 Active Window Info에 나와있는 메모장의 프로세스(ahk_exe notepad.exe)를 적어주면 메모장이 실행되어 있는지 확인합니다.

 WinActivate,프로그램명은 프로그램명과 같은 프로그램 창을 맨위로 올려줍니다. 최소화 되어있더라도 프로그램 창을 띄워줍니다.

 요약하자면 ifWinExist 함수로 프로그램이 실행되어 있는지 확인하고 WinActivate으로 프로그램을 활성화한 뒤 코드를 실행하도록 구성하면 됩니다.


 지금까지의 코드를 이용해서 제작해보고 싶은 매크로를 직접 만들어보며 연습해보시길 바랍니다.


※ 참고문헌
https://elderlykims.tistory.com/ 킴영감 이야기
https://secretgd.tistory.com
http://autohotkey.kro.kr/
http://urin79.com/blog/534396

2019년 1월 24일 목요일

[매크로] 오토핫키(AutoHotkey) 설치

매크로를 만들기 위해 오토핫키(AutoHotkey)라는 프로그램을 설치해보자. 처음에 오토핫키(AutoHotkey)를 먼저 설치한 다음 스크립트를 적고 편집할 수 있는 SciTE4AutoHotkey도 설치해야한다.


1. 오토핫키(AutoHotkey) 설치 방법

https://www.autohotkey.com/download/ahk-install.exe 이 링크를 누르면 오토핫키 프로그램을 다운 받을 수 있다. 링크가 작동하지 않으면 네이버나 구글에 Autohotkey를 검색하거나 https://www.autohotkey.com 에서 다운 받을 수 있다.

(1) 구글 검색





(2) https://www.autohotkey.com 첫화면



(3) https://www.autohotkey.com Download 화면



(5) AutoHotkey setup 파일 실행 화면



(6) 설치 완료 화면



2. AutoHotkey 편집기 설치 방법

스크립트를 적고 편집할 수 있는 AutoHotkey 편집기를 설치해보자. http://fincs.ahk4.net/scite4ahk/dl/s4ahk-install.exe 이 링크를 누르면 편집기를 다운 받을 수 있다. 링크가 작동하지 않으면 http://fincs.ahk4.net/scite4ahk/ 에서 다운 받을 수 있다. 언어를 한글로 바꾸기 위해 한국어 패치 파일 링크를 눌러 파일을 받아 놓자. (바이러스 파일이나 불법 광고 아님)

(1) http://fincs.ahk4.net/scite4ahk/ 첫화면



(2) SciTE4AutoHotkey setup 파일 실행 화면





(3) 편집기 설치 완료 화면



업데이트를 하라는 문구가 나오는데 할 필요는 없다.





(4) 한글 패치 적용 방법

앞에서 다운 받은 한국어 패치 파일을 C:\Program Files\AutoHotkey\SciTE\locales 경로에 아래와 같이 복사 붙여넣기를 해야한다.


편집기 내에서 설정이 필요하다.

 









예(Y)를 누르면 편집기가 다시 켜지고 한글 입력시 정상적으로 입력되는 것을 확인할 수 있다.


※ 참고문헌
https://elderlykims.tistory.com/ 킴영감 이야기