위의 사진에 나온 소스만 해석할줄 알면 이번 강좌는 이해가 끝난것이다.
이번에는 빨간 공을 움직이다가 특정 좌표에 가면 파랗게 만들어 보도록 하겠다.
그전에 리턴값에 대해 알아보도록 하자
리턴값===
함수안에서 그냥 문자열을 리턴하고 싶다면 괄호 없이 "문자열"을 적도록 하자.
숫자를 리턴하고 싶으면 그냥 숫자를 알맞은 곳에 적으면 된다.
("문자열")하면 안된다.
(define (만약x x) (if (= x 1) 1 "1이아니다"))
만약x함수에 인자를 하나 전달해서 1이면 1을 리턴하고 아니면 "1이아니다"를 리턴한다
리턴값을 다음과 같이 응용할 수 있다.
(if (= (만약x 1) 1) "만약x에 1을 넣으니 1이 나왔다" "1이 안나왔다.")
=========
이번강좌에서 알아야 할 함수는 다음과 같다.
우선 나열하고 알려주도록 하겠다.
핵심===
big-bang
check-with
on-key
on-draw
================
빅뱅함수에 시간개념을 추가하려면?===
on-tick이라는 함수를 사용하면 된다
(on-tick 톡함수)
big-bang의 인자로 넣어주자.
첫번째인자로는 안된다.
상태 초기값으로 정해져있으므로 안된다.
on-tick은 1초에 28번 실행된다.
28번을 더 많게 또는 적게 바꿀 수 있다.
톡함수는 현재 상태와 같은 데이터구조를 리턴해야 한다.
리스트면 리스트를 리턴하고 그냥 숫자면 숫자를 리턴하면 된다.
빅뱅 초기값을0으로하고 on-tick의 톡함수로 add1을 써보자.
1초에 28번씩 톡함수가 호출된다.
한번 호출될때마다 1씩 증가한다.
이렇게 시간 개념이 추가되었다.
====================================
중간===
place-image
string=?
circle
list-ref
empty-scene
set!
=======
이미 배운것===
#lang scheme
begin
require
define
cond
and
>
<
=
list
============
우선 소스를 찬찬히 살펴보자.
모르는 함수는 뭐가 있는지.
대충 어떤식으로 돌아갈지 상상해보자.
소스시작!===
#lang scheme
;공움직여서 파랗게 만들기
;아래 두줄은 c언어의 include와 같은 기능이다.
;(require 2htdp/universe) 하면 big-bang이라는 함수를 쓸 수 있다.
;아주 유용하니 잘 알아두도록 하자.
(require 2htdp/universe)
(require 2htdp/image)
;계획을 말하겠다.
;x와y는 공의 좌표다.
;왼쪽 위가 0,0이다.
;x,y가 특정 좌표가 되면 상태 변수를 바꿀것이다.
;그냥 숫자로 하면 헛갈릴 수 있다.
;그래서 파란이라는 변수를 사용하겠다.
(define x 50)
(define y 50)
(define 상태 0)
(define 파란 1)
(define (키보드입력 상태 키)
(cond [(and (> x 10) (string=? "left" 키)) (begin (set! x (- x 10)) (list x y))]
[(and (< x 390)(string=? "right" 키)) (begin (set! x (+ x 10)) (list x y))]
[(and (> y 10) (string=? "up" 키)) (begin (set! y (- y 10)) (list x y))]
[(and (< y 390) (string=? "down" 키)) (begin (set! y (+ y 10)) (list x y))]
[else (list x y)]))
(define (그리기 cor)
(place-image (circle 5 "solid" (if (= 상태 파란) "blue" "red")) (list-ref cor 0) (list-ref cor 1) (empty-scene 400 400)))
(define (파란변신 cor)
(begin (cond
[(and (= (list-ref cor 0) 30) (= (list-ref cor 1) 30)) (set! 상태 파란) ])#t))
(big-bang (list x y 상태)
(check-with 파란변신)
(on-key 키보드입력)
(on-draw 그리기))
big-bang===
빅뱅 함수의 첫번째 인자 (list x y 상태)는 상태 초기값이다.
이 초기값을 가지고 함수들을 실행할 것이다.
보통 (지정된함수 함수func)와 같은 모양으로 실행한다.
함수func 가 실행될때 저 상태와 함께 실행된다.(또는 다른 인자와 함께)
지정된함수가 on-key와 같은 것이라면 함수func의 리턴값으로 (list x y 상태)변수가 바뀐다.
리턴값이 초기값과 같은 데이터구조여야 한다.
===========
===
check-with, on-key, on-draw의 인자로 함수 이름이 왔다.
결론적으로 말하자면 이 함수들은 전달받은 함수이름을 조금 다르게 실행하는 것이다.
===
check-with를 간략히 설명해 보겠다.
1. 함수이름(파란변신)을 인자로 전달받는다.
2. 전달받은 함수이름(파란변신)을 실행한다.
=> 여기서는 특정 인자와 함께 실행한다.
=> big-bang의 초기값(여기서는 (list x y 상태))을 인자로해서 실행한다.
=> 즉 (파란변신 (list x y 상태))과 같은 식이 실행된다.
3. 파란변신 함수가 #t를 되돌려주면(리턴하면) 냅둔다.
4. 파란변신 함수가 #f를 되돌려주면(리턴하면) 오류 뿜는다.
@파란변신 함수는 check-with함수뒤에 왔기 때문에 #t나 #f둘중 하나를 리턴해야된다.@
on-key함수를 간략히 설명해 보겠다.
check-with함수와 비슷하다.
다만 전달받은 함수를 인자 2개로 실행시킨다.
인자 두개중 첫번째 것은 현제 빅뱅의 상태를 전달하는데 쓰인다.
=> 현제 빅뱅의 상태는 (list x y 상태)이다.
두번째 인자는 눌린 키를 전달한다.
즉 on-key에 인자로 넘어가는 함수는 최소 2개 이상의 인자를 받을 수 있어야 한다.
비교할때에는 if나 cond를 쓰면 된다.
키가 어떤 키인지 알고싶을때에는 string=?함수를 쓰면 된다.
(if (string=? 키 "up") "up" 0) key변수가 "up" 즉 윗화살표인지 비교한다.
맞으면 "up"을리턴한다.
아니면 0을 리턴한다.
그냥 문자열이나 숫자를 리턴할때는 괄호로 묶지 않도록 하자.
여러 연산 한 후 리턴하고 싶으면 다음과 같이 해보자.
(begin (연산1) (연산2) (연산3) "문자열리턴")
=> "문자열리턴"이 리턴된다.
@자 규칙을 일목요연하게 정리해 주겠다.@
check-with 파란변신
1. 파란변신은 인자로 빅뱅의 상태를 받을수 있어야 한다.(즉 파라미터(인자변수)가 하나 이상이어야함)
2. #t나 #f를 리턴해야만 한다.
on-key 키보드입력
1. 키보드입력 함수는 인자가 2개여야한다.
=> 첫째는 상태를 둘째는 키보드 눌린 값을 받는다.
2. 리턴 값은 빅뱅의 상태 변수와 데이터 구조가 같아야 한다.
on-draw 그리기
1. 그리기 함수는 빅뱅의 상태 변수를 받을 수 있어야 한다.(즉 파라미터가 하나 이상이어야함)
2. scene를 리턴해야 한다. 한마디로 마지막에 그림을 그리면 된다.
=>여러 동작하고싶으면 (begin (동작1) (동작2) (동작3) (그림그리기))이런식으로 응용하자.
자그럼 다른 함수들을 알아보자.
place-image===
(place-image 그림1 x좌표 y좌표 (empty-scene 400 400))
배경크기가 가로세로 400인 곳에 그림1을 출력한다.
(empty-scene 400 400) 대신에 그림이 올 수 있다.
안믿기면 다음을 적고 실행해 보자.
(place-image (circle 5 "solid" "red") 50 50 (square 400 "solid" "green"))
==============
string=?===
(string=? "left" 키)
문자열을 비교할때 쓴다.
키와 "left"가 같은 문자열이라면 #t를 아니라면 #f를 리턴한다.
뭐 그냥 (equal? "left" 키)이라고 써도 된다.
===========
circle===
원을 그려주는 함수다
첫번째 인자로 반지름 두번째 인자로 생김새(안을 체웠냐 안체웟느냐 같은) 세번째 인자로 색상을 전달해줘야 한다.
(circle 5 "solid" "red")
빨간색("red") 안이 체워진("solid") 반지름 5의 원을 그린다
=========
list-ref===
리스트의 특정 원소를 참조할수 있다. 아주 유용하므로 외워두도록 하자.
(list-ref '(1 22 83 884 35 26 47 58 19) 0)
1이 리턴된다.
(list-ref '(1 22 83 884 35 26 47 58 19) 1)
22가 리턴된다.
(list-ref '(1 22 83 884 35 26 47 58 19) 2)
83이 리턴된다.
=>괄호앞에 '가 붙으면 리스트가 된다.
=>@참조번호는 0부터 시작되므로 주의하자!@
===========
empty-scene===
첫번째인자로 가로, 두번째 인자로 세로 크기를 받아서 비어있는 scene를 만든다.
empty-scene대신에 다른 그림을 사용해도 된다.
예를들어 가로세로 400픽셀인 정사각형은 (square 400 "solid" "green")와 같고
가로 400 세로 100픽셀의 직사각형은 (rectangle 400 100 "outline" "red")과 같다.
사용하려면 #lang scheme(또는 #lang racket)바로 밑에 (require 2htdp/image)를 해줘야 한다.
==============
set!===
이미 define으로 선언되어있는 변수의 값, 이미지 등을 바꿔준다.
(set! x (- x 10)) x를 x에 -10한 값을 저장한다. 즉 x에 -10을 한다.
=======
그럼 이제 이 강좌를 처음 보는 사람을 위해서 이 소스에 쓰인 나머지 함수를 설명해 주겠다.
#lang scheme===
언어를 scheme으로 설정하라는 의미이다.
require===
보통 #lang 다음줄에 온다.
다음과 같이 쓴다.
(require 2htdp/universe)
=>htdp는 how to design programs라는 책 이름이다.
인터넷에 있는 소스를 require할수도 있다.
그러면 자동으로 다운로드 받아서 로컬에 설치도 해준다.
=>예: (require (planet orseau/mred-designer:3:7))
begin===
함수를 절차지향적으로 실행시켜준다.
((함수)(함수)(함수)(함수)(함수))
괄호가 있으면 가장 처음것은 함수 이름이다.
함수이름자리에 괄호가 오고 그안에 함수가 왔으니
함수가 실행된 뒤에 리턴값을 다시 함수 이름으로 인식해서 실행하려 할것이다.
이것을 막아주는게 begin이다.
begin을 쓰면 begin다음에 오는 함수들을 순서대로 실행한다.
아주 많이 쓰이므로 잘 알아두도록 하자.
다음 두 식을 하나씩 실행해 보자.
begin이 없는 식은 오류가 날 것이다.
((display "1") (display "2") (display "3"))
(begin (display "1") (display "2") (display "3"))
========
define===
변수나 함수를 정의할때 사용한다.
변수 정의할때는 다음과 같이 사용한다.
(define 변수이름 값)
값 자리에는 이미지가 올수도 있다.
이미지를 넣는방법은 insert메뉴에서 insert image를 누르면된다.
함수를 정의할때는 다음과 같이 사용한다.
(define (함수이름) 몸체)
=>이 함수는 전달받는 인자가 없다.
인자를 전달 받으려면 다음과 같이 해보자
(define (함수이름 변수1 변수2 변수3) 몸체)
=>몸체는 하나일수도 여럿일수도 있다.
@몸체가 하나일경우 큰괄호 안의 식들을 순서대로 실행하기만 원할때 begin을 쓴다.@
다음은 몸체2개인 함수다. 몸체1이 실행되고난후 무조건 몸체2가 실행된다.
(define (함수이름 변수1 변수2 변수3) (몸체1)(몸체2))
=========
cond===
비교할 값이 여러개일경우 쓰면 편리하다
(cond [(조건)(참일때)] [(조건)(참일때)] [(조건)(참일때)])
[(조건)(참일때)]를 많이 쓸수도 있다.
예를 보자. 보기좋으라고 들여쓰기를 하겠다.
(cond [(equal? x "일") "일이군요~"]
[(equal? x "이") "이이군요~"]
[(equal? x "삼") "삼이군요~"]
[(equal? x "사") "사이군요~"])
물론 "일이군요~" 같은 문자열 자리에 괄호로 둘러싸인 함수가 와도 된다.
숫자가 와도 된다.
이미지가 와도 된다!
잠깐===
[]와 ()는 같은 역할을 한다.
그러면 왜 []를쓰나? 하는 사람이 있을것이다.
보기좋으라고 쓴다.
[]자리에 ()와도 되고 ()자리에 []와도 된다.
단 [로 괄호를 열었으면 ]로 닫아야 한다.
=======
=======
and===
if를 중첩해서 쓰는것보다 and를 쓰는게 훨씬 보기좋다.
and는 and뒤에 온 모든 값이 참일때 #t를 돌려준다.
#t는 참이라는 뜻이다.
다음을 보자
(and (= 1 1) (= 2 2) (= 3 3))
(= 1 1)같으니깐 #t를 리턴.
2와 3의 경우도 모두 #t를 리턴한다.
모두 #t(참)이니깐 and함수는 참을 리턴한다.
(and (= 1 1) (= 2 1) (= 3 3))
2와 1이 똑같지 않으므로 #f가 나올것이다.
======
>===
스킴에서는 a>b>c>d>e>f>g를 다음과 같이 쓴다.
(> a b c d e f g)
물론 a>b처럼 두개만 쓸 수도 있다.
(> a b)
====
=(같다라는 의미이다)===
숫자 비교할때에만 쓰인다.
(= 1 "1") 오류난다 "1"은 문자열이기 때문이다.
(= 2 (+ 1 1)) #t가 나온다.
1더하기 1과 2는 같기 때문이다.
=======================
list===
괄호 앞에 '를 붙이면 리스트가 된다.
'(1 2 3 4 5 6)
1 2 3 4 5 6을 원소로 갖는 리스트가 되었다.
그런데 괄호앞에 '를 붙이면 안에 함수가 들었든 뭐가 들었든 글자 그대로 리스트가 된다.
다음 식은 (+ 2 2)가 실행(평가)되지 않고 그대로 리스트가 된다.
'(1 2 3 (+ 2 2) 5 6)
하지만 list를 쓰면 안의 식이 평가된 후에 리스트가 된다.
(list 1 2 3 4 5 6)은 다음과 같다.
(list 1 2 3 4 (+ 2 3) 6)
=======
자 이번강좌를 다 봤으면 연습문제를 하나 풀어보자.
쉬운거===
이 소스를 안 보고 다시 짜보자.
이왕이면 캐릭터하나를 구해다가 움직이게 해보자.
문을 특정 좌표에 그려넣고 그 문에 캐릭터가 접근하면 (exit)함수를 실행시켜 보자.
=========
중간===
간단한 자동차를 하나 그리자.
차가 왼쪽에서 오른쪽으로 계속 지나간다.
오른쪽 버튼을 누르면 속도가 빨라지고 왼쪽버튼을 누르면 속도가 느려진다.
위버튼을 누르면 가속도가 증가하고 아래버튼을 누르면 가속도가 감소한다.
=======
어려운거===
똥피하기 게임을 만들어 보자.
===========