'전체'에 해당되는 글 544건

  1. 2015.06.13 What is Forth? (포스란 무엇이냐) (1)
  2. 2015.01.06 스택 머신
  3. 2014.12.21 pisc 분석
  4. 2014.12.17 PISC 마이크로 프로세서
  5. 2014.09.06 펌)머피의 법칙 책중에서 110개 정도 요약한 부분
  6. 2014.07.14 펌)물막이 이후, 명불허전의 터진 옆구리
  7. 2014.06.11 펌)비만에 시달리는 지구인
  8. 2014.05.22 10대들을 위한 파이선 게임 프로그램 시작하기 (1)
  9. 2014.01.23 펌)값싼 고기는 어떻게 식탁에 오르나
  10. 2014.01.21 펌)시간의 경제학-10년 동안 프로그래밍 배우기
2015.06.13 02:45

What is Forth? (포스란 무엇이냐)

이 글은 python for fun의 forth 편을 번역한 것이다,

뒷부분은 번역이 조금 안되었지만 이해에는 별 문제가 없을 것으로 본다.
lisp의 거울상처럼 움직이는게 신기해서 한번 이해해 보려는 시도의 하나였다.


2015.6.12 -현재 버전 0.7


What is Forth? (포스란 무엇이냐)


알맹이만 말하자면 포스는 컴파일러와 인터프리터를 조합한 것이다.  컴파일러는 이전의 챕터에서 본것 처럼 소스코드를 기계어코드로 바꾸어주는 것이 아니라 "가상"기계의 명령어로 바꾸어주며 우리는 이를 "pcode"라고 부른다. 같은 아이디어가 자바나 파이선 같은 언어에서 쓰이고 특히 최신의 동적언어에서는 특히 그렇다. 

그러나 포스에서 우리는  pcode  레벨에서 프로그램하고 이것이 가상 기계의 어셈블리어라고 부를 수 있는 것이다. 그러나 이 언어어는 동적인 특성이 강하고 흥미롭운 방법으로 확장할 수 있는 언어다. 



포스에서 "snippets of computation"라고 할수 있는  "words"를 가지고 푸시다운 데이타스택을 조작하거나 이들을 다시 연결해서 새로운 "words"를 만들어(compile ) 한단계 더 높은 레벨에서 같은 일을 할 수 있다. 

더 이상 흔하게 쓰이지는 않지만 포스는 공부할 가치가 있는 특징들이 있다. 이 언어는 예제 코드의 공부를 통해서만 얻어질 수 있는 대단한 미니멀리즘이 있다.

포스는 어셈블러에 비해 프로그램을 비교적 쉽게 작성할 수 있는 좋은 타협이며 놀랄만큼 작은 메모리를 사용하고 놀랄만큼 빠르다.  내장된 컴파일러와 인터프리터를 가지고 동시적인 스레드를 갖는 어플리케이션 코드까지 만드는데 몇 킬로 바이트의 메모리와 어셈블러의 1/2 속도를 내는 시스템을 만든적이 있다.

위키백과에 따르면 포스는 부트로더나 임베디드 시스템 , 우주선 어플리케이션에 사용되며 GNU 프로젝트의 활발한 구현도 있다.

이 장에서 우리는 작은 포스  compiler/interpreter 시스템을 만들어 자세하 살펴볼 것이다.
우리의 구현은 매우 작고 기본적인 것이다.  (floats and ints) 숫자만이 기본 데이터 타입이며 IO는  오로지 터미널을 통해서만 일어난다.

나중에 위에서 말한 어플맅케이션을 간단히 보기로 한다. 신문의 메일룸을 공정제어하는 시스템이다, 이제 의자에 앉아 즐겨보자.

인용하는 단어에 대해 이야기하자. 모두 대눈자를 사용하는 단어가 있다면 그거는 포스의 단어다. 우리의 포스는 실제로는 대소문자 구별이 없지만 전통적으로 포스 프로그램은 대문자로 작성되었다.  대소문자가 섞인 것들은 파이선 코드이다. TOS 는 top-of-stack이다. 다른  단어들은 스스로를 나타낼 때 인용부호가 붙을 것이다.

Using the Data Stack

"데이터스택(data stack)"은 중요한 기능이다. 부억의 화로와 같다.  이 기능을 직접 이용하는 것으로 언어의 제약점이 줄어든다.  반드시 후위연산(postfix)과 편해져야 한다. 


이제 예제로 점프해 보자. 포스의 코드는 여기에  Click Here to access forth.py
$ python forth.py
Forth> 5 6 + 7 8 + * .
165


이제 두합의 곱 "(5+6)*(7+8)"을 계산해보자. 여기서는 인픽스 표기법으로 적었으며곱셈이 덧셈의 뒤에 일어나야 한다는 것을 확실하게 만들기 위해  괄호가 필요하다.  리스프 언어처럼 프리픽스 표기법으로 적는다면 괄호 하나가 더 필요하다. 하지만 포스에서 처럼 포스트픽스 연산을 한다면 괄호는 아주 간단히 불필요하게 돈다. 연산자는가 계산에 필요한 위치에 자리잡으면 끝나는 것이다
 
(사족이지만 만약 독자가 일본어를 안다면 포스트픽스로 생각하는 것이 부자연 스럽지 않다는 것을 알것이다,)

일의 진행을 조금 명백히 보여주기 위해 포스의 워드인  "dump"를 사용하여 그때 그때의 데이타 스택의 값을 보여준다. 이제 조금 더  진행하여 각각의 단일한 수행마다 데이타 스택의 변화를 구경하자. 
Forth> 5 dump 6 dump + dump 7 dump 8 dump + dump * dump
ds =  [5]
ds =  [5, 6]
ds =  [11]
ds =  [11, 7]
ds =  [11, 7, 8]
ds =  [11, 15]
ds =  [165]
Forth> 
바라건대 투명한 이해가 있기를 

Built in primitive words for data stack manipulation

데이타 스택 조작을 위한 기초단어 만들기

가감승제말고도 스택을 만지기 위한 기본 내장워드들이 있다. 

Along with add, subtract, multiply and divide there are other basic builtin words that manipulate the stack as well.

  • DUP 은 스택의 탑을 복제한다 (TOS)
  • SWAP 은 맨위의 두개를 바꿔치기한다
  • DROP 은 TOS 를 뽑아서 버린다t
  • "."  TOS에서 데이타를 팝하고 인쇄
  • "=" 은 두 데이타를 팝해서 비교한 후 같으면 스택의 꼭대기에 1을 올려놓고 아니면 0을  올려놓는다.

이들은 총명한 방법으로 조합될 수 있고 다음에 두 예제를 보자.

These can all be combined in clever ways. Here are two examples.

Forth> # Lets square and print the TOS
Forth> 25 dup * .
625
Forth> # Lets negate the TOS and print it
Forth> 42 0 swap - .
-42
Forth> 

 forth.py 에 있는 기본 런타임 파이선 코드들을 보인다. 데이타 스택은 단순히 "ds"라고 불리는 파이선 리스트이다.   리스트의 "append" 메소드로 아이템을 밀어넣고   "pop" 메소드로 맨위의  아이템을 얻는다. ( 그리고 버린다)  그리고 기본워드는 작은 함수로 두개의 인자가 있다,  우리가 이 인자를 이용할 것은 아니지만 나중에 런타임함수들은 이 인자를 이용할 것이다. 

 
def rAdd (cod,p) : b=ds.pop(); a=ds.pop(); ds.append(a+b)
def rMul (cod,p) : b=ds.pop(); a=ds.pop(); ds.append(a*b)
def rSub (cod,p) : b=ds.pop(); a=ds.pop(); ds.append(a-b)
def rDiv (cod,p) : b=ds.pop(); a=ds.pop(); ds.append(a/b)
def rEq  (cod,p) : b=ds.pop(); a=ds.pop(); ds.append(int(a==b))
def rGt  (cod,p) : b=ds.pop(); a=ds.pop(); ds.append(int(a>b))
def rLt  (cod,p) : b=ds.pop(); a=ds.pop(); ds.append(int(a<b))
def rSwap(cod,p) : a=ds.pop(); b=ds.pop(); ds.append(a); ds.append(b)
def rDup (cod,p) : ds.append(ds[-1])
def rDrop(cod,p) : ds.pop()
def rOver(cod,p) : ds.append(ds[-2])
def rDump(cod,p) : print "ds = ", ds
def rDot (cod,p) : print ds.pop()

이들은 물론 더 효율적으로 구현될 수도 있으나 명료함을 위해 이번에는 이런 방식으로 하자.  그리고 나누기와 빼기의 순서를 눈여겨보자. 그리고 나누기에서 파이선의 / 를 이용하므로 두 인자중의 하나가 float 이면 결과도  같은 형식이라는 것도.  만약 두 인자가 정수라면 정수의 나누기가 이루어진다.

이 함수들의 참조는  "rDict" 의 룩업테이블에서 일어난다.  "+"는 함수 (rAdd) 에 매치되는 식이다. 이 사전의 항목들은 단순명료하다. 


Defining new words

새로운 워드를 정의


새로운 워드 NEGATE를 정의하여 tos 를  원래 값의 음의 값으로 바꿔보자. 모든 워드 정의는 ":"로 시작하요 정의할 단어가 바로 따라온다.  그리고 ";"가 나오기 전까지 뭔가가 줄줄이 붙고 이것이  워드 정의의 몸체다. 그래서 negate를 정의하고 태스트 하고 다음에 같은 일을 sqr에도 해보자




Forth> : negate 0 swap - ;
Forth> 5 negate .
-5
Forth> : sqr dup * ;
Forth> 6 sqr .
36
Forth> 

Compiling Words to Pcode

워드를 PCODE로 컴파일 

컴파일의 첫번째 단계는 문법적파싱이고 포스에서는 아주 간단하다.  "tokenize" 함수가  커멘트를 제거하는데 "#" 로 시작해서 줄의 끝까지 모든 것을 제거한다.  그리고 텍스트를 화이트스페이스 기준으로 워드의 리스트로 분리한다. 이것을 이제 파이선 프롬프트에서 확인하자.


>>> import forth
>>> forth.tokenizeWords("5 6 + .  # this is a comment")
>>> forth.words
['5', '6', '+', '.']
>>> 

만약 컴파일러가 워드를 정의하는 도중이 아니거나 나중에 보듯이 새로운 제어구조를 형성하는 도중이 아니라면 "immediate mode" 라고 부르는 중간 모드에 있다.  한개의 워드가 컴파일되고 되돌아온다. 


>>> forth.compile()
Forth> 5 6 + .
[<function rPush at 0x9bdf5a4>, 5]
>>> forth.compile()
[<function rPush at 0x9bdf5a4>, 6]
>>> forth.compile()
[<function rAdd at 0x9bdf1ec>]
>>> forth.compile()
[<function rDot at 0x9bdf48c>]
>>> forth.words
[]
>>> 

compile 함수를 수행하다보면 자동으로 프롬프트가 나오는 것에 유의하라.

컴파일된 코드가 리스트에 나온다. 숫자는 정수이건 실수형이건 수자를 "rPush"를 통해 데이타 스택으로 들어간다.  "+" 와 "." 도 각각 해당하는 런타임 함수로 컴파일된다. 이제 파이선의 "compile" 함수를 구경하자.


def compile() :
    pcode = []; prompt = "Forth> "
    while 1 :
        word = getWord(prompt)  # get next word
        cAct = cDict.get(word)  # Is there a compile time action ?
        rAct = rDict.get(word)  # Is there a runtime action ?

        if cAct : cAct(pcode)   # run at compile time
        elif rAct :
            if type(rAct) == type([]) :
                pcode.append(rRun)     # Compiled word.
                pcode.append(word)     # for now do dynamic lookup
            else : pcode.append(rAct)  # push builtin for runtime
        else :
            # Number to be pushed onto ds at runtime
            pcode.append(rPush)
            try : pcode.append(int(word))
            except :
                try: pcode.append(float(word))
                except : 
                    pcode[-1] = rRun     # Change rPush to rRun
                    pcode.append(word)   # Assume word will be defined
        if not cStack : return pcode
        prompt = "... "

부분적으로는 애매할 것이다. 기본적으로 우리는 다음 단어를 "getWord" 를 사용해서 가져온다. 입력이 더 필요하면 프롬프트 할 것이다. 이  "compile" 함수는 프롬프트가  "Forth> "  또는 "... "일지를 제어한다. 만약 워드이름이 기본 런타임 동작으로 "rDict" 에 있는 것이라면 그 함수를 부르는 것으로 번역될 것이다. 
만약 워드가 정수나 실수형으로 만들어질수 있는 것이라면 "rPush" (역시 내장형) 로 번역되고 그 다음에 데이터 스택으로 푸시될 실제 숫자가 온다.   immediate mode에서는 단일한 입력 워드가 컴파일되고 리턴된다. 

이제 새로운 단어를 컴파일해보자.


>>> forth.compile()
Forth> : negate 0 swap - ;
[]

아무 pcode도 리턴되지 않았다, 그러나 재미있는 부차적 효과(side effect)가 생겼다.

>>> forth.rDict['negate']
[<function rPush at 0x9fbe5a4>, 0, <function rSwap at 0x9fbe374>, 
 <function rSub at 0x9fbe25c>]
>>> 


이제 새로 들어온 넘은 rDict에 있고 내장함수처럼 쓸 수 있다. 
>>> forth.compile()
Forth> 6 negate
[<function rPush at 0x9fbe5a4>, 6]
>>> forth.compile()
[<function rRun at 0x9fbe56c>, 'negate']
>>> 

이제  위의 "compile" 함수에서  cAct 가 cDict 에 있는지 체크한다. 이는 컴파일 타임 함수를 찾는 것이다. 이 함수들은 컴파일과정을 위한 헬퍼 함수다. ":" 와 ";" 는 모두 컴파일 타임 워드들이다. 이제 이들의 해당 파이선 함수를 보자.


def cColon (pcode) :
    if cStack : fatal(": inside Control stack: %s" % cStack)
    label = getWord()
    cStack.append(("COLON",label))  # flag for following ";"

def cSemi (pcode) :
    if not cStack : fatal("No : for ; to match")
    code,label = cStack.pop()
    if code != "COLON" : fatal(": not balanced with ;")
    rDict[label] = pcode[:]       # Save word definition in rDict
    while pcode : pcode.pop()

이제 cStack에 ":" 로 시작하면서 밀어 널고 나중에 ";"으로 뽑아내야 한다는 것을 보았다.  ":"  워드는 입력으로 부터 라벨을 받고  만약 여의치 않으면 "..."로 프롬프트한다. 이 라벨은  저장되어 ";"워드가 컴파일된 코드와 연결되어 rDict에 하나의 엔트라를  만들도록 한다. 이렇게 되면 코드는 지워진다. 이제 이 기간동안 cStack은 비워져 있지 않다. ":"로 컴파일이 시작되면  ";"에 매치되는 곳까지 진행되어야 한다.  이제 우리는 컴파일러가 "deferred(지연된)" 모드로 들어갔다고 말한다. 

이제 cStack을 같이 사용하고 있는 다른 워드 그룹을 보자 . 이들은 지연된 컴파일을 강제한다. 

So now let's look at other word groups that also use the cStack, forcing deferred compilation.

BEGIN ... UNTIL Control structure

 BEGIN 과 UNTIL 은 반복 루프를 설정한다. UNTIL은 TOS에서 팝을 한다. 만약 0 이라면  제어는 begin 다음으로 돌아간다.  아래에 예제가 있다. 

Thewords set up an iterative loop. UNTIL will pop the TOS and, if it is zero, will return control to the word following BEGIN. Here is an example

>>> import forth
>>> forth.main()
Forth> 5 begin dup . 1 - dup 0 = until
5
4
3
2
1
Forth> 

우리는 5를  스택에 넣는 것으로 시작하여 인쇄한후 1을 빼는 작업을 0 이 될때까지 반복한다.  DUP을 두번 쓴 이유는 카운트 다운 뿐만이 아니라  안쇄하고 0이 되는가를 체크하기 위해서도 필요하다.
BEGIN 과 UNTIL은 모두 컴파일 타임 워드이며 아래에 해당 파이선 함수를 보인다.

def cBegin (pcode) :
    cStack.append(("BEGIN",len(pcode)))  # flag for following UNTIL

def cUntil (pcode) :
    if not cStack : fatal("No BEGIN for UNTIL to match")
    code,slot = cStack.pop()
    if code != "BEGIN" : fatal("UNTIL preceded by %s (not BEGIN)" % code)
    pcode.append(rJz)
    pcode.append(slot)

BEGIN은 아무 코드도 만들지 않는다. 다만 콘트롤 스택의 다음에 올 워드의  주소(len(pcode)) 만 집어넣는다.  그리고 컴파일러를 지연 모드로 만든다.  UNTIL은 매치되는 BEGIN을 체크하고 rJZ call (Jump if Zero) 을 발생시키며 저장된 주소로 돌아간다.  런타임에는 rJz이 TOS를 팝하고 만약 0이면 점프를 행한다. 

다음에 "포스스러운 (Forth-like)" 팩토리얼 계산의 정의가 있다. 이코드는 파일   "fact1.4th"에 저장되어 있어야 한다. 


# fact1.4th

: fact                             #  n --- n!  replace TOS with its factorial
  0 swap                           # place a zero below n
  begin dup 1 - dup  1 = until     # make stack like 0 n ... 4 3 2 1
  begin dump *  over 0 = until     # multiply till see the zero below answer
  swap drop ;                      # delete the zero

중간의 DUMP는 디버깅을 위한 것이다. 돌려보자.

>>> import forth
>>> forth.main()
Forth> @fact1.4th
Forth> 5 fact .
ds =  [0, 5, 4, 3, 2, 1]
ds =  [0, 5, 4, 3, 2]
ds =  [0, 5, 4, 6]
ds =  [0, 5, 24]
120
Forth> 

IF, ELSE, THEN Control Structure


이 제어문의 구조는 

condition IF true-clause THEN

  or

condition IF true-clause ELSE false-clause THEN

만약 어느정도 일본어 문법에 친숙하다면 이 순서가 겁나게 부자연스러운 것은 아니라고 보일 수도 있다. 이들 워드의  컴파일 타임의 도우미들을 구경하자. 
def cIf (pcode) :
    pcode.append(rJz)
    cStack.append(("IF",len(pcode)))  # flag for following Then or Else
    pcode.append(0)                   # slot to be filled in

def cElse (pcode) :
    if not cStack : fatal("No IF for ELSE to match")
    code,slot = cStack.pop()
    if code != "IF" : fatal("ELSE preceded by %s (not IF)" % code)
    pcode.append(rJmp)
    cStack.append(("ELSE",len(pcode)))  # flag for following THEN
    pcode.append(0)                     # slot to be filled in
    pcode[slot] = len(pcode)            # close JZ for IF

def cThen (pcode) :
    if not cStack : fatal("No IF for ELSE for THEN to match")
    code,slot = cStack.pop()
    if code not in ("IF","ELSE") : fatal("THEN preceded by %s (not IF or ELSE)" % code)
    pcode[slot] = len(pcode)             # close JZ for IF or JMP for ELSE

 BEGIN 과 UNTIL과 친밀한 구조로 보여야 한다.  컴파일 타임 코드에서 IF는 만약  1이라면 ELSE로 가는 rJZ 코드를 발생시키고 아니라면 THEN으로 가는 넘을 만든다. ELSE는  IF 를 위한 점프를 완결시키고 그 다음에는 THEN이 완결되면 가야할 곳으로 무조건 점프를 셋업한다. 
 
다음에 두번째 팩토리얼 워드 정의가 있다.  BEGIN과 UNTIL을   쓰는 대신 우리는 재귀를 사용하고 이 주제는  나중에 심도있게 다른다. 그러고 끝점을 설정하기 위한 플랙을 설정하지 않고 IF THEN을 사용했다. 
# fact2.4th  Recursive factorial       # n --- n!

: fact  dup 1 > if                     # if 1 (or 0) just leave on stack
            dup 1 - fact               # next number down - get its factorial
    dump    * then                     # and mult - leavin ans on stack
  ;

다시 DUMP는 동작을 보여주기 위해  의도적으로 넣은 코드다.

Forth> @fact2.4th
Forth> 5 fact .
ds =  [5, 4, 3, 2, 1]
ds =  [5, 4, 3, 2]
ds =  [5, 4, 6]
ds =  [5, 24]
120
Forth> 

Variables, Constants and the Heap 

변수 상수 그리고 힙


이제 우리는 데이타를 데이타 스택의 바깥에 저장해야 하는 시점까지 왔다.  우니는 많은 변수들을 데이타 스택에 아닌 곳에 편하게 저장하기를 원할수도 있으며  데이타를 1차원 또는 다차원의 행렬에 저장하기를 원할지도 모른다. 
포스 시스템은 이러한 목적을 위해 메모리 영역을 따로 만들어 놓았으며  다른 워드를 만들기 위한 내장기능을 갖고 있다. 상당히 깔끔하다. 


우선 이런 내장기능을 살펴보자 . 이번 모델에서 힙은 단순히 20개의 정수이다.  실제와는 조금 다르다. 


heap     = [0]*20      # The data heapheapNext =  0          # Next avail slot in heap

def rCreate (pcode,p) :
    global heapNext, lastCreate
    lastCreate = label = getWord()      # match next word (input) to next heap address
    rDict[label] = [rPush, heapNext]    # when created word is run, pushes its address

def rAllot (cod,p) :
    global heapNext
    heapNext += ds.pop()                # reserve n words for last create

이제 흥미롭게도 ,  rCreate 와 rAllot 은 런타임 워드다.  rCreate가 돌아갈 때  컴파일러는 즉시모드이며  입력에서 다음에 올 워드 (pcode에서가 아니라)
가 정의될 워드다. 정의된 워드의 런타임 작용은 단순히 예약된(reserved) 힙 주소를 데이타 스택에 옮기는 것이다. ALLOT은 실제로 하나 또는 그 이상의 워드를 예약하는 것이며 heapNext를 진전시켜서 나중의 CREATE가 쓸수 있도록 준비하는 것이다. 이제 예제를 보자.  포스 코드를 실행하고 컴파일 하기 위해 forth.main을 사용할 것이다.



>>> import forth
>>> forth.main()
Forth> create v1 1 allot
Forth> create v2 3 allot
Forth> create v3 1 allot
Forth> dump
ds =  []
Forth> v1 v2 v3 dump
ds =  [0, 1, 4]
Forth> 

여기서 우리는  V1, V2,  V3  세개의 워드를 만들었다. 각각은 해당 힙 주소가 있고 실행시에는 이 주소를 푸시한다.  V2와 V3 사이의 "공간 (space)"을 보자.  V2를 만들때 ALLOT이 사용되었기 때문이다. 
그리고 아래에 힙장소들을 사용하는 방법을 보여준다. "@" and "!" 는 힙에 있는 워드들을 꺼내오고 (fetch) 설정한다 ( set ).  


>>> import forth
>>> forth.main()
Forth> create v1 1 allot
Forth> create v2 3 allot
Forth> create v3 1 allot
Forth> ^D
>>> print forth.heapNext, forth.heap
5 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> forth.main()
Forth> 22 v2 !          # set v2[0] = 22
Forth> 23 v2 1 + !      # set v2[1] = 23
Forth> v2 @ .           # print v2[0]
22
Forth> ^D
>>> print forth.heapNext, forth.heap
5 [0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> forth.rDict['v3']  # See definition of v3
[<function rPush at 0x8ba0454>, 4]

이제 2개의 단일 변수  (V1 and V3)  와 3개의 워드를 갖는 V2를 만들었다. 다시 파이선으로 돌아야 우리는 힙이 변경되는 것을 볼 수 있고 다른 변수들의 실시간 정의를 볼 수 있다.
다른 유용한 내장 기능인 "." 도 있다. TOS 에서 팝을 한다음 힙의 다음 자유위치에 푸시한다. 이는 ALLOT을 대신해서 변수를 0으로 초기화하는 대신의 용도로 사용 가능하다. 


>>> forth.main()
Forth> : varzero create 0 , ;
Forth> varzero xyz
Forth> xyz @ .
0


Finally, there is a builtin DOES> that works together with CREATE inside a definition. It takes all following words up to the closing ";" and appends them to the rDict entry for the word just created. First consider this definition and usage of a CONSTANT

Forth> : constant create , ;
Forth> 2009 constant thisYear
Forth> thisYear @ .
2009

That's fine, but there is nothing to prevent you from simply "!"ing thisYear to another value. It's the same as any variable. But if we instead do the following

Forth> : constant create , does> @ ;
Forth> 2009 constant thisYear
Forth> thisYear .
2009
Forth> ^D
>>> forth.rDict['thisyear']
[<function rPush at 0x9865454>, 3, <function rAt at 0x9865534>]
>>> 

then you can see how a call to rAt has been attached to thisYear's runtime. There is no need to use an "@" to retrieve its value and "!" cannot be used to change its value.

With these builtins, it is not difficult to make arrays, including multidimensional ones. We can even make primitive structs (like C) assigning constants for field offsets.

Like C, however, there is not much memory protection. If an array reference is out of bounds, it will simply write into something else. Of course, in this model, this will stay within our heap but in a C adaptation of this code, even that would be lost.

We'll end this section with a final factorial program, this time using variables. The code looks more like a traditional language, albeit in postfix

# fact3.4th

: variable create 1 allot ;            #   ---     create var and init to TOS
  variable m
  variable answer

: fact                                 #  n --- n!  replace TOS with factorial
     m !                               # set m to TOS
  1 answer !                           # set answer = 1
  begin
    answer @ m @ dump * answer !       # set answer = answer * m
    m @ 1 - m !                        # set m = m-1
    m @ 0 = until                      # repeat until m == 0
  answer @                             # return answer
  ;

 15 fact .                             # compute 15! and print

And now, let's run it

Forth> @fact3.4th
ds =  [1, 15]
ds =  [15, 14]
ds =  [210, 13]
ds =  [2730, 12]
ds =  [32760, 11]
ds =  [360360, 10]
ds =  [3603600, 9]
ds =  [32432400, 8]
ds =  [259459200, 7]
ds =  [1816214400, 6]
ds =  [10897286400L, 5]
ds =  [54486432000L, 4]
ds =  [217945728000L, 3]
ds =  [653837184000L, 2]
ds =  [1307674368000L, 1]
1307674368000
Forth> 

Since our model is built in Python, we inherit its nice automatic switch to long integers.

Notice that the variables "m" and "answer" are defined outside the "fact" definition. We don't have private local variables within a definition.

Other Issues

As mentioned earlier, Forth can be very efficient both with memory and CPU time. Consider the following bits of PDP-11 assembler code. It is a recreation of a little bit of our first Forth expression "5 6 +".

stack:
         ...       ;      more space here for the stack to grow
         6         ; <--- r4 stack pointer (stack is upside down)
         5
ds:      0         ; base of stack         
         
         rPush     ; <--- r3 tracks the pcode thread 
         5
         rPush
         6
         rAdd
         .
         .         ; thread continues ...
         
         
rPush:   mov    (r3)+, -(r4)       ; ds.append[pcode[p]]; p += 1
         jmp   @(r3)+              ; return to thread
         
rAdd:    add    (r4)+, (r4)        ; tmp=ds.pop(); ds[-1] += tmp
         jmp   @(r3)+              ; return to thread
         
rDup:    mov    (r4),-(r4)         ; ds.append(ds[-1])
         jmp   @(r3)+              ; return to thread

This should look somewhat familiar from the assembler model in the previous chapter. We have the data stack on top, a bit of "threaded" code in the middle and 3 builtins. The threaded code (the name will be obvious in a minute) is essentially the same as our "pcode" array in the Python model. Machine register r3 is our "p" indexe to the next word in the pcode. The program counter, PC jumps between the builtins. The instruction "jmp @(r3)+" loads the program counter with the memory word indexed by r3 and then increments r3 to point at the next word. The program execution weaves through the threaded code out of one builtin (rPush) and into the next (rAdd). Register r4 is the ds index. On the PDP-11 the stack grew downward and lower machine addresses were actually higher on the stack. The instruction "mov (r3)+,-(r4)" pushes the next word in the thread (5 say) onto the data stack, first decrementing r4 to the next higher stack location.

Now if we were writing this in assembler we might do the following

        mov  #5, -(r4)        ; push 5 onto stack
        mov  #6, -(r4)        ; push 6 onto stack
        add  (r4)+,(r4)       ; add in stack

But if we add up the memory use and execution cycles, only the "jmp @(r3)+" instructions, the needle, if you will, that sews the code together are missing. These jumps constitute very little overhead.

In the early 1980's I developed a process control system for a newspaper mailroom that tracked bundles of newspapers on conveyor belts. Each bundle had a specific chute designation which would deliver it to a truck being loaded. We put together a small Forth system in less than 1000 lines of assembler. This system was concurrent having a special word so that one thread could yield control of the cpu to another. Like Forth itself, this application was divided into tiny pieces sewn back together. One pcode thread for example monitored keyboard input from one of the terminals. Another output messages to all the screens which included echoing input from either keyboard. Still other threads would handle a sensor on a belt or update a light display. Each thread had its own data stack but they shared variables on the heap and of course word definitions. There were no locking problems because the threads themselves yielded control only when safe to do so. Such a system was possible because throughput was only at human speed.

One final point. We used recursion in the second factorial example. This is unusual in Forth. Normally a word must be defined before being used in another definition. But in our compile function the last "except" clause allows us to build an rRun to an undefined word with the assumption that it will be defined before it is actually used. But this in turn leads to another issue. Our rRun runs a word dynamically, that is, it looks up the definition in rDict just before running it. Most Forths would not do that. It's expensive when the computation for most words is usually so small. So rather than following a pcode entry "rRun" with the name of a word, it would be reference to the words pcode and the dictionary lookup is avoided. This also has an interesting implication. If you redefine a word that has been used in the definition of other words, those other words do not change their behaviour. They are still locked to the old code. The programmer might well find this unexpected.





저작자 표시
신고
Trackback 1 Comment 1
2015.01.06 11:32

스택 머신

예전에 나는 sicp를 설명하면서 레지스터머신을 설명한 적이 있다. 

그런데 레지스터 머신과 항상 경쟁하는 스택머신의 중요성은 그때에는 간과했다. 


FORTH 언어의 생태계는 스택 머신 위에서 움직인다,

lisp의 반대의 표기법을 갖는 포스는 가상 머신의 방식도 반대 

위키 백과에는 스택 머신을 이렇게 설명한다 .


http://en.wikipedia.org/wiki/Stack_machine


쿠프만의 책은 당시나 지금이나 중요하다 


http://users.ece.cmu.edu/~koopman/stack_computers/contents.html


저작자 표시
신고
Trackback 1 Comment 0
2014.12.21 23:38

pisc 분석

당분간 이 프로세서 분석은 알파와 베타 중간 상태다. 

현재 버전 0.0 (2014.12.21)




pisc 분석

이 프로세서는 참으로 특별하다.
너무 간단하게 만들다보니 동작도 이상하고 결함도 많다.
자세한 내요은 번역부분을 읽어라.

명령어는 매번 클럭시마다 사용된다.
매 클럭마다 한번은 fetch라는 명령어가 사용되고 한번은 execute가 시행된다.

원본에는 이렇게 나온다.
a) 레지스터중 하나가 어드레스 버스로 나가고 ALU 의 A 입력이 된다;
b1) 다른 레지스터는 데이터버스로 출력하고 ALU의 B 입력이 되거나; 또는
b2) 메모리로ㅜ터의 데이터가 다른 레지스터의 입력이 된다;
c) ALU의 출력이 A (그리고 아마도 B)에 적용되고 데이터는 첫 번째(address)레지스터에 저장된다,

a) one register is output to the Address bus and the ALU's A input;
b1) another register may be output to the Data bus and the ALU's B input; or
b2) data from memory may be input to another register;
c) an ALU function is applied to A (and perhaps B) and the result is stored in the first (address) register.


 

조건은 다음과 같다.

인스트럭션 레지스터는 외부에 따로 존재하는 것으로 회로도 page2에 74298을 이용하여 구현했다. (Quad 2-line to 1-line multiplexers with storage)

클럭의 하강 에지에 A 또는 B 선택을 한다.

일단 클럭의 상승에지에 clock의 반전입력이 들어가므로 클럭의 상승에지에 D 버스를 캡처하거나 미리 정해진 하드와이어드 코드를 캡처해서 출력한다.

미리 정해진 값은 10 111 111 1 111 00000이다.

그 값은 다음과 같다.
 
사진 참조


이 값의 의미는 다음과 같다.

메모리를 읽어서 r7에 저장하고 데이터라인에도 r7을 내보낸다. D line에는 메모리를 읽은 값이 들어간다. 결국 R7에 쓴다. CY=11로 0이 선택된다. 이 값은 래치된다.

이런 목적으로 74172 dual port ram이 사용되었다, 74182는 2비트 램이다.

74181은 00000이 선택되면 동작은 캐리가 0 인 경우 a+1이 일어난다. a 입력은 A 버스에 연결되어 있다, 결과는 종종 어드레스값에 1을 더하게 된다.


mrd는 rec로 바로 연결된다. 기묘하지만 메모리를 읽지 않는 상태가 듀얼포트를 읽는 것이고 mrd가 High인 경우는 clock의 반전 입력과 nand를 거처 mrd\ 가 된다..
(mwr도 같은 방법) 이것이 IR 이라는 게 신기할 다름이다.

wec\는 mrd와 fetch\의 nand다. 그러니까 메모리는 읽는 상태이고 fetch가 아닌 exec 상태이다. 메모리를 읽지 않으면 쓰여지지 않는거다.

  


저작자 표시
신고
Trackback 0 Comment 0
2014.12.17 17:01

PISC 마이크로 프로세서

PISC 마이크로 프로세서


이제부터 다시 IT 에 관한 글을 쓰기로 했다.

긴 주제인데 일단 근원적 코딩에 관한 글들을 적어보기로 한다. 

아마 1/3은 번역이고 1/3은 내가 쓰는 것 1/3은 제작 기사다.

물질(atom)과 정보 (bit)에 대한 요리책이기도 하다.



오늘은 PISC이라는 프로세서를 번역해 보기로 한다.

프로세서를 직접 만들어보는 사람치고 이 글을 안읽은 사람은 없다. 

무척 중요한 글이다. 

저자를 잠깐 분석해보면 50년대에 태어난 분 같고

막강한 실전형으로 지금도 개발자로 살며  forth  와 태고적 임베디드에 무척 강한 분이다.

원본의 위치는 http://www.bradrodriguez.com/papers/piscedu2.htm 에 있다.


나도 이 회로를 보고 느낀 당혹감은 엄청났다. 

그래서 실제로 만들어 보려고 한다.  회로분석은 물론 실행한다. 


일단 번역을 해보자.

현재 0.7 버전이다. (2015.1.5) - 초벌 번역이 끝났다.

현재 0.2 버전이다. (12.18)

아직까지는 버전 0.1이다. 시작만 했다. (2014.12.17)


아키텍처 탐구를 위한 초단순 TTL 프로세서

A Minimal TTL Processor for Architecture Exploration

 

Bradford J. Rodriguez

McMaster University

 

저작권 표시다 그냥 넘어가자

From the Proceedings of the 1994 ACM Symposium on Applied Computing. Copyright (c) 1994, Association for Computing Machinery. Permission to copy without fee all or part of this material is granted provided that the copies are not made or distributed for direct commercial advantage, the ACM copyright notice and the title of the publication and its date appear, and notice is given that copying is by permission of the Association for Computing Machinery. To copy otherwise, or to republish, requires a fee and/or specific permission.

 

 

키워드

Keywords: CPU, processors, architecture, education

 

현재 컴퓨터 아키텍처를 손에 익히도록 배우려면 VLSI설계도구가 있을때만 가능하다. PISCTTL 논리소자로 만들어 CPU의 하드웨어와 마이크로코드의 동작을 보여준다. 효과적인 stack machine은 쉽게 구현할 수 있고 간단한 하드웨어 변경으로 인터럽트, 메모리 세그멘테이션 , 마이크로 시퀜서 , 병렬성과 파이프 라이닝을 구현할 수 있다. PISC 보드는 경제적이고 유효한 프로세서 디자인의 도구이다.

 

소개

 

컴퓨터 아키텍처연구는 종종 추상적이며 종이위의 연습이다. 학생들은 싱글칩 마이크로프로세서의 내부 동작도 알아낼 수 없고 학생들이 검토할 수 있는 개별 로직으로 만든 기계들은 거의 없다. VLSI설계 도구를 가진 대학만이 프로세의 설계와 구현에 대해 직접 만져보는 체험을 시킬 수 있다. 더 불쌍한 기관들은 학생들에게 책으로 배우기만을 제공할 수 있다.

 

 

 

Pathetic Instruction Set Computer는 개별로직으로 만든 모델 프로세서이다, 하드와이어드와 마이크로프램 CPU의 원리를 보여준다. 22개의 표준적 TTL (memory제외)만을 사용하며, 학생이 만들고 이해하는 수준내에 있다. 작성가능한 마이크로프로그램은 저렴한 EPROM RAM을 사용한다. 완전히 정적동작이 가능해서 관찰을 위해 느린 클록 속도나 수동으로 싱글스텝으로 돌릴 수 있다. 간단한 확장으로 인터럽트 , 명령어와 데이터의 데이터공간의 분리 , 병렬처리와 파이프라이닝을 만들어 볼 수 있다.

 

The Basic Processor

기본 프로세서

 

 

PISC-1a processor (Fig. 1)는 최소의 논리회로로 최대의 기능성을 갖도록 디자인되었다,. 16개의 내부 제어 신호만을 가지며 인코드되지 않은 마이크로인스트럭션은 16비트 길이이다.

 

ALU4개의 74181로 만들고 더하기 빼기 증가와 감소등의 숫자연산에다가 모든 논리적 연산이 가능하다. 프로그램되는 상태래치와 캐리입력에 대한 4 가지 경우의 멀티플렉서가 ALU 로직을 완성한다. 8개의 741728개의 16비트 레지스터로 포트를 3개 갖는 레지스터 파일이다. 이 파일은 바로 한 레지스터에 대한 쓰기 ("A") , 두 번째는 ("B")를 읽은 것이거나 세 번째로 ("C")에 적을 수 있다. 한번의 클럭 사이클에 다음과 같은 일들이 일어난다:

a) 레지스터중 하나가 어드레스 버스로 나가고 ALU A 입력이 된다;

b1) 다른 레지스터는 데이터버스로 출력하고 ALUB 입력이 되거나; 또는

b2) 메모리로터의 데이터가 다른 레지스터의 입력이 된다;

c) ALU의 출력이 A (그리고 아마도 B)에 적용되고 데이터는 첫 번째(address)레지스터에 저장된다,

 

 

 

a) one register is output to the Address bus and the ALU's A input;

b1) another register may be output to the Data bus and the ALU's B input; or

b2) data from memory may be input to another register;

c) an ALU function is applied to A (and perhaps B) and the result is stored in the first (address) register.


달리 지정된 마이크로시퀀서는 없다. 그 기능은 ALU와 레지스터 파일에서 이루어진다. 모든 마이크로인스트럭션은 두 개의 동작상태(phase)fetchexecute이다. fetch 상태에서는 (illustrated in Fig. 1) 하드와이어드된 가짜 명령어(pseudo-instruction)가 실행된다.

 

a) R7의 출력 (the program counter)이 어드레스버스와 ALUA 입력으로 간다.

b) 데이타를 메모리에서 읽어온다

c) A+1의 기능을 적용하고 결과를 다시 R7 에 적는다. (클럭의 하강에지에서)

 

a) output R7 (the program counter) to the Address bus and the ALU's A input;

b) read data from memory;

c) apply the function A+1 and store the result back in R7 (at the trailing edge of the clock).


PISC as a Hardwired CPU

하드와이어드 CPU PISC

 

PISC는 일반적인 CPU가 하드와이어드 제어 유닛을 가진 경우로 볼수 있다. 레지스터-레지스턴 아키텍처 [3] 그리고 PDP-11의 잔재가 남은 별로 안좋은 명령어셋을 가지고 있다.

 

ALU 조작은 하나 또는 두 개의 연산자로 레지스터와 레지스터 이동, 더하기 , 캐리를 포함한 더하기, 빼기 , 보로우를 가진 빼기 , 증가 , 감소 그리고 좌측 쉬프트와 모든 논리연산이 가능하다, 곱하기 나누기와 우측 쉬프는 없다.

 

메모리 조작은 로드와 스토어 그리고 세가지 어드레싱 모드가 있다: 레지스터 인다이렉트 , 레지스터 인다이렉트 후 증가 또는 감소 . R7에 대해 post increment 어드레싱은 immidaite 어드레싱이 된다. (Postincrement addressing on R7 (the program counter) yields immediate addressing.)

 

컨트롤 명령은 프로그램 카운데에 대한 ALU 조작이다. 레지스터 인다이렉트 점프 (상대 또는 절대)와 조건부 skip은 단 인스트럭션에 만들 수있다. 다른 점프와 브랜치 그리고 서브루틴 콜/리터은 명확하게 코드되어야 한다.

 

 

PISC as a Microprogrammed CPU

 

PISC 명령어는 물리적 제어 신호를 일으키고 따라서 어떤사람은 PISC을 일종의 마이크로프로그램된 CPU로 볼수도 있다. 기본적인 PISC는 흔한 기계를 비효율적으로 구현한 것이다. 왜냐하면 마이크로인스트럭션의 필들들을 분리하고 디코드하는 논리회로가 결여되어 있다. 그러나 PISC은 오퍼랜드가 없는 아키텍처인 스택머신보다 낫다. 가장 빠른 구현은 쓰레드된 코드[1] 16비트 마크로인스트럭션을 사용한다.

 

MRD PC,IP,A+1 ; mem(IP)->PC, IP+1->IP

레지스터 하나는 마크로 인스트럭션의 포인터에 할당되었고 다른 하나 또는 두 개의 다른 레지스터는 스택포인터처럼 사용된다. 인다이렉트 스레드 코드를 사용하는 하나의 마이크로인스트럭숀을 인터프리터에 더하면 약간의 유연성을 증가할 수 있다. [2]

 

논리적으로는 마이크로프로그램의 저장은 마크로프로그램 메모리로부터 분리되어야 한다. 그러나 통합된 마크로 - 와 마이크로 - 프로그램 저장은 프로그래머가 마이크로코드를 작성하고 새로운 마크로 인스트럭션을 더하게 되는데 이것은 가치있는 교육적 도구다. 스택머신에서 확장가능한 명령어 셋 (extensible instruction set)FORTH 프로그래밍언어에서 영향력이 있었고 이 개념은 다른 FORTH 전용 프로세서들에서 예견되었던 것들이다. [4]


너무 확연한 결함들

Glaring Deficiencies

 

PISC의 많은 결함들은 잠시만 사용해도 확실하다. 다음과 같다:

 

 

a) no conditional branch microinstruction -- an important need [6];

b) no provision for literal values in the microinstruction;

c) no ALU logic for multiply, divide, and right shift;

d) no logic for decoding of macroinstructions;

e) no provision for interrupts;

f) sparse coding of the ALU function select; and

g) two clocks required per microinstruction.

 

PISC이 교육적으로 가치있는 도구라고 이야기할수도 있다. 왜냐면 이런 결함들이 있고 여러 가지의 잠재적 해답이 있다는 것이 분명하기 때문이더. 어떤 결함들은 논리회로의 많은 추가가 없거나 마이크로인스트럭션의 확장이 없으면 고쳐지지 않는다, 그러나 상당수의 개선은 사소한 편이다.


ALU 연산 디코드

ALU Operation Decoding

 

16비트 마이크로 인스트럭션중 ( 캐리 입력 선택을 포함) 7비트는 ALU 기능의 선택에 사용된다. 그러나 128 코드중의 32개 미만이 쓸모가 있다. 나노코드 메모리 "nanocode" memory [3]나 논리조합 회로등을 사용하면 7비트에서 5비트로 ALU 기능을 줄일 수 있다.

 

다른 방법은 사용하지 않는 코드를 보조적인 제어 신호로 디코드하는 것이다. 예를들어 캐리 입력 선택 (IR6:5)은 로직연산(IR4=1)에서는 "don't-care" 가 된다, 그래서 64개의 로직연산 코드중에 48개는 다른 용도로 사용할 수 있다. 74138 하나로 8개의 추가 제어 신호를 제공할 수 있다. 이를테면 인터럽트의 가능/불가능 신호같은 거이다. 추가적인 논리 회로는 만약 원하는 경우는 ALU 출력을 레지스터에 쓰게하거나 쓰지 못하게 할 수도 있다


Conditional ALU Operations

간단한 조건부 마이크로인스트럭션이 ALU 기능을 캐리의 상태에 따라 바꾼다. 두가지의 변형이 유용할 것이다:

a) if carry set, change ALU operation from "A" to "B" (conditional jump)

b) if carry set, change ALU operation from "A" to "A+B" (conditional branch)

사용되지 않는 않은 ALU 기능이 이런 연산에 디코드 될 수 있고 적당한 논리회로가 ALU 기능을 바꾸어 입력을 선택하게 할 수 있다. 그러나 이런 일은 CPU의 결정적인 타이밍 과정을 지연시킨다.


Interrupts

인터럽트

 

두종류의 인터텁트가 PISC에 쉽게 더해질 수 있다. 마이크로인터럽트는 인터럽트를 셋하는 플립플롭을 갖게하여 구현할 수 있고, 프로그램그램 카운터가 R7 dl 아니라 R6에서 가짜 인스턱션을 가져오도록 하면 된다. R6은 인터럽트 서비스레지스터로 전용되어야 하고 플립플롭을 리셋하는 제어 시그널이 더해져야 한다. (RCA 1802 가 비슷한 인터럽트 방법을 사용했다.)

 

마크로인터럽가 마이크로인터프리터에 알려지는 것은 조건부 스킵을 첨가하고 마이크로 인터프리터에 인터럽트 서비스 루틴을 첨가하면 가능하다. 인터럽트 입력이 캐리입력 멀티플렉서에 연결되고 거의 쓰이지 않는 A=B 입력을 대체하면 된다. 인터프리터는 1 마이크로인스트럭션만큼 느려진다.

 

어느경우에든 레지스터와 상태래치는 마이크로코드에 의해 저장되고 복구되어야 한다. 인터럽트입력을 불가능하게하는 논리회로가 있는 것이 바람직하다.


다중메모리 공간

Multiple Memory Spaces

 

PDP-11 같은 많은 프로세서들은 명령어공간과 데이터 공간의 분리를 하고 있다. PISC의 어드레스 레지스터가 선택가능하고 R7이 프로그램 카운터이기 때문에 세 개의 NAND게이트는 명령공간의 지정이 가능한 신호를 만들어 낼 수 있다, 이 신호는 이미디어트 어드레스 모드에서 제대로 지정될 수 있다.

 

메모리 세그멘트의 구분이 더 이루어지는 것은 마크로 머신의 레지스터 지정에 좌우된다. 2-to-4 디코더는 마이코로 코드와 마크로코드 그리고 데이터스페이스를 threaded stack machine에서 확인가능하게 만들 수 있다.(이것은 80x86에서 제안할 만한 내용이다.)

Further segmentation of the memory space depends upon the register assignment for the macro machine. One 2-to-4 decoder can identify microcode, macrocode, stack, and data spaces in the threaded stack machine. (This is suggestive of the 80x86.)


Parallelism

병렬성

 

만약 마이크로코드 메모리가 주 메모리로부터 분리되면 fetch execcute 페이즈는 병행적으로 일어날 수 있고 각 마이크로 인스트럭션은 하나의 클럭 사이클에 실행될 수 있다. (그림 2)

 

12비트 (16비트도 가능) 카운터가 원시적인 마이크로시퀜서의 역할을 한다. 이 작업은 ALU를 시퀀서의 역할에서 풀어놔서 가짜명령어를 fetch하는 필요성을 없앤다. 각 클럭 사이클은 마이크로프로그램 ROM에서 마이크로인스트럭션을 fetch 한다.





ALU나 데이터 버스에서 카운터로 로딩하는 것으로 절대점프는 여전히 가능하다. 그러나 프로그램 카운터에 ALU 조작을 하는 것은 이제 안된다. 그래서 상대 브랜치나 조건부 스킵이다 즉치 어드레스(immediate addressing ) 력은 없어진다. 마이크로 인터럽트도 상실되고 마크로 인터럽트도 실제적으로 쓸모가 없어진다.

 

각 마이크로 인스트럭션이 매 클럭 사이클마다 fetch 된후 실행되므로 (Fig. 2) 점프 명령어는 한 클럭 사이클 딜레이를 가지게 되고 점프 다음에 오는 명령어들은 언제나 실행된다. 이것은 대부분의 마이크로 프로그램된 기계들이나 파이프라인을 갖는 일부 RISC 머신에서 보는 지연된 브랜치 (delayed branch)"이다.

 

이런 설정에서 메인메모리 억세스는 한 클럭 사이클에 완료될 필요가 없다. 클럭속도의 한정요소는 ALU 경로와 마이크로 인스트럭션 ROM이다. 선행적인 조사에서 메모리 참조에 두 클럭 사이클을 사용한다면 메모리 클럭을 두배로 할 수 있다는 것을 알 수 있다.


로드/스토어 (RISC 비슷한) 동작

Load/Store (RISC-like) Operation

더 변형을 하여(Fig. 3) 마이크로코드와 마크로코드 메모리를 재통합한다. ALU 동작 기간에 어드레스 버퍼는 불능이 되고 fetch 와 execution은 동시에 일어난다. 그러나 메모리의 로드와 스토어 기산에 PC의 출력은 트라이스테이트 상태가 되고 어드레스 버퍼는 동작상태가 된다. 그러면 ALU가 메인메모리(PROM' and RAM')의 번지 지정을 할 수 있게 된다. 메모리 접근이 완료된 다음에 더미 명령어가 실행되고 PC는 다음 명령을 페치한다.



이런 설정에서 pisc은 로드/스토어 아키텍처로 볼 수 있다.[3] RISC 머신처럼 모든 명령어는 한 클럭 사이클에 실행된다. 예외는 메모리 참조로 2 클럭을 필요로 한다.

만약 어드레스 버퍼가 양방향이면 PC는 ALU로 경로를 잡을 수 있다. 상대브랜치 , 조건부 스킵 , immediate addressing 은 다시 사용할 수 있게 복구된다.

"변경가능한 PISC"

The "Mutable PISC"

학생들에게 “한봉지의 부속”과 와이어 랩 도구를 쥐어주고 과제로 PISC을 만들라는 것은 조금 불합리할지도 모른다. 학생들은 더 좋아하지만 실험하는 사람들에게는 덜 끌리는 방법은기본 PISC 과 간단한 개선사항을 담은 PCB를 제공하는 것이다. 이것은 PISC-2 (Fig. 3)의 비전이다

PISC-2는 Am29705 register file을 구하기도 어려운 74172 대신 사용하고 16비트의 데이터 래치와 제어신호가 더 필요하게 된다. 마이크로인스트럭션을 더 늘리기보다 최소한의 기능을 디코드하는 로직이 더해질 것이다.

부품을 주의깊게 더하고 빼어 PISC-2 는PISC-1 (two-clock instructions)으로 설정될 수 있고 개별명령의 microprogram machine이나 load/store machine으로 설정할 수 있다. “통합메모리("unified memory)" 에서의 프로그램 개발은 키보드와 디스플레이로 할 수도 있고 보드안의 모니터 프로그램을 사용하여 RS-232 시리얼 포트로 할수도 있겠다.



결론

Conclusions

 

PISC 의 교욱적인 단점이라면 통상적(1- or 2-operand)” 마크로머신의 극악한(abysmal) 구현일 것이다. 이는 PISC의 원래의 미션의 귀결이기도 하다: 스택 프로세서로 최소한의 표준 TTL 논리회로(2100 게이트 )를 사용하는 것이다. 그러나 PISC-1은 성능이 반드시 복잡성을 의미하지는 않는다는 것을 극명하게 배우게 한다. 5MHz PISC-1a 5 MHz 8086에 비교해보자 (여기서 숫자는 200ns 클럭수이다 ):

 

 

primitivePISC8086
NEXT423
EXECUTE419
DROP629
EXIT639
BRANCH836
DUP846
@1052
LIT1046
R>1050
R@1044
>R1051
!1053
ENTER1049
OVER1250
AND1253
0<1447
SWAP1261
?BRANCH1651/56
UM+1869

 


 

PISC과 정말 비슷한 QS2VLSI 설계과정에 사용된 적이 있다. [5] PISC은 표준 TTL로 구성할 수 있다는 장점이 있다: 그래서 가난한 학교나 학생들도 사용할 수 있다.

 

참고문헌

References

 

1. Bell, James R., "Threaded Code," Communications of the ACM, Vol. 16 No. 6 (June 1973), pp. 370-372.

 

2. Dewar, Robert B. K., "Indirect Threaded Code," Communications of the ACM, Vol. 18 No. 6 (June 1975), pp. 330-331.

 

3. Hennessy, John L. and Patterson, David A., Computer Architecture: A Quantitative Approach, Morgan Kaufmann Publishers, San Mateo, CA (1990).

 

4. Koopman, Philip J., Stack Computers: the new wave, Ellis Horwood Ltd., Chichester, England (1989).

 

5. Rible, John, "QS2: RISCing it all," Proceedings of the 1991 FORML Conference, Forth Interest Group, Oakland, CA (1991), pp. 156-159.

 

6. Stallings, William, Computer Organization and Architecture, Macmillan Publishing Co., New York (1987).


Schematic Diagram

The schematic diagram of the PISC-1a is available if you have Adobe Acrobat or another .PDF reader. Thanks to Derry Bryson for converting the schematics to PDF files.

저작자 표시
신고
Trackback 3 Comment 0
2014.09.06 14:33

펌)머피의 법칙 책중에서 110개 정도 요약한 부분



머피의 법칙 책에서 누군가 요약한 것이다.

재미난 일상 생활의 법칙 110가지!

매우 길기는 한데 많은 부분은 사실이다.

(나는 32번의 힉돈의 법칙을 보고 뒤로 넘어가는 줄 알았는데..)



1>머피의 법칙 
잘못될 가능성이 있는 것은 반드시 잘못된다.

2>검퍼슨의 법칙 
일어나지 말았으면 하는 일일수록 잘 일어난다.

3>질레트의 이사 법칙 
지난 이사 때 없어진 것은 이번 이사때 나타난다.

4>프랭크의 전화 불가사의 법칙 
가. 펜이 있으면 메모지가 없다. 
나. 메모지가 있으면 펜이 없다. 다. 둘 다 있으면 적을 메시지가 없다.&

5>마퀘트의 일요목수 법칙 
1.찾지 못한 도구는 새 것을 사자마자 눈에 보인다. 
2. 필요한 도구는 손이 닿지 않는 곳에 있다.

6>코박의 수수께끼 법칙 
전화번호를 잘못 눌렀을 때 통화중인 경우는 없다.

7>쇼핑백의 법칙 
집에 가는 길에 먹으려고 생각한 초콜릿은 쇼핑백의 맨 밑바닥에 있다.

8>홀로위츠의 법칙 
라디오를 틀면 언제나 가장 좋아하는곡은 맨 마지막 부분이 흘러 나온다.

9>마인스하트의 법칙 
타인의 행동이 평가 대상이 되었을 때 마음속으로 좋은 인상을 심어주면 꼭 실수를 한다.

10>아일스의 법칙 
더 쉬운 방법은 반드시 있기 마련이다.

11>치스홀름의 법칙 
어떤 일이 순조로울 때는 반드시 무엇인가가 잘못되고 있는 증거다.

12>스코트의 제1법칙 
아무리 잘못된 것도 옳게 보이는 수가 있다.

13>스코트의 제2법칙 
잘못되었다고 해서 고치고 나면 본래의 것이 옳았다는 것을 깨닫게 된다.

14>소드의 법칙 
무언가 해보려고 하면 뜻하지 않은 것이 개입하여 훼방을 놓는다.
그럼에도 불구하고 때로 무슨 일이 이루어지는 것은 훼방을 놓는 그것도 역시 또 다른 훼방을 받기 때문이다.

15>아리스토텔레스의 법칙 
사람들은 불가능해 보이는 가능성보다 가능해 보이는 불가능성을 더 선호한다.

16>루딘의 법칙 
위기에 몰리면 사람들은 대부분 최악을 선택한다.

17>런스포드의 과학적 탐구법칙 
복잡한 해답에는 반드시 간단한 설명만 따른다.

18>퍼더의 법칙 
시작이 좋으면 끝이 나쁘다. 
시작이 나쁘면 끝은 더욱 나쁘다.

19>타일자크의 확률의 법칙 
우연한 일일수록 떼지어 생긴다.

20>자이머지의 시스템 역학의 법칙 
일단 지렁이 깡통을 따면 그 지렁이들을 다시 집어넣는데는 더 큰 깡통이 필요하다.

21>업적후퇴의 법칙 
작년은 항상 좋은 해였다.

22>입조심 법칙 
무엇인가에 대해서 말하면 좋은 것은 가 버리고 나쁜 것은 나타난다.

23>클립스타인의 법칙 
1. 특허를 출원하면 같은 것이 1주일 전에 출원되어 있다. 
2. 어떤 프로젝트에 N개의 부품이 필요할 때 창고에 남아 있는 재고는 n-1개이다. 
3. 고장은 최종점검이 끝난 뒤에 생긴다.

24>머라이언의 법칙 
찾지 않으면 반드시 발견된다.

25>얼간이 법칙 
찾는 물건은 항상 마지막에 찾아보는 장소에서 발견된다.

26>얼간이 법칙에 대한 블로크의 반론& 
찾는 물건은 항상 맨 처음 찾아보는 장소에 있는데도 처음에 찾을 때에는 발견하지 못한다.

27>질레트의 전화역학의 법칙 
계속해서 기다리던 전화는 방문을 나서는 순간에 걸려온다.

28>월터의 법칙 
짬이 있으면 돈이 없다. 돈이 있으면 짬이 없다.

29>머피의 법칙의 확장 
계속해서 무엇인가가 잘못될 때에는 최악의 과정을 밟아가며 잘못되어 간다.

30>더카르메의 법칙 
절호의 기회는 최악의 타이밍에 찾아온다.

31>듀드의 2원성 법칙 
두가지 사건을 예상할 수 있는 경우 보다 좋지 않은 쪽이 발생한다.

32>힉돈의 법칙 
뛰어난 판단력은 쓰라린 경험에서 생긴다. 
그러나 그 경험은 형편없는 판단력에서 생긴다.

33>패로우지의 법칙 
시작이 나쁘면 문제는 지수함수적으로 증가한다.

34>제닝의 법칙 
빵의 버터를 바른 쪽 면이 바닥을 향해 떨어질 확률은 카페트의 가격에 비례한다.

35>풀턴의 중력법칙 
깨지기 쉬운 것이 떨어질때 공중에서 잡으려고 하면 가만히 있을 때보다 손해가 더 크다.

36>바러크의 법칙 
망치를 든 사람에게는 모든 것이 못으로 보인다.

37>기막힌 착상의 법칙 
한 사람이 기막힌 해결방법을 생각했을 때는 다른 사람이 이미 문제를 막 해결했을 때이다.

38>지오야의 법칙 
비전문가일수록 자신의 의견을 피력하고 싶어한다.

39>에이그너의 법칙 
아랫사람이 아무리 훌륭하게 일을 끝내더라도 윗사람은 그 결과에 손을 대려고 한다.

40>조의 법칙 
선물공세를 펴서 겨우 연줄을 잡은 사람은 다음 인사이동때 가장 먼저 잘리게 된다.

41>승진에 대한 폭스의 법칙 
자신을 승진시킨 것이야말로 다른 한편으로는 자신의 목을 위협한다.

42>1급부하의 법칙 
상사보다 자신이 더 유능하다는 사실을 절대로 상사가 깨닫게 해서는 안된다.

43>피터의 법칙 
매우 탁월한 인물은 무능한 인물보다도 더 혐오스럽다.

44>존즈의 법칙 
일이 잘못된 경우에도 웃을 수 있는 사람은 그 책임을 전가할 수 있는 다른 사람을 이미 생각 
하고 있다.

45>올드와칸의 법칙 
회의의 효율성은 참가자수와 토의시간에 반비례한다.

46> 
샤나한의 법칙 
회의시간의 길이는 참가자수의 제곱이 된다.

47> 
판스톡의 논쟁법칙 
논쟁할 만한 가치가 있는 문제는 기피할 만한 가치도 있다.

48> 
비즈니스 회의의 제1법칙 
필기중에 연필심이 부러질 확률은 필기내용의 중요성에 비례한다.

49> 
비즈니스 회의의 제2법칙 
한 이름의 철자를 2가지로 생각할 수 있는 경우 틀린쪽을 선택할 가능성이 높다.

50> 
스위플의 발언권 법칙 
목소리가 가장 큰 사람이 발언권을 얻는다.

51> 
리의 법칙 
단체교섭에서는 처음 예상보다 모두 한층 더 집요해진다.

52> 
톰슨의 법칙 
상황이 이상해지면 이상한 녀석들이 전문가가 된다.

53> 
돈 역학의 법칙 
뜻밖의 수입이 생기면 반드시 뜻밖의 지출이 그만큼 생긴다.

54> 
클라크의 법칙 
고명한 노과학자가 "그것은 가능하다"고 말하면 그의 말은 대부분 옳다.
그러나 "그것은 불가능하다"고 말하면 대부분 옳지 않다.

55> 
버스의 사람구분 법칙 
사람은 2가지 부류가 있다. 사람을 2가지 부류로 분류하는 사람과 분류하지 않는 사람이다.

56> 
시걸의 법칙 
시계가 1개 있는 사람은 몇시인지 알 수 있다. 
시계가 2개 있는 사람은 시간을 결코 알 수 없다.

57> 
와일러의 법칙 
직접 행하지 않는 사람의 사전에는 불가능이란 없다.

58> 
매츠의 법칙 
생각하다 지친 시점에서 결론이 나온다.

59> 
메이어의 법칙 
사태를 복잡하게 하는 것은 간단한 일이지만 사태를 간단하게 하는 것은 매우 복잡한 일이다.

60> 
파레토의 법칙 
전체 고객 중 20%가 올린 매상이 총 매상의 80%를 차지한다.

61> 
오브라이언의 법칙 
회계감사에서는 결산서의 맨 아랫자리 금액이 5나 10으로 나누어 떨어지면 어떤 경비든 문제가 된다.

62> 
존의 담보법칙 
융자를 얻기 위해서는 우선 융자가 필요치 않다는 것을 증명해야만 한다.

63> 
메인의 법칙 
큰 잘못은 들키지 않는다.

64> 
프리랜서 디자이너를 위한 법칙 
1. 철야한 일은 적어도 이틀 동안 묵히게 된다. 
2. 바쁜 일들은 모두 마감날이 같다.

65> 
앤터니의 작업장의 법칙 
작업대에서 공구가 떨어지면 가장 성가신 장소로 굴러간다.

66>작업장에서의 법칙 
렌치나 드릴은 필요할 때에는 공구함에 없다.

67>피네이글의 법칙 
1. 실험이 제대로 되어가면 무언가가 이상하다. 
2. 일단 꼬여버린 일은 잘해보려고 애쓰면 애쓸수록 더 꼬이기 마련이다.

68>아인슈타인의 법칙 
수학의 정리는 현실적인 것일수록 불확실하고 확실한 것일수록 현실과 관계가 없다.

69>다윈의 법칙 
자연은 모든 것을 할 수 있다고 대놓고 거짓말을 늘어 놓는다.

70>맥크리스티의 컴퓨터 법칙 
소프트웨어의 버그는 그 소프트웨어가 구식이 되는 시점에서 박멸된다.

71>수강시간표 법칙 
1. 가장 수강하고 싶은 과목의 정원이 N일때 당신의 신청순서는 N+1번째이다. 
2. 수강하고 싶은 학과를 이수하기 위해서 먼저 수강해야 하는 과목은 그 학과의 다음 학기에 
개강된다.

72>기말시험 법칙 
한학기 내내 사용한 포켓 계산기는 기말시험이 한창일 때 건전지가 떨어져버린다.

73>나탈리의 대수학 법칙 
테스트가 끝난 다음에야 문제의 핵심을 파악할 수 있다.

74>사이트의 고등교육 법칙 
졸업에 필요한 마지막 한 과목은 당신의 최종학기에는 개강되지 않는다.

75>존슨의 법칙 
읽지 못한 잡지에 자신이 가장 읽고 싶어한 기사와 특집과 연재물이 실려 있다.

76>관리감독의 법칙 
하루에 딱 한차례 등받이에 몸을 기대고 마음껏 기지개를 켤 때면 사무실을 지나가는 보스가 
눈에 띈다.

77 
드류의 전문가 법칙 
가장 짜게 구는 고객이 가장 말이 많다.

78 
틸리스의 정리정돈의 법칙 
1. 정리정돈해 두지 않으면 필요한 때에도 그것이 어디에 있는지조차 모른다. 
2. 정리정돈해 놓으면 무엇이 어디에 있는지는 알고 있지만 필요할 때가 없다.

79 
줄서기의 원리 
기다리는 시간이 길어지면 길어질수록 엉뚱한 줄에 서 있을 가능성이 높다.

80 
플러그의 법칙 
가장 바쁜 계산대에서 일하고 있는 직원이 가장 굼뜬다.

81 
바일의 줄서기 고등법칙 
긴 줄에서 기다리고 있으면 바로 뒤에 서 있던 사람이 새로 생긴 짧은 줄로 옮겨 간다.

82 
루포하인스키의 법칙 
1. 일찍이 가면 취소된다. 
2. 시간에 맞춰서 가면 기다리게 된다. 
3. 늦으면 그것은 너무 늦은 것이다.

83 
글러크의 법칙 
엘리베이터에 탄 뒤에 버튼을 찾으면 항상 찾는 쪽의 반대쪽에 있다.

84 
위튼의 법칙 
손톱을 깎으면 틀림없이 한시간 뒤에 그 손톱을 사용할 일이 생긴다.

85 
자드라의 
생물역학 법칙 
가려움은 손이 닿기 어려우면 어려울수록 그만큼 더 심하다.

86 
편지 법칙 
그럴듯한 문구가 떠오르는 때는 편지를 봉한 뒤이다.

87 
로저스의 법칙 
스튜디어스의 커피 서비스가 시작되면 여객기는 난기류를 만난다.

88> 
수화물의 기본원리 
수화물의 컨베이어 앞에서 기다리고 있으면 당신의 가방은 다른 수화물 컨베이어벨트에 실려
나온다.

89> 
앵커스의 법칙 
여행을 떠나기 위해서 환전한 이튿날, 환전한 외국화폐는 가치가 떨어진다.

90> 
바이론의 건축업 법칙 
콘크리트를 비비면 비가 온다.

91> 
론의 법칙 
레코드의 흠집은 항상 가장 좋아하는 곡에 생긴다.

92> 
벡하프의 법칙 
미모에 두뇌를 곱하면 상수가 된다.

93> 
텔레스코의 간호법칙 
즉각 달려오는 의사일수록 솜씨는 별볼일 없다.

94> 
브레다의 법칙 
어떤 이벤트에서든 통로에서 가장 먼 좌석을 구입한 자일수록 가장 늦게 입장한다.

95> 
모저의 스포츠관전 법칙 
화끈한 플레이는 득점판에 눈길을 돌릴 때나 핫도그를 사러 갈 때 이루어진다.

96> 
연습의 법칙 
1. 연습은 이론대로 되지 않는다. 
2. 게임은 연습대로 되지 않는다.

97> 
시그타드의 법칙 
자기차례가 되면 규칙이 바뀐다.

98> 
비행기의 법칙 
당신이 타고 있는 비행기가 연착하면 바꾸어 타야 할 비행기는 정시에 이륙한다.

99>
레마의 주차공간 법칙 
빌딩앞에 자리가 없어 다른 곳에 차를 세워두고 오면 빌딩입구 바로 앞에 한 대를 주차시킬 수 있는 공간이 생긴다.

100 
그레이의 버스법칙 
기다리다 지쳐서 걷기 시작하여 목적지까지 거의 다오면 그제야 버스는 그 모습을 드러낸다.

101 
교통정체의 법칙 
정체되고 있는 차선은 당신의 차가 빠져나오자마자 소통되기 시작한다.

101>멜론의 집안일 법칙 
수리공은 기다리고 있으면 하루를 잡아먹지만 5분간만 집을 비우면 그 사이에 수리하러 온다.

102>베스의 보편적 법칙 
1. 전화벨은 문 밖에서 열쇠를 찾고 있을 때 울린다. 
2. 허겁지겁 수화기를 들면 상대가 수화기를 내려 놓는 소리만 들린다.&

103>골드의 법칙 
발에 딱 맞는 신은 모양이 마음에 들지 않는다.

104>핀만의 바겐세일 법칙 
사고 싶은 것은 바겐세일 품목이 아니다.

105>루이스의 법칙 
한참 돌아보고 어렵사리 샀어도 물건을 사고 돌아선 순간 더 싸게 파는 가게가 눈에 띈다.

106>매치의 법칙 
끝없는 공포보다 공포의 결과 쪽이 더 낫다.

107>쿠퍼의 고등논리 법칙 
새로운 법이 공포되면 빠져나갈 구멍도 새로 공포된다.

108>커크카드의 법칙 
인생은 앞을 향해서만 나아간다. 그러나 거슬러 올라가야만 이해할 수 있는 것이다.

109>개비털의 법칙 
현명한 자는 진실을 발견함으로써 기뻐하고 어리석은 자는 오류를 찾아냄으로써 기뻐한다.

110>에스터의 법칙 
가장 신경이 날카로운 사람에게 가장자리가 깨어진 커피 잔과 립스틱이 묻은 컵, 머리카락이 
들어 있는 음식이 나온다.

저작자 표시
신고
Trackback 2 Comment 0
2014.07.14 11:12

펌)물막이 이후, 명불허전의 터진 옆구리

물막이 이후, 명불허전의 터진 옆구리
[39호] 2011년 12월 12일 (월) 11:53:13박창근  info@ilemonde.com

“지금 문제는 속도전이고, 전광석화와 같이 착수하고 질풍노도처럼 몰아붙여야 한다.” 2008년 12월, 4대강 사업에 대해 당시 한나라당 대표인 박희태 국회의장이 한 말이다. 그 뒤 밀실에서 6개월 만에 4대강사업 마스터플랜이 만들어지고 4개월 만에 환경영향평가를 완료하는 등 각종 절차를 형식적으로 완료하고, 1년이 채 지나기도 전인 2009년 11월 마침내 4대강 사업은 착공됐다. 2년간의 공사로 사업은 완료 단계에 있다. 속도전으로 보면 4대강 사업은 가히 ‘명불허전’(命不虛傳)이다.

  
지난여름 집중호우에 유실된 칠곡보 하상보호공을 지난 11월 말 포클레인들이 치우고 있다. <한겨레> 김명진 기자

부실설계·부실시공, 악의 시너지

정부가 4대강 사업의 모범 사례로 자랑하는 낙동강 화명지구 하천공원사업은 계획 기간으로 약 4년이 필요했고, 공사 기간도 약 3년이 소요됐다. 살필 게 그만큼 많았다는 뜻이다. 그러나 사업규모 면에서 500배 이상인 4대강 사업이 기본계획에서 준공까지 3년이 걸렸다. 국토해양부는 당초 보와 준설은 지난 6월에 완료하겠다고 밝혔지만, 현재 4대강 사업은 각종 부실공사 탓에 공사 기간이 늘어나고 있다. 10월에서 12월로 준공이 늦춰졌다가 다시 내년 4월로 준공 시점을 조정하고 있다. 부실공사를 보강하는 뜻도 있지만, 총선과 연계한 꼼수라는 의혹을 지울 수 없다.

그들만의 논리로 만들어진 4대강 마스터플랜(기본계획)에는 △홍수 방어 △물 확보 △수질 개선이라는 목표가 제시돼 있다. 홍수는 4대강 사업 구간이 아닌 지천에서 발생하고 있고, 확보된 물은 사용처가 없으며, 보에 물을 저장하면 썩을 수밖에 없기 때문에 4대강 사업은 애초 목표가 잘못 설정됐다. 방향이 잘못 설정되면 속도는 아무런 의미가 없다. 오히려 부작용만 증가시킨다. 지금 4대강 사업 현장에서는 잘못된 설계와 부실시공으로 심각한 문제들이 여기저기서 발생하고 있다.

먼저, 설계 잘못에 따른 문제점은 일일이 열거하기조차 힘들다. 보 부근에서 홍수 위험이 높아졌고, 보에 물이 고임에 따라 수질이 악화되고 상수원수 처리 비용이 증가할 것이며, 준설한 모래의 20% 이상이 다시 강바닥에 쌓이면서 헛준설이 되고 말았다. 함안보에 물을 채우면 약 400만 평 농경지에 침수 피해(규모의 차이는 있지만 다른 보에서도 농경지 침수 피해가 발생할 것이다)가 일어날 것으로 예측되고, 농경지 리모델링 사업으로 원활한 영농 활동을 유지할 수 없게 될 것이다. 이 밖에 역행침식으로 인한 지천 제방과 교량 붕괴, 상주보 하류 지역 낙동강 본제방 일부 유실, 수압으로 수문이 비틀어져 홍수 때 원활한 수문 작동의 어려움, 하천 둔치에 설치한 자전거도로와 공원에 대한 유지·관리 비용 등은 이미 발생했거나 현재진행형인 문제다.

더욱이 부실한 설계에 부실한 공사가 만나면서 부정적 시너지 효과를 일으키고 있다. 과도하게 준설을 하면서도 안전장치를 제대로 하지 않아 이미 경북 구미에서는 단수 사태를 겪었고, 왜관철교와 남지철교는 붕괴되고 말았다. 구미보와 칠곡보의 하상보호공이 유실되면서 보 본체가 붕괴될 우려가 있고, 대부분의 보에서 누수로 인한 콘크리트 구조물의 약화로 내구연한이 줄어들 것으로 보이며, 역행침식을 막기 위해 설치한 하상보호공도 유실 가능성이 농후하다.

홍수 위험 상승, 농경지는 상습 침수

여기서는 최근 사회적 논란이 되고 있는 4대강 사업 현장의 보 누수 문제와 보에 물을 채움으로써 발생하는 농경지 침수 문제를 좀더 구체적으로 살펴보자.

  
지난여름의 호우로 다리 일부가 무너진 경북 칠곡군 왜관읍 왜관철교. <한겨레> 이정아 기자

지난 12월 5일 국토해양부는 “4대강 사업으로 건설되는 16개 보 중 낙동강 유역 8개 보 모두와 금강의 공주보에서 누수 현상이 발생했다”고 발표했다. 그런데도 국토해양부의 태도는 안이하다. 국토해양부는 “상대적으로 누수가 많은 상주보는 34곳에서 누수가 발생했지만 나머지 8개 보는 누수 부위가 1~4곳 이하”라며 의미를 축소했다. 또한 “설계서대로 시공이 됐고, 누수 내용도 경미해 안전에 문제가 없다”며 “있을 수 있는 경미한 현상으로, 보완하면 문제가 없다”는 게 공식 설명이다.

먼저 상주보 외 나머지 8개 보에서는 누수 지점이 최대 4곳 이하라는 설명은 사실을 축소하려는 의도로 파악된다. 현장 조사 결과, 실제 낙동강의 나머지 7개 보의 경우 적어도 10곳 이상에서 누수가 발생했다. 국토해양부는 현장에서 발생한 누수 상황도 제대로 파악하지 못한 셈이다. 누수가 발생하더라도 보의 안전에 문제가 없다는 정부의 인식은 한심하다. 보에 누수가 발생했다고 당장 보가 무너지지는 않는다. 그러나 콘크리트에 균열이 간 사이로 물이 스며들면 겨울철에 물이 얼었다 녹았다 하는 과정에서 물과 맞닿은 콘크리트가 깨질 위험이 있다. 이런 과정이 계속되면 결국 보의 내구연한이 줄어들 것이다. 만약 보의 수명이 50년이라면 부실공사로 인해 20~30년 정도로 단축될 수 있다. 이는 부실공사의 심각한 부작용으로, 결코 무시할 수 없는 문제다.

누수 현상보다 더 심각한 점은 보 직하류부에 설치한 하상보호공이 일부 유실된 사건이다. 구미보와 칠곡보에서 이런 사고가 이미 발생해, 현재 보강공사가 진행되고 있다. 일반적으로 보 하류부에 별다른 공사를 하지 않으면 폭포가 형성돼 그곳의 모래가 물살에 파여나가게 된다. 이것을 ‘세굴 현상’이라 하는데, 보 하류부의 세굴 현상은 보 본체가 주저앉는 결과로 이어질 수 있다. 이를 방지하기 위해 보 하류부에 하상보호공을 설치하는데, 이 하상보호공이 일부 유실되는 사고가 발생한 것이다. 이것은 명백한 설계 잘못이라 판단된다. 즉, 구미보와 칠곡보는 제대로 보강공사를 하지 않으면 붕괴 위험에 처할 수도 있다.

보는 설계서대로 시공했고 경미한 누수는 안전에 문제가 없다는 설명은, 4대강 사업에 대한 국토해양부의 안이한 인식이 그대로 녹아 있다. 우리나라에서 중간급 기술을 가진 건설회사도 제대로 공사를 했다면 누수 현상은 발생하지 않는다. 간단한 석축공사를 해도 누수가 발생하지 않는데, 대규모 보를 건설하는 현장에서 준공도 하기 전에 콘크리트 구조물에서 물이 줄줄 새는 공사장은 한국의 토목기술 수준에서는 생각할 수 없다. 또한 댐 설계 기준 어디에서도 누수를 인정하는 내용은 없다.

새는 보, 붕괴 위험 배제 못해

토목계는 정치권에 떠밀려 억지로 4대강 사업을 진행했는데, 정치권이 제시한 시간표는 2년 내에 사업을 마무리하는 것이었다. 당초 불가능한 시간표대로 사업을 진행하다 보니 무리한 일정으로 공사를 할 수밖에 없었다. 임진강에 최근 완공된 군남댐의 경우 공사 기간이 6~7년이었는데, 2년 만에 16개 보를 한꺼번에 설치하려다 보니 여러 가지 문제가 발생하는 것은 너무나 당연하다. 예고된 부실공사다.

365일 동안 하루 24시간을 쉼없이 현장에서 공사가 진행됐는데, 야간에는 공사장 인부들의 집중도가 떨어질 수밖에 없다. 보 높이가 10m 정도로 높아 콘크리트를 일체로 타설할 수 없기 때문에 분할 시공을 해야 했다. 즉 콘크리트를 한 번 치고 나서 마르면 다시 콘크리트를 치는데, 그 시공이음부(Construction Joint)가 부실해질 수 있다. 특히 겨울철에 영하 10℃ 이하로 떨어지는 현장에서는 공사를 하지 않는 게 원칙인데, 공사 기간을 맞추다 보니 무리하게 공사를 강행했다.

우리나라에서는 동절기에 공사 중지 기간을 두고 있는데, 지역마다 다소 차이는 있지만 보통 12월부터 이듬해 2월까지 공사를 일시 중지하고 날이 풀리면 재개한다. 그리고 상식적으로 야간에는 공사를 하지 않고 인부들이 잠을 자야 하는데, 대낮같이 조명을 밝히고 폐쇄회로텔레비전(CCTV)까지 설치해 공사를 독려하다 보니 콘크리트 품질이 떨어질 수밖에 없는 상황이었다.

  
칠곡보에서 유실된 하상보호공을 치우는 공사가 진행되고 있을 때, 같은 시간 구미보에서는 날개벽과 보 본체의 갈라진 틈 사이로 물이 새나왔다. <한겨레> 김명진 기자

농경지 침수 피해 조사, 결과는 쉬쉬

단군 이래 최대 국책사업이라고 떠들어댄 4대강 사업이 그 주체인 토목계의 의견은 전혀 반영되지 않고 정치권의 시간표대로 사업을 진행하다 결국 부실공사로 이어졌다. 이는 속도전이 가져다준 예견된 부실공사다. 속도를 강조하다 보면 안전에는 소홀해진다. 많은 토목인들은 이를 두고 ‘토목계의 수치’라고 인식한다.

4대강 사업의 핵심은 16개 보 건설과 대규모 준설이라 할 수 있다. 이 중 낙동강에 위치한 함안보·합천보는 담수를 할 경우 강 수위가 올라가 인근 보 상류 지역의 농경지가 침수될 수 있다. 이로 인해 함안보에서는 공사 도중 긴급하게 댐 높이를 2.5m 낮추는 설계 수정을 하고 사업을 진행했지만, 여전히 주변 농경지의 침수 피해 우려가 해소되지 않고 있다. 이런 문제를 평가하기 위해 경상남도는 2010년 12월 7일, 국책사업으로 시행하고 있는 낙동강 사업 중 함안보·합천보 설치로 인한 관리수위 상승이 농경지 등 주변 지역에 미치는 영향을 분석하기 위해 피해조사 용역에 착수했다.

  
함안보 관리수위 상승에 따른 침수 우려 지역

경상남도는 지난 6월, 함안보가 영향을 미칠 지역에 대해 지하수 이용 현황, 지하수위 현장 조사, 수리지질 특성, 지하수 함양량 등을 파악하고 지하수위 모델링을 수행해 지하수위 영향범위를 분석했다. 그 결과 함안보 건설에 따라 지표와 지하수위의 차가 1.0m 이하인 영농피해 우려지역 면적은 12.28㎢로 분석됐다. 합천보의 경우 지표와 지하수위의 차가 1.0m 이하인 영농피해 우려지역 면적은 0.44㎢이었다. 경상남도는 연구용역의 결과를 국토해양부와 한국수자원공사, 그리고 해당 지방자치단체에 통보하고 대책 수립을 건의했다. 지하수위 상승이 농작물 작황에 영향을 줄 것으로 보고 농업기술연구원을 통해 해당 지역의 주요 작물에 대한 피해 조사에도 착수했다. 이와 함께 함안보 설치에 따른 농경지 침수 및 농작물 피해 대책 수립을 위해 다음과 같이 국토해양부와 한국수자원공사에 요청했다.

우선 함안보의 관리수위를 현재의 5m에서 3m 이하로, 합천보의 경우 10.5m에서 8m 이하로 낮춰 경남도민의 재산권 피해를 최소화해야 한다. 만약 관리수위 조절이 힘들면 피해 대책 수립 전까지 함안보와 합천보의 수문을 완전히 개방해 경남도민의 재산상 피해가 발생하지 않아야 한다.

한국수자원공사는 함안보 설치에 따른 피해 대책 수립을 위해 2010년 8월 7억원의 예산을 들여 용역을 진행했지만, 아직까지 결과를 공개하지 않고 있다. 그만큼 함안보로 인한 농경지 침수 범위가 넓기 때문에 발표 시점을 미루는 것이다. 이 와중에 11월 29일 함안보 개방 행사가 열렸는데, 한국수자원공사의 농경지 침수 대책은 여전히 감감무소식이다. 한국수자원공사는 용역 결과를 즉각 공개하고, 만약 그 결과에 경상남도의 용역과 차이가 있으면 전문가와 해당 지자체, 주민이 함께하는 토론회를 열어 명명백백하게 내용을 공개하고 대책을 수립해야 한다.

합천보에서는 벌써부터 농경지 침수 피해가 발생하고 있다. 지난 12월5일 경남 고령군 객기리 연리들(객기배수장에서 1.5m 떨어진 지점)에서 한국수자원공사, 고령군 및 농어촌공사가 공동으로 지하수위를 조사했다. 객기리 연리들 내 2개 지점을 포클레인 2대로 1.8m 굴착한 결과 지하수가 용출됐고, 그 부근 지표면은 모두 축축했다. 농사를 짓기에는 부적절한 상태이고, 이 때문에 지난 8월 20일 파종한 수박 모종의 뿌리가 모두 괴사해 17동(1만1239㎡·3400평 정도)의 재배지가 피해를 입었다. 지금은 수박 농사를 위한 비닐하우스를 설치할 수 없을 만큼 침수 피해가 발생하고 있다.

  
또한 같은 시간, 상주보에서는 인부들이 물이 새는 곳에 에폭시를 주입하는 보강공사를 하고 있었다. <한겨레> 김명진 기자

준공 불가능한 사업, 예정된 재앙

앞에서 살펴본 바와 같이, 부실시공으로 보에서 누수가 발생했고 보에 물을 채움으로써 인근 농경지가 침수 피해를 입어 영농에 심각한 악영향을 주고 있다. 이런 피해는 졸속으로 계획한 사업이 가져다준 예견된 재앙이라 할 수 있다. 22조 원이 소요된 4대강 사업을 유지·관리하기 위한 예산은 정부 추산으로 2400억 원이고, 대한하천학회가 산정한 유지·관리비는 연간 6천억 원에 이른다. 그러나 재퇴적된 모래를 다시 준설하는 데 약 1조 원의 추가 비용이 소요되는 것으로 추정되고, 추가 준설 예산을 확보하는 것이 사실상 불가능하기 때문에, 4대강 사업은 결국 허상만 좇아다녔다고 할 수 있다. 시작은 하였으나 마칠 수 없는 것이 4대강 사업이고, 실패한 4대강 사업을 은폐하기 위해 20조 원의 지천사업을 후속 사업으로 계획하고 있다.

4대강 사업은 이미 많은 문제를 발생시켰다. 발생한 문제를 보면 공학적으로 해결하기 어려운 것보다는 제대로 검토하지 않아 발생한 것이 대다수다. 대규모 국책사업을 시행하면서 비전문가인 정치인들의 목소리만 커졌을 때 어떤 사태가 벌어지는지를 보여주는 좋은 예다. 4대강 사업은 녹색성장의 주요 사업이라고 선전되고 있지만 결코 ‘녹색성장’이라는 이름을 붙일 수 없는 사업이다. 친환경적이지 않고, 예산을 낭비했고, 지속 가능하지도 않고 졸속으로 진행한, 실패한 국책사업으로 역사에 기록될 것이다.
한 번 거짓말을 하면 그것을 감추기 위해 계속 거짓말을 할 수밖에 없고, 더 큰 거짓말을 낳는다는 사실을 알아야 한다. 우리 사회가 그런 거짓말에 더 이상 관심을 보이지 않을 때까지 거짓말은 계속될 것이다. 이것은 밀실행정이 가져다주는 전형적인 폐단이다. 지금이라도 국토해양부는 거짓말로 진실을 감추려 하지 말고 4대강 관련 문제에 대해 공개적으로 토론하고 해결 방안을 마련해야 한다. 그래야만 더 큰 재앙을 예방하거나 줄일 수 있다.

 / 박창근 관동대 교수·토목학
시민환경연구소 소장, 한반도 대운하를 반대하는 전국교수모임 공동집행위원장.


저작자 표시
신고
Trackback 4 Comment 0
2014.06.11 12:03

펌)비만에 시달리는 지구인

식품회사의 업무는 사람들을 많이 먹게 하는 것이다.

비만이 가난의 상징 같은 것이 된거는 역사상 처음일 거다.

르몽드 디쁠로마틱에서 퍼옴 


http://www.ilemonde.com/news/articleView.html?idxno=1932


비만에 시달리는 지구인
[48호] 2012년 09월 12일 (수) 16:38:38브누아 브레빌  info@ilemonde.com
  
 

식품업계가 흔히 퍼뜨리는 편견이 있다. 비만은 자신의 욕구를 통제하지 못하는 사람들이 걸리는 것이니, 자신의 상태는 자신이 책임져야 한다는 말이다. 이같은 주장은 세계화되고 있는 비만 현상의 원인을 감추는 것이다. 비만의 실오라기를 하나 잡아당기면 이른바 선진사회의 삶 방식에서 모든 실타래가 풀린다.

1985년, 포레스트 데이비스는 용접공 일을 그만두고 '대형 관(棺)' 전문회사 골리앗 카스켓(Goliath Casket)을 창설할 때만 해도, 회사가 이렇게 잘될 줄은 상상하지 못했다. 인구비만율이 채 15%도 안 되는 미국의 대형 관 시장은 걸음마 단계였다. 이후 미국인의 허리둘레는 부쩍 늘었다. 그 덕분에 1980년대 말까지만 해도 연간 대형 관(일반 관의 3배 크기)을 1개밖에 판매하지 못하던 동부 인디애나의 작은 가족 회사에서 판매량이 매월 5개로 증가했다. (중략) 황금으로 도금한 손잡이에 내부를 쿠션으로 채운 다양한 색상의 '사치스러운 관'까지 등장했다. 현재 미국 성인 인구의 3분의 1이 과체중이다. 또 다른 3분의 1은 비만에 시달리고 있어, 미국은 세계 최대의 뚱보 나라 중 하나다.(1)

시장도 이런 새로운 체형에 발 빠르게 대응하고 있다. 기업들은 이같은 현상에 적응하며 '거인'들을 겨냥한 특별 상품을 출시하고 있다. 경기장과 연극관용 대형 소파와 뼈대를 강화시킨 들것, 킹사이즈 매트리스, 그리고 뚱뚱한 독신들을 위한 만남 사이트들도 등장했다.

이를 틈타 기업들은 이른바 살 빼는 약에서부터 군대식 다이어트 캠프(비만캠프), 1만 달러짜리 외과 시술에 이르기까지 다양한 비만 퇴치 프로그램을 소개하며 수천억 달러의 수익을 챙기고 있을 것이다. 비만이나 비만현상을 분석하며 이에 대한 기적의 처방을 소개하는 책들이 봇물을 이루자, <뉴욕타임스>는 별도의 난을 만들어 이런 책들의 판매 순위를 알리고 있다. 한편 미국인들의 체중 증가 원인은, 이들 삶의 패턴이 칼로리 섭취량은 늘고 소비량은 줄어드는 쪽으로 바뀌었기 때문이다.

미국의 라이프스타일은 소비와 기술의 발전을 숭배하고 있어 육체적 비활동을 장려한다. 즉 엘리베이터, 에스컬레이터, 리모컨, 자동 스프링클러, 진공청소기, 세탁기, 세탁건조기, 전동 오프너와 나이프 등이 육체적 활동을 저해한다. 에릭 A. 핑켈슈타인과 로리 주커먼은(2) "이같은 발명품들로 인해 우리는 자신도 모르는 사이에 칼로리(kcal) 양이 줄었다. 예를 들어, 우리가 세탁기로 옷을 빠는 대신 손빨래를 하면 45kcal를 절약한다"고 했다. 기술 진보가 가져다준 해악일까? 미국인은 특정 가사 부담에서 해방되며 시간적 여유가 생겼지만 그 시간을 여가활동을 하는 데 쓰기보다는 주로 TV 시청이나 운전대를 잡는 데 썼다.

도시 삶의 형태는 자동차를 이용하도록 부추기는 면이 있다. 제2차 세계대전 이후 수십 년간, 도시 주민들은 도심의 집값이 상승하자 도시 변두리로 대거 이주했다. 이로 인해 교외 지역이 문어발식으로 개발됐다. 하지만 끝없이 펼쳐진 빌라, 미흡한 보도시설(때론 보도가 아예 없는 곳도 있다), 단조로운 거리 풍경, 잘못 표기된 횡단보도 등 보행자들에겐 교외 지역이 악몽이었다. 대도시를 제외하곤 개발에 걸맞은 대중교통 시설이 갖춰지지 않은데다 한층 멀어진 거리 때문에, 주민들은 일상적으로 자동차를 타고 다닐 수밖에 없었다. 1960년대 이후 교외에서 자동차로 출퇴근하는 인구수는 3배, 자동차 주행거리는 3~5배 증가했다.(3) 미국인은 주당 10시간 이상을 자동차 안에서 보낸다. 이런 비활동시간이 체중을 증가시킨다. 애틀랜타에서 실시한 연구에 따르면, 매일 1시간씩 운전하면 비만일 확률이 6% 높아지고, 매일 반마일씩 걸으면 그 확률이 대략 5% 감소하는 것으로 드러났다.(4) 그러므로 미국에서 가장 드문드문 건설된 25개 주택 단지(즉, 자동차로 이동하는 거리가 가장 긴)에 거주하는 주민의 체중이, 또 다른 25개 주택 단지나 최대 주택 밀집 지역에 거주하는 주민의 체중보다 6파운드(2.7kg) 더 나간다고 해서 놀랄 일도 아니다.(5)

하지만 미국인이 주당 40시간씩 스크린(텔레비전, 컴퓨터, 비디오게임 등) 앞에서 보낸다는 것을 감안하면, 운전하는 시간 때문에 운동할 시간을 내지 못한다는 것은 가당치않은 말이다.(6) 아침부터 저녁까지 켜져 있는 TV는 미국 가정의 중요한 요소가 됐다. 그래서 미국 일반 가정의 TV 보유 대수는 가족 수보다 더 많다(2.9 대 2.57). 예컨대 TV가 덜 움직이고 많이 먹게 하는 징검다리 구실을 하고 있다. 집 안에 틀어박혀 지내는 삶이 TV 애청자들을 군것질로 내몰고, 봇물을 이루는 TV 광고가 이들(특히 청소년층)의 식습관을 과식으로 유도하는 것이다.

그래서 푸드 시장은, 우리 몸이 요구하는 것보다 더 많은 양을 우리에게 먹일 수 있다는 진단을 제기했다. 물론 이들의 주장을 뒷받침해줄 만한 명확한 근거는 없다. 하지만 불필요한 유행 셔츠나 최신형 휴대전화도 구입하는데, 자신의 의지에 따라 건강을 담보로 신체기관이 필요로 하는 양보다 많은 칼로리를 섭취할 수 있는 것 아닐까? 예컨대, 사람의 신진대사는 음식을 인구성장과 연동시켜 서서히 성장하는 시장으로 만들어야 했다. 그러나 1970년 하루 권장량 2200kcal를 섭취하던 미국인이, 40년이 지난 지금 2700kcal를 섭취하고 있다.

국민 비만을 조장하는 미국의 임금정책

농산물 가공 산업은 수익을 늘리기 위해 자연적인 인구성장의 틀을 깼다. 이들은 상점에 수많은 신상품들을 채워 신상품에 대한 소비자들의 욕구를 끝없이 자극했다. 1990년~2000년대 말, 슈퍼마켓 진열장에 등장한 신상품은 11만6천 개를 웃돌았다. 이런 '공급의 다양화' 때문에 건축가의 창의력이 요구되는 곳이 미국 식료품 가게의 음료 진열대이다. 반짝반짝 빛나는 강장음료, 포도 향이나 산딸기 향이 첨가된 음료, 6개들이 세트를 얼음 팩에 담아 팔거나 '레게의 전설' 밥 말리의 이미지를 부착해 판매하는 캔음료가 진열되어 있다. 온갖 맛을 내는 탄산음료와 체리·레몬(녹색이나 노란색)·바닐라 맛을 내거나, 설탕과 카페인이 첨가되어 있지 않은 이른바 코카콜라의 변형 음료, 반투명 주스, 과즙을 첨가하거나 뺀 주스, 무공해 주스, '과일에서 추출한' 주스 등으로 진열대가 채워져 있다. 이런 전략은 대박 효과를 냈다. 1970년 미국인의 1인당 연간 탄산음료 소비량은 85ℓ였다. 그 후 1980년엔 135ℓ로, 그리고 현재는 178ℓ로 증가했다.

포장·보존·유통 방식이 고도화된 덕분에 가공식품, 특히 고칼로리 가공식품 가격이 중요한 영양소(미네랄, 비타민 등)가 함유된 신선한 농산물 가격보다 쌌다. 이를테면 1달러로 감자칩을 사 먹으면 당근을 사 먹는 것보다 더 배불리 먹을 수 있었다. 만약 모든 미국인이 정부의 '식이요법 충고'에 따라 칼륨·비타민D·칼슘의 섭취량을 늘리고, 가공식품에 설탕과 소금이 든 불포화지방의 섭취를 줄인다면, 미국인은 연간 1인당 400달러를 더 지출해야 한다.(7)

미국의 임금정책이 빈곤층을 비만으로 내몰고 있다. 빈곤층의 가계 지출 내역을 살펴보면, 이들은 주로 칼로리는 높고 영양소는 적은 식품을 소비하고 있어 가장 먼저 비만의 희생자가 될 수밖에 없었다. 2011년 7월 7일자 <월스트리트 저널>에 따르면, 연간 소득이 1만5천 달러 미만인 성인 중 3분의 1이 비만에 시달리는 데 반해, 연간 소득이 5만 달러 이상인 성인의 비만율은 24.6%에 그쳤다. 따라서 라틴계나 아프리카계 등의 소수민족 비중이 큰 미국의 최대 취약 주- 앨라배마, 테네시, 텍사스, 켄터키, 루이지애나 등- 에서 과체중과 비만에 시달리는 사람들이 많이 발견된다.

상품 가격의 하락은 단지 빈곤층과 식품 간의 관계만 역전(결핍에서 과다섭취로)시킨 것이 아니라, 시장경제의 상황까지 뒤흔들어놨다. 이제 가격에서 식품 자체가 차지하는 부분은 미비한 반면, 포장 및 홍보 그리고 콘셉트 비용이 가격의 대부분을 차지한다. 그러다 보니 같은 크기의 용기에 대용량을 담아 판매할 때 이득이 컸다. 예를 들어 월마트는 321g들이 땅콩과 캐러멜 초콜릿바 1봉지를 3.58달러에 판매하는 데 반해, 1100g들이는 8.98달러에 판매한다. 3배 밑도는 가격에 4배 가까운 용량을 담아 파는 것이다. 대부분의 고객, 특히 극빈층은 가격 혜택을 누리기 위해 후자를 선택한다. 거의 모든 상품에 이런 마케팅이 사용되어 우유는 리터보다는 갤런으로, 감자칩은 패밀리용으로 포장된 상품을, 체다 치즈는 진공 포장된 500g짜리를 구입하는 것이 항상 유리하다.

패스트푸드의 '슈퍼 사이즈' 전략

사람들이 경제 논리가 생태적 정언 명령(환경보호)과 공조하는 것이니 희소식이 아니냐는 반응을 보일 수도 있다. 물론 그럴 수 있으나, 영양학자 매리언 네슬은 "우리 머릿속에 있는 뭔가는, 우리 앞에 음식이 많이 놓여 있을수록 우리로 하여금 더 많이 먹게 만든다"며 반박했다.(8) 바바라 롤스 펜실베이니아대학 교수도 실험을 통해 이 사실을 입증했다. 그는 평소 자신의 몸매에 관심이 많은 날씬한 젊은이들을 상대로 실험을 했다. 그들에게 매일 서로 다른 용량의 치즈 마카로니를 제공한 후, 하루 섭취량을 쟀다. 그들은 치즈 마카로니 450g을 제공하면 280g을, 700g을 제공하면 425g을 먹어치움으로써 전날 저녁 자신들이 먹고 흡족해했던 용량의 절반 이상(143g)을 더 먹어치웠다. 또한 대·소형 팝콘을 가지고 영화관에서 진행한 실험, 직원들의 눈에 띄는 곳에 케이크를 놓고 직원들의 먹성을 실험한 사무실에서도 결과는 마찬가지였다.

  
 

이런 인간 심리에 정통한 패스트푸드 체인점들은 '슈퍼 사이즈' 전략을 세웠다. 고객은 몇 달러(하지만 효과 만점인)만 더 내면 '사이즈 업'한 메뉴와 음료, 고기 한 점이 더 들어간 햄버거, 감자튀김을 더블 사이즈로 먹을 수 있다. 모든 식당이 소비자들의 새로운 기대 심리를 충족시키기 위해 패스트푸드점이 제공하는 음식량을 따라가며, 식당의 '표준' 사이즈도 덩달아 커졌다. 40년 전만 해도, 맥도널드는 오직 0.2ℓ들이 단일 사이즈 음료만 팔았다. 하지만 현재는 가장 작은 사이즈가 0.35ℓ, 가장 큰 사이즈는 1ℓ에 달한다. 당시 판매되던 성인용 햄버거는 이제 어린이용으로 제공되고 있고, 성인들은 그것을 간식으로 먹는다. 슈퍼마켓보다 패스트푸드가 5배 더 많은 나라에서, 이런 변화는 응당 비만 확산에 영향을 미치고 있다.

더구나 광고를 통해 소비자들, 특히 어린이들에게 고칼로리 음식을 먹는 즐거움을 계속해서 상기시킨다. 미국의 가난한 사람들과 청소년들이 광고 시장의 표적이 되고 있다. 오랜 기간 음식 소비는 절대적으로 부모들의 소관이었다. 대부분 부모의 구매력 증가와, 자녀의 욕망에 대한 부모의 시각 변화는 어린이들을 완전한 소비자로 만들었다. 전 텍사스 농업기술대학의 교수이자 '어린이 마케팅의 교황'으로 불리는 제임스 맥닐은 <뉴욕타임스>(2011년 4월 20일)에서 "어린이들이, 그 주변인들이 한 해 구입하는 식품과 음료의 8% 이상을 좌지우지하며, 이를 액수로 환산하면 1천만 달러에 해당한다"고 했다.

그래서 광고는 어린이들의 비위에 맞추기 위해 애쓴다. 미국 어린이는 한 해 평균 2만5천 건의 광고에 노출되고, 이 중 5천 건이 식품 광고다.(9) 청소년의 관심을 끌기 위해 특별히 제작된 광고들은 제품과 청소년 간에 끈끈한 관계를 형성할 목적으로 주로 청소년에게 친숙한 인물을 광고에 기용한다.(10) 따라서 미국 애니메이션 <스펀지 밥>은 크래프트 치즈 마카로니를 비롯해 브라이어즈 아이스크림, 허시 초콜릿바 등의 광고를 하고 있다. 그래도 '광고의 천재'들은, 3살 미만 어린이 프로그램에는 다양한 피부색의 스타 정령들이 출연하는 '텔레토비'까지 이용하지 않았다.

그러나 몇 년 전부터 소비자 단체들이 이 광고 기법을 비난하자, 다국적 농수산물 기업들은 새로운 미디어를 공략하고 있다. 이 기업들은 온라인상에서 스마트폰용 애플리케이션으로 전자 퀴즈를 제공한다. 이들은 인터넷과 휴대전화로 여태껏 한 번도 경험하지 못한 신대륙을 발견한 것이다. 게다가 이런 광고는 규제도 힘들다. 그 어떤 법도 어린이가 페이스북에서 로널드 맥도널드와 '친구'가 되거나, 어린이를 대상으로 한 귀여운 꿀벌 캐릭터 게임 사이트(honeydefender.com)에서 수시간씩 머물며 꿀을 딴다고 해서 막을 수는 없다. 또 맥도널드가 운영하는 맥월드 닷컴(McWorld.com)에서 어린이들이 '스펀지 밥'과 그림 그리는 것을 막을 수 없다.

식품업계의 공격적 관행 앞에서 정부는 오랫동안 뒷짐만 지고 있었다. 그러는 사이 2011년, 정크푸드 시장은 거대 공룡이 됐다. <파이낸셜 타임스>(2012년 6월 9~10일)가 발표한 수치에 따르면 피자와 패스트푸드의 세계 총매출액이 7060억 달러에 달하며, 유명 브랜드들은 자사 이익을 위해 광고에 막대한 자금을 쏟아붓는다고 한다. 그러나 이 관행에 서서히 고삐가 조이고 있다. 비만율이 높아지고, 이로 인해 발생되는 문제들(우울증, 차별, 건강 위험, 생산성 손실 등)이 사회 전체를 불안하게 만들고 있다. 한 해 비만으로 사망하는 인구가 20만 명에 달해- 흡연으로 사망하는 인구(40만 명 이상)보다는 적지만, 알코올이나 교통사고로 사망하는 인구보단 훨씬 많아- 비만은 '피할 수 있는 사망' 원인 중 2위에 올라 있다. 비만 관련 질병들(제2형 당뇨병, 심혈관 질환, 고혈압, 동맥경화, 폐색전증, 콜레스테롤, 암 등)로 인해 매년 발생하는 추가 의료비가 1470억 달러(대략 총의료비의 10%에 달한다)에 이른다. 이 중 618억 달러를 미국 의료 협회, 메디케어&메디케이드가 직접 부담하고 있다.(11)

"적당히 살찐 모습은 성공의 표시"

최근 연방정부는 청소년 체육활동 활성화, 제품의 영양가를 보장하는 라벨 제작, 학교 안에 탄산음료 반입 금지 등 비만 예방 프로그램을 늘리고 있다. 지역, 주, 시로 갈수록 엄격한 법률을 도입하고 있다. 예를 들어, 2010년부터 캘리포니아를 비롯한 메인·오리건·뉴저지 주(州) 등은 패스트푸드점에 제품의 칼로리 표기를 의무화했다. 지난 5월 뉴욕시는 식당, 영화관, 경기장 내에서 설탕 든 슈퍼사이즈 청량음료는 판매를 금지시켰다.

2010년 연례 보고서에 따르면, 기업의 미래 수익과 물 부족, 세계경제 위기, 그리고 기후변화 등에 영향을 미칠 수 있는 30가지 조항이 담긴 미국 법률을 가장 잘 지키지 않는 기업은 코카콜라사로 밝혀졌다. 그래서 다국적기업은 자신들의 장래를 위해 미국보다 (음료 시장의) 포화상태가 덜하고, 특히 통제가 덜한 새로운 시장 쪽으로 눈길을 돌리고 있다.

한때 비만은 서양과 페르시아만 국가의 전유물이었다. 그런데 이젠 모든 신흥국가를 덮치고 있다. 개인의 체중이 마치 국내총생산(GDP)의 성장과 연동해 움직이는 것처럼 보인다. 성인비만율이 30%에 달하는 멕시코는 남아프리카공화국(18.1%)과 브라질(13.9%)의 성인비만율을 앞지르며 불량학생의 표본이 되고 있다. 물론 인도와 중국도 예외는 아니다. 경제발전은 도시화, 기계화, 식품의 산업화, 대형 유통기업을 등장시켰다. 경제발전이 미국인의 라이프스타일을 바꿔놓았는데, 인도·중국인들도 점차 미국 체제에 적응했다. 예를 들어 인도 전체 인구 중 도시민이 채 30년도 안 돼 23%에서 31%로 증가했다. 예전엔 농촌에 거주하던 수천만 명의 인도 육체노동자들이 그 지역에서 나는 식품으로 그럭저럭 끼니를 때웠지만, 이젠 이들이 점차 대량 소비에 맛들이고 있다. 자동차, TV, 세탁기가 집 안에만 틀어박혀 지내는 생활을 확산시키고 있다. 냉장고, 슈퍼마켓, 가공식품, 포장식품, 냉동식품 등 주로 수입품이 대도시를 점령하고 있다. 대형 유통업계의 매출이 매년 270만 달러 이상 증가하는 것으로 추정한다. 15년 전 라틴아메리카에서 그랬듯, 인도의 모든 식품 구매가 대형 할인마켓에서 이뤄지고 있다. 이들의 시장점유율이 1990년 15%에서 2000년 60%까지 치솟았다.(12)

패스트푸드 체인점은 신흥국에서 미국과 유럽의 전략과 제조법을 지속적으로 썼다. 이들은 단지 소스만 현지 취향에 맞췄다. 예를 들어, 인도 시장을 공략할 땐 광고 등장인물을 할리우드나 농구 스타에서 볼리우드(인도의 뭄바이를 중심으로 하는 힌디어 영화 산업을 일컫는 말) 스타나 크리켓 선수들로 교체했다. 힌두교도가 80%를 웃도는 국가라 맥도널드의 유명 햄버거 '빅맥'에 대한 반응이 시큰둥하자, 맥도널드는 인도인의 입맛에 맞춘 마하라자 치킨버거를 출시했다. 도미노피자는 페페로니와 스테이크 피자를 없애고, 대신 파프리카와 양고기 피자를 출시했다. 현지 패스트푸드 체인점들(Moti Mahal, Nahus Sweets, Sagar Ratna 등)은 연간 25~30%(13)의 신장세를 보이는 패스트푸드 시장에서 거대 미국 기업들을 상대로 매출 경쟁을 벌이고 있다. 2011년 켄터키프라이드치킨, 타코벨, 피자헛을 보유한 미국의 세계적 패스트푸드 외식업체 얌브랜드(Yum Brands)는, 2015년 전까지 인도에 지점을 1천 개 더 오픈하겠다고 발표했다. 하지만 이 정도는 중국에 대한 투자에 비하면 하찮다. 향후 중국에 2만 개 지점을 열 계획이기 때문이다.

인도와 중국의 비만 인구는 아직은 제한적이긴 하지만, 지속적으로 과체중 인구가 증가해 비만율이 벌써 상당한 수준에 도달했다. 인도 성인의 15%가 비만이며, 특히 여성 비만율이 더 높다. 일부 대도시(첸나이, 자이푸르, 델리, 뭄바이, 콜카타)에선 비만율이 30%, 심지어 40%에 달한다.(14) 중국에선 개인 병원들이 미국 다이어트 캠프를 본뜬 다이어트 프로그램을 고가로 운영하고 있다. 이 병원들을 찾는 성인 고객 중 30%가 과체중이며, 이 중 12%는 비만 판정을 받고 있다.(15) 중국에선 한 해 600만~1천만 명이 비만에 걸리고 있지만, 정부 차원에서 운영하는 비만 예방 프로그램은 아직 없다. 복지부에 근무하는 전문 영양학자 첸 추밍은 "사람들에게 햄버거나 고칼로리 음식을 먹지 말라고 당부하면, 그들은 '이젠 나도 돈이 있으니 내가 원하는 것은 뭐든 먹겠다'고 한다"며 자신도 어쩔 수 없다고 했다.(16)

일부 국가의 서민들은 빈부 차이와 농촌과 도시 간 간극 때문에 영양 섭취하는 데 이중고를 겪고 있다. 시골에선 음식이 귀하고 비싸서 농민들이 영양실조에 걸리는 데 반해, 식품산업이 넘치는 도시에선 중산층들이 외출·오락·소비를 즐기며 고칼로리 음식을 섭취하는 것이다. 니제르에선 도시 주민의 30%가 과체중인 데 반해, 시골 주민의 20%는 영향 결핍에 시달리고 있다. 나미비아공화국 대 인도는 각각 40% 대 18%, 25% 대 50%로 나타났다. 서방국가 대부분에서 실패했던 논리가 신흥국가에선 통한 것이다. 그래서 부자들은 뚱보가 되고 가난한 자들은 메말라갔다. 첸나이에서는 과체중이 거의 성공의 상징이 돼버렸다. 이 도시의 패스트푸드점은 한때 자사 상품 광고에, '당신은 비만이십니까? 축하합니다!'란 광고문구를 썼다. 거의 2명당 1명꼴로 에이즈, '피골이 상접하는 질병'에 감염되고 있는 일부 아프리카 마을에서 과체중은 심지어 개인의 양호한 건강 상태를 증명해주는 평가 기준이 되고 있다.

하지만 비만과 영양실조는 도시와 농촌 사이를 갈라놓을 수도 없고, 부자와 빈곤층 사이도 갈라놓을 수 없다. 비만과 영양실조가 같은 사회집단, 같은 지역, 같은 집안 내에 공존하기 때문이다. 레바논의 팔레스타인 난민이나 페루의 농민, 브라질 빈민가나 말리와 세네갈의 일부 대도시 주민들의 경우가 좋은 예다.

이런 공존은 세대 간 식이요법의 차이와 단절에서 비롯된다. 유년 시절 영양실조에 시달리던 사람은 신진대사가 바뀌어 지방을 축척하는 경향이 있다. 만약 이런 사람이 성인이 되어서 고칼로리 음식을 섭취한다면, 여전히 철분이나 비타민이 결핍되어 급히 살이 찌게 된다. 또 이들의 자녀는 영양실조에 시달리며, 키도 작고 빈혈에 걸릴 수 있다. 그래서 이집트는 구루병 걸린 아이들의 12%가 비만인 어머니를 두고 있다.(17)

세계적 차원에서 볼 때, 과체중 인구(대략 15억 명에 달하며, 이 중 5억 명은 비만이다)는 영양실조에 시달리는 인구(대략 10억 명)를 웃돌고 있다.(18) 유럽과 미국이 비만 퇴치에 나선 가운데, 많은 국가들이 아직 행동을 취하지 않고 있다. 한편 미국 정부가 '30가지 재앙 목록'을 담은 법안을 발표하자, 코카콜라사는 벌써 "비만과 여타 의학적인 문제들이 일부 자사 제품의 수요를 감소시킬 것"이라며 볼멘소리를 내고 있다.

글/브누와 브레빌 Benoît Bréville 작가.

번역/조은섭 chosub@ilemonde.com

(1) 세계보건기구(WHO)의 진단 기준에 따르면 체질량지수가 25kg/㎡ 미만이면 과체중으로, 30kg/㎡ 이상이면 비만으로 진단한다.
(2) Eric A. Finkelstein, Laurie Zuckerman, <The Fattening of America. How the Economy Makes Us Fat, If It Matters, and What to Do About It>, John Wiley & Sons, Hoboken (New Jersey), 2008.
(3) Amanda Spake, <Building Illness>, U.S. News & World Report, 2005년 6월 20일.
(4) Lawrence D. Frank, Martin A. Andersen, Thomas L. Schmid, <Obesity relationships with community design, physical activity and time spent in car>, American Journal of Preventive Medicine, 2004.
(5) Reid Ewing et al., <Relationship between urban sprawl and physical activity, obesity and morbity>, American Journal of Health Promotion, 2003년 9월.
(6) State of the Media, <Consumer Usage Report 2011>, Nielsen Media Research, 2012.
(7) Marion Nestle, <Does it really cost more to buy healthy food?>, www.foodpolitics.com, 2011년 8월 5일. 
(8) Amanda Spake, <A fat nation>, U.S. News & World Report, 2002년 8월 19일. 
(9) <Children’s Exposure to TV Advertising in 1977 and 2004>, Federal Trade Commission, 2007년 6월 1일. 
(10) 폴 모레라, ‘광고 때문에 병드는 아이들’, <르몽드 디플로마티크>, 1995년 9월호.
(11) <Fas in Fat, How obesity Threatens America’s Future 2010>, Trust for America’s Health/Robert Wood Johnson Foundation, 2010년 6월. 
(12) Barry Popkind, <The World is Fat: The Fads, Trends, Policies and Products That are Fattening the Human Race>, Avery, New York, 2009.
(13) Jason Overdorf, <India, the next Fast Food Nation?>, Global Public Square, CNN.com Blogs, 2011년 10월 25일. 
(14) Sanjay Kalra, AG Unnikrishnan, <Obesity in India, The weight of the nation>, Journal of Medical Nutrition & Nutraceuticals, vol.1, n°1, 2012. 
(15) <30 percent of Chinese adults overweighted>, People’s Daily Online, 2012년 3월 22일. 
(16) Calum McLeod, ‘China wrestles with growing obesity’, <USA Today>, 2008년 12월 20일. 
(17) ‘Arab diets, feast and famine’, <The Economist>, 2012년 3월 3일. 
(18) Boyd A. Swinburn et al., ‘The global obesity pandemic, shaped global drivers and local environments’, <The Lancet>, vol.378, n°9793, 2011년 8월 27일.


저작자 표시
신고
Trackback 2 Comment 0
2014.05.22 17:50

10대들을 위한 파이선 게임 프로그램 시작하기

파이선으로 놀기 .. 1편


0.1 로 진입하다. 토끼의 회전까지..(2013.8.17)

이 글은 버전 0.0 이다. 당분간 계속 덧붙여 나갈 것이다. 오늘은 시작만

0.2로 진입하기 (해가 바뀌어 2014.5.21) 9개월 정도 방치

0.3 으로 진입 8 9장만 남음  (5.23)

밑의 글에도 잠시 적기는 했지만 파이선으로 만든 프로그램이 인터랙티브하게 돌아야 할 이유는 많다,

파이선은 빠른 프로토타입이나 리버스 엔지니어링에 좋다고 한다. 쉽게 말하면 나같이 게으른 사람을 위해 만든 언어라고 보아도 좋다. 

문제는 이제 이걸로 무엇인가를 해야 하는데 몇가지의 장벽이 있다. 

0.5 로 진입 (5.23 저녁)  초벌 번역 끝

예제분석을  준비중이다. 


하나는 기계와 다이렉트 io 하는 부분이 약하다는 것이다. c 나 다른 언어로 무엇인가를 해주어야 한다.

펑셔널 어프로치가 아쉽다는 점... 이부분은 람다로 어느 정도 극복 가능하고 정 안되면 리스프나 스킴 인터프리터를 내재해도 된다.

그래픽이나 사운드같은 것이 잘 안된다는 점 .. 이부분을 pygame 같은 것으로 만들어서 놀면 된다는..


오늘은 그래서 파이선 게임을 만드는 예제를 한번 차분하게 번역을 해보기로 했다.

Beginning Game Programming for Teens with Python



글의 제목은 10대들을 위한 파이선 게임 프로그램 시작하기 정도로 번역할 수 있겠다. 더 좋은 이름이 있으면 제게 알려주면 이름을 고치겠다. 


에서 볼수 있다.

그럼 조금씩 시작해 보자.

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

이 글은 튜토리얼 팀 멤버인  줄리안 메이어 , 13 세 파이썬 개발자가 적었다.    와 Twitter 에서 찾을수 있다.

비디오 게임을 만드는 방법이 대다한 것이라고 생각할지도 모르지만 그다지  복잡하지 않다!

이 튜토리얼에서  토끼와 오소리라는 간단한 게임을 만들 것이다. 여기서 히어로인 토끼는 오소리떼의 공격에서 성을 방어할 것이다.


이 게임을 작성하려면, 당신은 파이썬을 사용하게 된다.  큰 뱀 얘기가 아니다! :]

파이썬은 컴퓨터 프로그래밍 언어다. 파이선을 사용하는 이유는  시작하기 간단한 언어이고, 재미 있고 쉽게 배울 수 있기 때문이다.


파이썬을 잘 모르는 경우,  시작하기 전에  파이썬 생각하기 : 컴퓨터 과학자처럼 생각하 를 일어보자. 속도가 올라갈 것이다

이제 토​​끼와 오소리 사이의 전쟁으로 뛰어들어가자.


시작하기 : 파이썬 설치하기

Windows PC에서이 자습서를 시도하려는 경우 파이썬 을 설치해야 한다. 3.3 버전이 아니리 2.7.3 버전을 설치한다.  설치프로그램 실행  후 IDLE 는 프로그램 폴더의 시작 메뉴에 나와야 한다.  IDLE를  시작한다.


올바르게 되었다면, 다음과 같이 나타난다 :


Python 2.7.3 (v2.7.3:70274d53c1dd, Apr  9 2012, 20:52:43) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>


파이썬이 잘 작동하는지 테스트하려면 파이썬 프롬프트에  print 1 +1 을 치고 Enter 키를 누른다.  2를 인쇄한다. 첫 번째 파이썬 프로그램을 작성한것이다!


파이썬이 제대로 작동하고 이제  파이썬을 사용하여 게임을 작성하기 위해 파이게임(pygame)을 설치해야 한다.

파이 게임은 아주  쉽게 게임을 작성하게 파이썬 라이브러리다!  이미지 처리 와  쉽게 게임에 통합 할 수있는 사운드 재생 같은 기능을 제공한다.


여기에  시스템에 적합한 파이게임 설치 프로그램을 다운로드 한다. 파이썬 2.7 버전을 다운로드해야한다.


파이 게임이 제대로 설치되어 있는지 확인하려면  파이썬 IDLE 실행하거나 파이썬 프롬프트에서 다음과 같이 타이핑하여 아무것도 출력하지 않으면 일이 잘 된 것이다. 

반면에 아래 오류같은 것을 출력하면 파이 게임이 제대로 설치되어 있지 않은 것이다.


Python 2.7.2 (default, Jun 20 2012, 16:23:33) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pygame
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named pygame
>>>


이 같은 오류가 발생하는 경우, 포럼에 게시하면 도움을 얻을 수 있을 수 있을 것이다.


파일에서 파이썬 코드를 실행

파이썬 프롬프트에서 매번 짧은 파이썬 코드를 실행해도 되지만  파일에 코드를 저장하면 큰 프로그램 (게임 등)을 돌리는 경우  매번 입력 할 필요가 없다.

파일로 파이썬 프로그램을 실행하는 방법은 여러 가지가 있다. 한 가지 방법은 노트패드 (윈도우) 같은  텍스트 편집기를 사용하는 것이다.새 텍스트 파일에   파이썬 코드를  입력하고 (print 1 +1 같은). 다른 이름으로 저장 XXX.py (XXX은  파일 이름) 한다.

그런 다음 Windows에서  실행하려는 파일을 더블 클릭한다. 

다른 방법은이 튜토리얼에서 하려는 것처럼 IDLE 편집기를 사용하여 코드를 입력하는 것이다. 이렇게 하려면  IDLE 메뉴에서 NewWindow를 선택하고 파이썬 코드를 입력 할 수있는 텍스트 편집기 창을 연다. 파일의 코드의 변경 사항을 Save로 통해 코드를 저장하고  Run Module (F5)로  실행란다.

편집기 창에 열려있는 파일이 있을때만 Run메뉴를 사용할 수 있다.


게임 리소스 추가




화일을 다운로드했으면  게임의 폴더를 만들고 리소스 폴더를 그 언애 만들고 이름을 resources 로 하자. 그  안에 다양한 자료들이 몇개의 폴더를 만들면서 들어간다:


이제 게임을 만들 준비가 거의 다 된 것이다. 하지만  멋진 그래픽과 음향 효과가없는 게임이라면?  ZIP 아카이브로 게임에 필요한 모든 그래픽과 사운드 효과를 함께 넣었다.  그것을  여기에  다운로드 할 수 있다.

일단 파일을 다운로드 하고 하드 디스크에 게임 폴더를 만들고 게임 폴더가 Resource라는 하위 폴더를 갖도록 만든다 :

자원


이제 토끼와 오소리 만들기를 시작할 준비가 된 것이다. :]


Step 1: Hello Bunny

IDLE 를 실행하고 새로운 텍스트 에디터 윈도우를 열어 다음 코드를 에디터 창에 입력한다:


# 1 - Import library
import pygame
from pygame.locals import *
 
# 2 - Initialize the game
pygame.init()
width, height = 640, 480
screen=pygame.display.set_mode((width, height))
 
# 3 - Load images
player = pygame.image.load("resources/images/dude.png")
 
# 4 - keep looping through
while 1:
    # 5 - clear the screen before drawing it again
    screen.fill(0)
    # 6 - draw the screen elements
    screen.blit(player, (100,100))
    # 7 - update the screen
    pygame.display.flip()
    # 8 - loop through the events
    for event in pygame.event.get():
        # check if the event is the X button 
        if event.type==pygame.QUIT:
            # if it is quit the game
            pygame.quit() 
            exit(0)


이제 이 화일을 게임폴더에 저장하고 이름을 game.py 라고 하자.

이제 코드를 섹션별로 진행하자.


  1.  PyGame library를 가져온다. 라이브러리의 기능을 프로그램에서 사용할수 있게한다.
  2. PyGame 을 초기화하고 디스플레이 창을 설정한다. 
  3. 토끼에 사용할 이미지를 로드한다.
  4. 이제 다음과 같은 코드들을 루프로 돌린다
  5. Note: Where other languages like Objective-C, Java or PHP use curly braces to show a block of code to be executed within a while loop or an if statement, Python uses indenting to identify code blocks. So proper indentation is very important in Python – keep that in mind. :]

  6. 무엇을 그리기 전에 화면을 검은색으로 칠한다.
  7. 토끼의 이미지를 화면위치 x=100 and y=100 에 놓는다.
  8. 화면 업데이트.
  9. 만약 빠져나가는 명령에 해당하는 이벤트가 있으면 프로그램에서 빠져 나온다
  10. Note: According to the PyGame documentation, you shouldn’t need to call pygame.quit() since the interpreter will automatically call it when the interpreter shuts down. However, at least on Mac OS, the game would hang on exit unless pygame.quit() was called.


이코드를 돌리면  (via Run\Run Module in the Idle menu) 아래에 보이는 것과 같은 스크린을 볼 수 있어야 한다.


화면에 토끼가 나오고 이제 무언가 돌아갈 준비가 된거다!

하지만 게임은 검은 화면에 토끼만 덜렁 남아 무섭기도 하니 화면에 조금 예쁜 것들을 그려넣을 때이다:]


2 단계 : 풍경 추가

게임 장면에 배경을 추가하여 시작하자.  몇 번의 screen.blit () 호출로 가능하다.


game.py (화면 높이와 너비를 설정 한 후) 섹션 # 2의 끝에 다음 코드를 추가하자   :


grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")


이제 이미지를로드하고 특정 변수에 저장한다. 이들은 화면에 그릴 수 있다. 당신은 잔디(grass) 이미지를 체크한다면, 잔디 이미지가  640 X 480인  화면 전체 영역을 커버하지 않는다는 것을 알 수 있다. 이것은 당신이  잔디를  화면영역을 완전히 커버하는 타일처리해야 한다는 것을 의미한다.

다음 코드를 game.py (플레이어가 화면에 그려지기 전) 섹션 # 6의 시작 부분에  추가한다:


    for x in range(width/grass.get_width()+1):
        for y in range(height/grass.get_height()+1):
            screen.blit(grass,(x*100,y*100))
    screen.blit(castle,(0,30))
    screen.blit(castle,(0,135))
    screen.blit(castle,(0,240))
    screen.blit(castle,(0,345 ))


보이는 것처럼 for 문은 x 축으로 루프를 돌고 그 for 루프안에서 y 축으로 루프를 돌아 결국 잔디는 x y  값으로 만들어진 for 루프에서 그려지는 것이다. 

그 다음 몇줄은 성을 그리는것이다.


프로그램을 지금 돌려보면 다음과 비슷하게 보여야 한다:


훨씬 낫다! 이제 좋아보이기 시작한다:]


Step 3: Make the Bunny Move

다음 작업은 토끼가 키 입력에 반응하는 것처럼 몇 가지 실제 게임 플레이 요소를 추가하는 것이다.

어떤 키가 특정 순간에 눌리고 있는가를  추적하는 좋은 방법을 구현한다.   간단히  게임에 사용할 각 키의 상태를 유지하는 키 상태의 어레이를  만들면 된다.

game.py 섹션 # 2의 끝에 (화면 높이와 너비를 설정 한 후)  다음 코드를 더한다 :


keys = [False, False, False, False]
playerpos=[100,100]


코드는 그 자체가 설명이다.  키들의 어레이는 키들이 눌려진 상태를 따라간다. WASD다. 어레이의 아이템들은 키와 연관되어 있다. 첫번째가 w 그 다음이 a 인 식이다. 


 playerpos 변수는 프로그램이 플레이어를 그릴 위치에 대한 변수이다. 게임이 플레이어를 다은 위치로 움직이기 때문에 플레이어의 위치를 기억하는 변수에 맞추어 플레이어를 그리는 편이 쉽다.

 

이제  playerpos 변수를 사용하여 플레이어를 그리도록 기존의 코드를 고쳐보자. 섹션 #6의  라인 :

    screen.blit(player, (100,100))

을 다음과 같이 바꾼다 :

    screen.blit(player, playerpos)

그 다음은 키들의 어레이 값을 어떤 키가 눌려지느냐에 따라 변경한다. Pygame은 event.key 함수를 사용하여 이 작업을 쉽게 해준다. 


섹션 #8의 끝에  event.type==pygame.QUIT 의 바로 뒤에 다음의 코드를 집어넣는다,(at the same indentation level as the pygame.QUIT if block):

   

        if event.type == pygame.KEYDOWN:
            if event.key==K_w:
                keys[0]=True
            elif event.key==K_a:
                keys[1]=True
            elif event.key==K_s:
                keys[2]=True
            elif event.key==K_d:
                keys[3]=True
        if event.type == pygame.KEYUP:
            if event.key==pygame.K_w:
                keys[0]=False
            elif event.key==pygame.K_a:
                keys[1]=False
            elif event.key==pygame.K_s:
                keys[2]=False
            elif event.key==pygame.K_d:
                keys[3]=False


와 이제 코드는 제법 길어졌더,  if문을 차근히 읽어보면 그다지 복잡하지 않다.

처음에 체크하는 것은 키를 누르거나 떼는 것이다. 그 다음은 어떤 키가 눌리거나 풀리거나를 체크한다. 만약 이 키가 사용하는 키라면 해당하는 키의 변수값을 업데이트한다. 


끝으로 키를 누르는 일에 반응하여 playerpos 변수를 변경하는 것이다. 이일은 아주 간단하다. 다음의 코드를 gmae.py에 더한다 (with one indentation level, putting it at the same level as the for loop):


    # 9 - Move player
    if keys[0]:
        playerpos[1]-=5
    elif keys[2]:
        playerpos[1]+=5
    if keys[1]:
        playerpos[0]-=5
    elif keys[3]:
        playerpos[0]+=5


이 코드는 단순히 어떤 키가 눌리거나 떨어지는 가를 체크하여 플레이어의 x y 값을 더하고 빼서 이동시키는 일을 한다. 


게임을 돌리면 풀레이어는 이전의 그림과 같다. WASD 키를 눌러보면 .. 그렇다! 동작한다. 




Step 4: Turning the Bunny


그렇다. 토끼는 이제 키를 누르면 이동하지만 마우스로 토끼를 돌려서 방향을 바꿀 수 있게 하면 더 쿨할 것이다. 맨날 같은 방향만 향하는 것보다.  삼각법을 이용하면 간단한 일이다.


다음 그림을 보자:



위의 그림에서 (5,3) 이 토끼의 위치이고 (2,4) 가 마우스의 현재 위치라면 회전각 z 는 두점간의 거리차를 이용하여 삼각함수 atan2를 적용하여 알아낼 수 있다. 물론 회전각을 알면 토끼를 간단히 회전시킬 수 있다. :]


이부분에서 조금 혼란이 와도 걱정할 것은 없다- 어쨌든 진행핳 수 있으니까.  하지만 수학시간을 잘 들어두어야 하는이유이기도 하다 :]  이 부분은 게임프로그래밍에서 계속 사용하게 될 것이다.

이제 이 개념을 게임에 적용해보자.  그러려면 pygame의 Surface.rotate(degrees) 함수를 사용할 수 있다. Z 값이 라디안으로 나타난다는 것에 주의하자 :[

 

atan2함수는 파이선의 math 라이브러리에 있으니 먼저 섹션 #1의 끝에 다음과 같이 추가하자:

import math


그다음 섹션 #6의 마지막 줄 (the player.blit line)을 다음과 같은 코드로 바꾼다:


    # 6.1 - Set player position and rotation
    position = pygame.mouse.get_pos()
    angle = math.atan2(position[1]-(playerpos[1]+32),position[0]-(playerpos[0]+26))
    playerrot = pygame.transform.rotate(player, 360-angle*57.29)
    playerpos1 = (playerpos[0]-playerrot.get_rect().width/2, playerpos[1]-playerrot.get_rect().height/2)
    screen.blit(playerrot, playerpos1)


이제 코드의 기본적 구조를 보자. 첫번째로 마우스와 플레이어으ㅏ 위치를 얻고 그 다음에 이 값들을 atan2 함수에 준다.


그 다음  atan2 함수로부터의 값을 각도로 바꾼다.(라디안에  57.29 나 360/2π를 곱한다).


토끼가 회전하면 위치가 바뀌게 된다. 이제 새로운 토끼의 위치를 계산하여 회면에 그린다. 


게임을 다시 돌려보자. wasd를 사용하면 앞의 경우와 같지만 마우스를 움직이면 토끼는 회전한다. 쿨!

Step 5: Shoot, Bunny, Shoot!


이제 토끼가 회전할수 있으니 동작 몇개를 더해 보자 :] 토끼가 화살을 쏘게하면 어떨까. 얌전하기만 한 토끼가 아닌 것이다!


이 단계는 화살을 따라다니고 , 위치를 갱신하고 , 회전하고 화면을 벗어나면 지워야 하는 이유로 간단하지 않다.

우선 섹션 #2의 초기화 부분의 끝에 필요한 변수들을 추가하자:


acc=[0,0]
arrows=[]


처음 변수는 플레이어의 명중률을 두번째 변수는 모든 화살들의 추적하기 위한 것이다. accuracy 변수는 쏜 숫자로 맞은 너구리의 수를 나눈 것이다. 나중에 이 정보는 명중륳을 계산하는데 사용한다. 


다음에 섹션 #3의 끝에서 화살의 그림자를 로드하자:


arrow = pygame.image.load("resources/images/bullet.png")


이제 사용자가 마우스를 클릭하면 화살이 발사 되어야 한다. 섹션 #8의 끝에 다음과 같은 새로운 이벤트 핸들러를 추가한다.


        if event.type==pygame.MOUSEBUTTONDOWN:
            position=pygame.mouse.get_pos()
            acc[1]+=1
            arrows.append([math.atan2(position[1]-(playerpos1[1]+32),position[0]-(playerpos1[0]+26)),playerpos1[0]+32,playerpos1[1]+32])

이 코드는 마우스가 클릭되었나를 체크하고 그렇다면 마우스의 위치를 가져와 화살의 회전방향을 커서의 위치와 플레이어의 회전방향을 바탕으로 계산한다. 이  회전값은 arrows에 저장된다.


다음으로 화살을 화면에 실제로 그려야 한다. 다음 코드를 섹션 #6.1 다음에 추가한다:


    # 6.2 - Draw arrows
    for bullet in arrows:
        index=0
        velx=math.cos(bullet[0])*10
        vely=math.sin(bullet[0])*10
        bullet[1]+=velx
        bullet[2]+=vely
        if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
            arrows.pop(index)
        index+=1
        for projectile in arrows:
            arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
            screen.blit(arrow1, (projectile[1], projectile[2]))


vely 와 velx 값은 기본적이 삼각법으로 계산한다. 10은 화살의 속도이고 if뭉능 화살이 화면 경계를 지나갔는가를 계산하는 것이고 그렇다면 지운다. 두번째의 for  문은 arrows 변수로 루프를 돌려 화면에 정확히 회전된 그림을 그려낸다. 


프로그램을 고치고 돌려보면  마우스를 클릭할때 화살을 쏘는 토끼를 보게된다! :D




Step 6: Take Up Arms! Badgers!

 이제 성과 움직이면서 화살을 쏠 수 있는 영웅도 있다. 빠진 것은? 우리의 영웅이 쏘아 맞출 수 있는 성을 공격하는 적이다!

이 단계에서 무작위로 나타나서 성으로 달려오는 오소리를 만들어야 한다.  게임이 진행될 수록 점점 더 많은 오소리가 필요해진다.  그러면 여기 필요한 리스트를 만들어보자.


1.  나쁜넘들을 리스트에 넣은 어레이에 넣는다.

2.  나쁜넘들의 어레이를 각 프레임마다 업데이트하고 화면을 벗어나는지 체크한다.

3. 나쁜 넘들을 표시한다.

쉽다. 안그런가? :]


우선 다음 코드를 섹션#2의 끝에 첨가한다:

badtimer=100
badtimer1=0
badguys=[[640,100]]
healthvalue=194

위에 나온 코드는 타이머(다른 값들도)를 설정하여  게임에서 어떤 시간이 경과하면 새로운 너무리를 추가한다.  badtimer를  매 프레임마다 0이 될때까지 줄이면 새로운 너구리가 나타난다.

 

이제 다음 코드를 섹션 #3 끝에 추가한다:

badguyimg1 = pygame.image.load("resources/images/badguy.png")
badguyimg=badguyimg1


첫번째줄은 예전의 이미지 로딩코드와 비슷하다. 두번째줄은 이미지의 복사본을 만들어 나쁜넘들을 애니메이트 하기 쉽게 만들수 있게 한다.

다음에 악당들을 보이고 움직이게 만들기 위해 다음 코드를 섹션 #6.2에 추가한다:

    # 6.3 - Draw badgers
    if badtimer==0:
        badguys.append([640, random.randint(50,430)])
        badtimer=100-(badtimer1*2)
        if badtimer1>=35:
            badtimer1=35
        else:
            badtimer1+=5
    index=0
    for badguy in badguys:
        if badguy[0]<-64:
            badguys.pop(index)
        badguy[0]-=7
        index+=1
    for badguy in badguys:
        screen.blit(badguyimg, badguy)


코드들이 많다. :] 첫본째 라인은  badtimer가  0 인지 체크하고 만약 그렇다면 너구리를 만들고 지금까지 얼마나  badtimer가 수행되었는가에 따라  badtimer를 다시 설정한다. 첫번쨰 루프는 너구리의 x 위치를 갱신하고 너구리가 스크린을 벗어났으면 없애버린다. 두번째 루프는 너구리의 모든 것을 그리는 것이다.

랜덤함수를 사용하려면 rnadom 라이브러리르를 import해야 한다. 그래서 다음과 같은 코드를 섹션 #1의 끝에 추가한다:


import random


그리고 while문(섹션 #4)의 마지막에  각 프레임마다  badtimer를 줄이는 코드를 한줄 더하자:


badtimer-=1


게임을 실행시켜서 이 코드들을 모두 시도해보자. 이제  정말 게임플레이 화면을 볼수 있을 것이다. 쏘고 움직이며 돌고 너구리가 달려온다.


그러나 너구리는 왜 성에서 폭발하지 않는가? 재빨리 코드를 더해보자.

이 코드를  섹션 #6.3  첫번째 루프의첫부분의 index+=1 바로 앞에 에더하자:


        # 6.3.1 - Attack castle
        badrect=pygame.Rect(badguyimg.get_rect())
        badrect.top=badguy[1]
        badrect.left=badguy[0]
        if badrect.left<64:
            healthvalue -= random.randint(5,20)
            badguys.pop(index)
        # 6.3.3 - Next bad guy


코드는 상당히 단순하다. 만약 너구리의 x값이 64보다 적으면 악당을 지우고 게임의 헬스값을  5-20 사이의 무작위 값으로 감소시킨다. (나중에 헬스값을 스크린에서 보게 될 것이다,)

이제 프로그램을 빌드하고 실행시키면 이제 한무더기의 공격하는 너구리가 성에 부딪히면서 없어지는 것을 볼 수 있을 것이다.  그리고 보이지는 않지만 부딪힌 너구리들이 헬스값을 실제로 감소시킬 것이다.




Step 7: Collisions with Badgers and Arrows

너구리들이 성을  공격하지만 화살이 아무 효과가 없다! 바니가 어떻게 집을 지킬 수 있을까?


너구리를 잡고 성을 지키고  게임에서 승리하기 위해 화살을 세팅할 시간이다! 기본적으로 악당들을 모두 루프에서 처리해야 하고  각 루프 안에서 처리해야 한다. 그리고 모든 화살도 루프에서 체크해서 충돌하는 가도 검사해야 한다. 만약 충돌하면 너구리를 지우고 화살도 지우고 정화도를 가산한다.




섹션  #6.3.1의 뒤에 다음 코드를 더한다.

        #6.3.2 - Check for collisions
        index1=0
        for bullet in arrows:
            bullrect=pygame.Rect(arrow.get_rect())
            bullrect.left=bullet[1]
            bullrect.top=bullet[2]
            if badrect.colliderect(bullrect):
                acc[0]+=1
                badguys.pop(index)
                arrows.pop(index1)
            index1+=1


이 코드에서 중요한 내용이 있다. if 문의 Pygame 내장함수로 두 사각형이 겹치는 가를 조사한다. 나머지 줄들은 설명한 내용과 같다.


이제 프로그램을 돌리면 화살을 쏘아 너구리를 잡을 수 있게 된다.



Step 8: Add a HUD with Health Meter and Clock


게임의 진도는 아주 잘나간다. 공격자와 방어자가 있다, 이제 스코어와 바니가 하는 일을 보여주는 방법이 필요하다.  

가장 간단한 방법은 성의 현재 헬스레벨을 보여주는 HUD (Heads Up Display) 를 더하는 것이다.  시계를 더하면 성이 얼마나 오래 살아 남는가를 보여줄 수 있다.

처음에는 시계를 더하자. 다름 코드를 섹션 #7 바로 앞에 붙인다:


    # 6.4 - Draw clock
    font = pygame.font.Font(None, 24)
    survivedtext = font.render(str((90000-pygame.time.get_ticks())/60000)+":"+str((90000-pygame.time.get_ticks())/1000%60).zfill(2), True, (0,0,0))
    textRect = survivedtext.get_rect()
    textRect.topright=[635,5]
    screen.blit(survivedtext, textRect)


위의 코드는  PyGame 기본 폰트 사이즈 24의 폰트를 만들어낸다, 이 폰트로 판위의 시간을 그리는데  사용한다. 그 다음에 텍스타가 위치를 잡고 화면에 그려진다.

그 다음에 헬스바를 더 한다. 헬스바를 그리기 전에 막대를 위한 이미지를 로드할 필요가 있다. 다음 코드를 섹션 #3 끝에 붙인다. 


healthbar = pygame.image.load("resources/images/healthbar.png")
health = pygame.image.load("resources/images/health.png")


첫번째 붉은 이미지는 전체 헬스 막대를 표시하기 위한 것이고 두번째 녹색 이미지는 현재의 헬스 레벨을 표시하기 위한 것이다.  

이제 다음 코드를 섹션 #6.4 (방금전 덧붙인) 의 바로 뒤에 더하여 스크린에 헬스바를 그린다:


    # 6.5 - Draw health bar
    screen.blit(healthbar, (5,5))
    for health1 in range(healthvalue):
        screen.blit(health, (health1+8,8))

코드는 처음에 모두 붉은색 헬스바를 그린다,  그리고는 성이 얼마나 남아있는가를 반영하는 녹색막대를 그린다.,

만약 프로그램을 빌드하고 돌리면  타이머와 헬스바를 갖게된다.


Step 9: Win or Lose

만약에 게임이 오래 진행되어 헬스레벨이 0 이되어도 진행되다면 !  그뿐만이 아니라 너구리를 계속 쏠 수 있다면 .. 이것은 아니다.  게임이 놀 가치가 있으려면 승과 패의 시나리오가 필요하다.

그러면 이제 승패의 시나리오와 스크린을 더해보자 :]  이는 메인 루프에서 벗어나서 승/패의 루프로 들어가면 된다. 승/패의 루프에서는 유저가 진건지 이긴건지 판단하여 스크린에 표시해야 한다.


다음에 승/패의 기본적인 요약이 있다:

게임이 90초를 넘어 시간이 되면:


  • 게임을 중지하고
  • 게임의 결과값을 1로 만들거나 승리로

만약 성이 부서지면

  • 게임을 중지하고
  • 게임의 결과값을 0로 만들거나 패배로


정확도를 다음과 같은 방법으로 계산한다.  (acc[0]을 float 로 만드는 거다.)

Note: The acc[0]*1.0 is just converting acc[0] to a float. If you do not do this, the division operand will return an integer like 1 or 2 instead of a float like 1.5

다음 줄을  game.py 끝에 첨가한다:

    #10 - Win/Lose check
    if pygame.time.get_ticks()>=90000:
        running=0
        exitcode=1
    if healthvalue<=0:
        running=0
        exitcode=0
    if acc[1]!=0:
        accuracy=acc[0]*1.0/acc[1]*100
    else:
        accuracy=0
# 11 - Win/lose display        
if exitcode==0:
    pygame.font.init()
    font = pygame.font.Font(None, 24)
    text = font.render("Accuracy: "+str(accuracy)+"%", True, (255,0,0))
    textRect = text.get_rect()
    textRect.centerx = screen.get_rect().centerx
    textRect.centery = screen.get_rect().centery+24
    screen.blit(gameover, (0,0))
    screen.blit(text, textRect)
else:
    pygame.font.init()
    font = pygame.font.Font(None, 24)
    text = font.render("Accuracy: "+str(accuracy)+"%", True, (0,255,0))
    textRect = text.get_rect()
    textRect.centerx = screen.get_rect().centerx
    textRect.centery = screen.get_rect().centery+24
    screen.blit(youwin, (0,0))
    screen.blit(text, textRect)
while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)
    pygame.display.flip()


지금까지 나온 것중에 가장 길지만 복잡한 것은 아니다.

첫번째 if 문은 시간이 다되었는 가를 체크한다.

두번째는 성이 부숴졌나를 체크한다. 

세번째는 정확도 비를 계산한다.

그 다음에 if 문은 이겼는지 졌는지를 판단하고 적절한 이미지를 표시한다.


물론 승리나 패배의 이미지를 표시하려면 이미지가 미리 로드되어야 한다. 그래서 다음코드를 섹션#3 끝에 첨가한다: 


gameover = pygame.image.load("resources/images/gameover.png")
youwin = pygame.image.load("resources/images/youwin.png")

그리고 섹션#4 를 다음 코드에서:

# 4 - keep looping through
while 1:
    badtimer-=1

아래와 같은 코드로 고친다:

# 4 - keep looping through
running = 1
exitcode = 0
while running:
    badtimer-=1


실행 변수는 게임이 끝났는지 체크하고 탕충코드 변수는 게이머가 이겼는지 졌는가를 알려준다.


게임을 다시 돌리면 승리할 수도 있고 죽을 수도 있다. 한번 해보시도록  ! Cool. :]

Step 10: Gratuitous Music and Sound Effects!


게임은 모양이 좋지만 소리는? 아마 너무 조용하지 않은가? 약간의 소리효과를 더하면 게임의 전체적 느낌을 바꿀 수 있다.

PyGame 은 소리를 너무나 간단하게 로드하여 들려줄 수 있다. 첫째로 믹서를 초기화하는 것이고 다음 코드를 섹션 #2에 더한다.


pygame.mixer.init()

그 다음 소리를 로드하고 볼륨레벨을 정한다. 코드는 섹션3 뒤에.


# 3.1 - Load audio
hit = pygame.mixer.Sound("resources/audio/explode.wav")
enemy = pygame.mixer.Sound("resources/audio/enemy.wav")
shoot = pygame.mixer.Sound("resources/audio/shoot.wav")
hit.set_volume(0.05)
enemy.set_volume(0.05)
shoot.set_volume(0.05)
pygame.mixer.music.load('resources/audio/moonlight.wav')
pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.set_volume(0.25)


위의 코드 대부분은 단순리 오디오 파일을 로드하고 볼륨레벨은 설정하는 것이다. 그러나  pygame.mixer.music.load줄에 주의하자. 이 줄은 게임의 백그라운드 음악을 로드하고 다음 줄은 음악을 언제까지나 반복시킨다.


오디오의 설정에는 주의 해야 한다 ;] 이제 필요한 모든 것은 다양한 소리 효과를 필요할 때마다 플레이 하는것이다, 다름의 코드에 나오는 주석처럼 코드를  변경하자:


# section 6.3.1 after if badrect.left<64:
hit.play()
# section 6.3.2 after if badrect.colliderect(bullrect):
enemy.play()
# section 8, after if event.type==pygame.MOUSEBUTTONDOWN:
shoot.play()


이제 게임을 다시 한번 돌려보면 이제 배경음악과 충돌이나 활쏘는 소리가 나올 것이다. 게임은 더 생생한 느낌이 들 것이다 :]


Where To Go From Here?

자랑스러울 것이다:  이제 음악 , 소리효과 , 킬러 토끼 , 가미가제 너구리같은 것으로 만들어진 펀게임을 완성한 것이다. 아까 만들 수 있을 거라고 말했었다!


최종적인 소스 코드는여기서( here) 다운 로드 받을 수 있다.


이 시점에서 게임을 자신의 창작으로 확장해도 좋다.  아니면 자신의 그림으로 창작을 시도할 수도 있고 , 다른 무기나 괴물을 이 게임에 첨가할 수 있다!


만약에 이 설명서에 대한 질문이나  의견이 있다면?  포럼의 토론란에 참가하면 된다.  나는 듣는 것으 좋아한다,



이 글은  Tutorial Team Member인  Julian Meyer가 올린 것이다. 13세의 파이선 개발자다.


저작자 표시
신고
Trackback 4 Comment 1
2014.01.23 16:44

펌)값싼 고기는 어떻게 식탁에 오르나

르몽드디플로마띠끄에 실린 글이다.원문은 http://www.ilemonde.com/news/articleView.html?idxno=2180


값싼 고기는 어떻게 식탁에 오르나
[55호] 2013년 04월 10일 (수) 15:52:22아녜 스티엔  info@ilemonde.com

최근 일부 유명 브랜드의 식품에서 소고기 대신 말고기를 사용해 파문이 일었다. 이 사건으로 인해 세계 농식품 산업의 복잡다단한 층위가 세상에 드러났다. 신흥국의 급격한 수요 상승에 따라 고기 생산 체계는 점차 제조업의 세계적 공급망이 움직이는 방식을 닮아간다.

식품 스캔들에는 매번 같은 시나리오가 반복된다. 정치권은 꾸짖고 업계와 대형 유통업계는 우는 소리를 한다. 그리고 일치단결해 다시 나오는 투명성, 이력추적제, 인증제. 소리 높여 발표되고 수없이 듣던 조처들이다. 그러나 결국 이전과 같은 양상을 더욱 잘 지속시키기 위함이다. 그 이유를 알려면 사안을 보는 초점을 넓혀야 한다. '소고기'로 속을 채운 라자냐의 라벨에서 한창 새판짜기에 돌입한 세계 농업 구조의 추이와 맥락으로 시선을 옮겨야 한다. 새로운 농업 구조는 오직 한 가지 목적을 위한 것이다. 대규모 수출을 위해 특화 거점을 만들어 대량생산을 하는 것이다. 서유럽 국가는 국내 소비를 위해 소고기와 돼지고기를 수입하거나 기타 유럽 국가에 수출한다. 신흥국가의 경제성장과 함께 고기 수요는 증가했고, 따라서 축산업을 위한 농지 필요도 증가했다.

  
대량 축산업의 폐해: 축산업이 숲을 이용하게 되면 수질 오염, 초지 파괴, 약초재배업의 종말 등 아마존에 치명적이고 파괴적인 결과를 야기한다.

소고기 1㎏을 위해 곡물 7㎏ 필요

예를 들어 중국은 연간 1인 육류 소비량이 지난 10년간 55% 증가했다.(1) 최우선적으로 양계 공장의 닭들을 먹이기 위해 남미에서 재배된 콩을 어마어마한 양으로 수입하고, 사람과 가축을 먹이기 위해 아프리카에서 땅을 사들이고 있다(농지 수탈). 한 대륙에서 구매한 원자재는 제2자 대륙에 팔리고, 이어서 제3자 대륙에 다시 수출된다. 농산업은 제조업의 세계적 공급 사슬과 별반 다를 바 없다.

수십 년 전부터 농기업(Agribusiness)은 농촌, 생물 다양성, 토지, 물, 농민뿐 아니라 소비자의 건강을 망치는 방식을 끝없이 고수하고 있다. 지구촌을 제대로 먹여살리지도 못하면서 말이다. 2011년 충분히 먹지 못해 기아에 허덕이는 사람이 10억 명에 달한다. 몇 주 전부터 신랄하게 비판받고 있는 육류 산업은 이 모든 문제를 압축한 결정체이다. 전세계 총생산의 2%에 불과하면서도 전체 온실가스 배출량의 18%를 차지하는 육류 산업은 특히 천연자원과 토지, 농산물을 집어삼키는 주범이다. 사람이 먹기 위해 곡물을 생산하는 것인가, 아니면 소를 살찌우기 위해 생산하는 것인가. 곡물에 비해 육류 생산의 효율이 불균형인 만큼 이런 질문을 던질 수밖에 없다. 소고기 1kg을 살찌우려면 곡물이 최소 7kg 필요하다. 돼지고기 1kg에는 곡물 4kg, 닭고기 1kg에는 곡물 2kg이 필요하다.

목축지는 농지의 68%를 차지하고(그중 25%는 경작이 불가한 황무지), 사료 재배를 위한 면적은 경작 가능한 땅의 35%를 점유한다. 결국 전체적으로 78%의 농지가 축산을 위한 것이다. 별 가치도 없는 육류 생산을 위해 계속되는 농지 수탈은 극빈층 삶에 직접적인 타격을 가한다. 2006년 유엔 식량농업기구가 발간한 연차 보고서는 다음과 같이 경고했다. "축산업을 위한 식량 생산과 수입이 증가 추세다. 가축용 사료의 전체 수입이 빠르게 증가해, 중국의 축산업 성장이 가져올 전세계 곡물 가격의 상승과 식량난이 우려된다." 그 뒤 일어난 일을 우리는 알고 있다. 2008년은 국제 시장에서 원재료 가격이 전례 없이 폭등해 굶주림에 지친 사람들의 폭동이 잦던 해이다.

아마존을 파괴하는 브라질 축산업

당시는 지구촌이 금융위기의 발단으로 힘들 때였다. 이런 비극으로 정치 지도자들은 1차 생필품에 대한 투기를 금지했어야 한다. 그러나 아무 일도 없었다. 곡물 생산 비용은 실제 감소했지만 판매 가격은 계속해서 오르고 있다.(2) 세계은행은 2011년 2월 다음과 같이 경고했다. "세계 식량 가격이 위험한 수준에 도달하고 있어, 전세계 수억 명의 빈곤층에 위협을 가한다. 가격 상승으로 이미 수백만 명이 빈곤층으로 전락하고 있고, 수입의 반 이상을 식량 사는 데 써야 하는 최취약층을 압박하고 있다."(3)

  
농지의 불균형 이용: 목초와 사료 때문에 농지의 78%가 가축을 먹이기 위한 용도로 쓰인다. 일부 통지는 과다 남획 때문에 불모지가 된다.

목축은 흔히 생각하는 소 키우는 형태와 거리가 멀다. 브르타뉴 농촌 길을 지날 때 보듯 사과나무 그늘 아래 한 무리의 소들이 풀을 뜯는 평화로운 광경은 아무 문제가 없다. 그러나 목축 밀도가 높아질수록 생태계에 가하는 피해도 커진다. 지난 몇 년간 극심한 변화를 겪은 것은 남미다. 과밀 방목이 주를 이루면서 남겨진 것은 가축 배변으로 가득 찬 불모지다. 새로운 축우지를 위해 축우업자들은 주저 없이 불법 벌채에 매달린다. 특히 브라질은 불법 벌채가 심각하다. 최고의 소고기·소가죽 생산국이자 수출국인 브라질은 전세계 관련 시장의 30%를 점유하고 있다. 연간 수출되는 소고기 양은 2200만t이다. 주로 러시아와 유럽연합으로 수출된다. 2009년 그린피스가 조사하고 발표한 보고서는, 2억 마리는 족히 넘는 브라질의 축우업이 아마존 숲 파괴의 80%를 차지하는 주요 원인임을 보여준다.(4) 10년 동안 불에 타 사라진 아마존 숲은 1천만ha에 달한다. 이로 인해 가장 큰 피해를 본 것은 소농민과 원주민들이다. 거대한 '축우업 기계'의 확산으로 이들의 고통은 지금까지 계속되고 있다. 비정부기구 '서바이벌'(Survival)은 40여 년 전부터 축우업자들이 브라질 숲에 사는 인디언들을 학살하는 것을 알리고 있다.(5) 아마존 숲을 파괴하는 데는 두 가지 주요 목적이 있다. 하나는 농산 연료(바이오 연료)의 생산이며, 다른 하나는 축산을 위한 사료 생산이다. 농민운동 단체 '비아 캄펜시나' (Via Campesina)에 따르면 "콩 단작(단일 작물만 재배)이 파라과이 전체 농지의 4분의 1을 차지하고 있다. 브라질은 1995년 이후 콩 재배지가 연간 32만ha가량 늘어나고 있다. 아르헨티나는 이미 농지의 절반이 콩 재배지가 되었고, 농지가 아닌 땅 중 5600만ha가 1996~2006년에 콩을 재배하기 위한 땅으로 경작되었다. 이런 착취가 남미 사람들과 환경에 미치는 파괴적 결과는 여러 단체에 의해 잘 알려져 있다."

동물이라는 개념은 더 이상 없다

화학 기술에 의존한 방식으로 경작되고 수확된 곡물과 기름은 대서양을 건너 대기업의 보관창고로 옮겨진다. 농축 사료로 만들기 위해서다. 이렇게 만들어진 사료는 시멘트로 만든 어두컴컴하고 악취가 진동하는 공장에 갇힌 수백만 마리의 돼지와 닭이 2005년 한 해 12억5천만t을 먹어치웠다.

이 '고기 공장'은 전세계의 가공공장과 슈퍼마켓에 고기를 공급한다. 업자들은 생산부터 유통, 도축, 가공 등 모든 단계를 '합리화'해 비용을 최소화하려 한다. 노동인력을 줄이고 작업을 자동화 및 프로그램화하고 생산품을 표준화하며, 남은 잡고기는 저렴한 밥상을 위한 제품으로 재활용한다. 이 모두가 농기업과 대형 유통이 원하는 요건에 부응하기 위해 만들어진 수작이다.

이제는 더 이상 '동물'이라는 개념조차 없다. 자동차를 조립하듯 원재료에서 소시지를 제조한다. 단, 살아 있고 때때로 고통을 느끼는 '원재료'이다. 하지만 농학 연구의 산물인 이 가축들은 전혀 정상이 아니다. 선별하고 선별해 '제작'된 것이다. 근육 양의 성장 속도는 더욱 빠르고 번식력은 향상되어 있다. 반대로 생존에 중요한 장기는 최소한으로 줄여 더 이상 제 기능을 수행할 수 없을 정도다. 너무 허약해서 질병에 취약하다. 이들을 치료하기 위해 사육하는 건물에는 난방을 하지만 전염병을 피하는 데는 충분치 않다. 그래서 항생제를 자주 사용할 수밖에 없다.

이 축산 방식은 가축 분뇨 및 제거 과정에서 환경문제도 야기한다. 질소와 인이 혼합된 황은 더 이상 흡수할 수 없을 정도로 포화상태인 땅에 살포된다. 오늘날 프랑스의 브르타뉴는 양돈산업으로 인해 수원지의 바닷말류 오염과 연안 녹조류의 확산에 만성적으로 시달리고 있다.

  
경제성장과 고기 수요: 고기 소비 증가는 경제성장과 생활 수준 향상에 동반된다. 따라서 지난 수년간 목축업자들은 신흥국의 새로운 수요에 맞춰야만 했다. 출처: FAO, ‘세계식량농업현황’ (2009년)

파괴하지 않고 지구를 먹여살리기란

전통적으로는 현지에서 생산되는 먹을거리에 따라 가축을 키웠다. 목축은 특히 관심이 필요한 분야다. 가축들이 밟는 것에서 목초가 다시 자랄 수 있도록 보호해야 하고, 토양과 물의 질에 영향을 미치기 때문에 가축 분뇨도 한 군데 집중되지 않도록 막아야 한다. 농장 목축은 곡물 및 채소 재배와 공존하는 방식으로 이루어진다. 콩과 채소 등을 수확하고 남은 풍성한 자투리는 건강하고 균형 잡힌 사료가 된다. 밀짚은 가축 분뇨를 처리한다. 그렇게 얻어진 퇴비는 토양을 기름지게 한다. 완전한 순환 고리를 이룬다.

지구에 부담을 주지 않으면서 지역적으로 건전한 식량을 생산하는 데 관심이 많은 새로운 세대의 농업인들은 이런 옛날 기술에 영감을 받았다. 이들은 연구하고 실험하고 개선하며 이를 현대적으로 변화시켰다. 그중 일부는 산림농업(숲 가꾸기와 농사를 복합적으로 수행하는 농업)에 뛰어들었다. 심은 나무가 바람과 해로부터 밭을 보호한다. 또 나무들은 토양을 비옥하게 하며, 그 뿌리는 물을 담아두어 식물 재배가 잘 이뤄지도록 한다. 이 모두 유엔 식량농업기구(FAO)가 제안하는 방법이다.

*

 / 아녜 스티엔 Agnés Stienne 그래픽 디자이너. 환경문제에 관심이 많으며, 저널리스트로 활동 중이다.

번역 / 박지현 <르몽드 디플로마티크> 한국판 편집위원, 그린피스 해양 캠페이너.

(1) 로마 FAO ‘세계 식량농업현황’ 보고서, 2009. 
(2) 장 지글러, ‘식량, 마지막 투기 은신처’(Quand le riz devient un produit financier), <르몽드 디플로마티크> 2012년 2월호 참고.
(3) ‘식량 가격 상승으로 4400만 명의 인구가 가난의 구렁텅이로 떨어졌다’, 세계은행, 워싱턴, 2011년 2월 15일.
(4) 그린피스 2009년 7월 보고서, ‘아마존 학살: 축우, 아마존 삼림 파괴 확산의 첫 범인’(Slaughtering the Amazone), http://www.greenpeace.org/international/en/publications/reports/slaughtering-the-amazon/).
(5) Survival France, ‘햄버거에서 브라질 인디언까지’, 2010년 1월.
(6) ‘세계은행이 남미 토지의 독점을 부추긴다’, 2011년 7월 7일.


저작자 표시
신고
Trackback 3 Comment 0
2014.01.21 14:24

펌)시간의 경제학-10년 동안 프로그래밍 배우기

예전에 피터 노빅의 글을 보고 썼던 zdnet 컬럼이다. 원래의 링크는 사라졌다.

무슨 일을 하던지 10년은 걸린다는 내용인데 사실이기도 하다.

이글은 번역본을 조금 고치고 싶을 정도다.

아무튼 내가 나의 글을 가지고 있지않고 항상 검색을 한다는게 언제나 황당하기만 하다.


시간의 경제학-10년 동안 프로그래밍 배우기(출처 : ZDNet Korea IT 비지니스)  FreeBoard 

2007/10/05 18:05

복사http://blog.naver.com/virusabum/90022975410

전용뷰어 보기

필자는 요즘 프로그래밍을 다시 배우고 있다. 어떤 광고 문구에 나오는 것처럼 그동안 2% 부족하다고 느끼던 부분들을 손대기 위해서다. 완벽한 것은 없지만 중요하다고 느끼던 부분들이다. 프로그래머 생활을 한 사람으로 컴퓨터 언어로 표현하는 능력에 무엇인가가 부족하다는 것은 좋은 일이 아니다. 표현능력의 부족은 코딩 스타일에 문제가 있다기보다는 프로그래밍을 배우는 과정에 문제가 있거나 문제에 대해 접근하는 방법에 문제가 있을 지도 모르는 것이다. 좀 더 심하게 말하면 생각하는 방법에 문제가 있을 수도 있다. 개인적으로는 중요한 문제다. 그렇다면 신중하게 접근해야 한다. 

일의 발단은 10년 전에 LOGO로 프로그래밍하면서 느꼈던 기묘한 궁금증들을 나중에 생각해보니 상당히 중요한 문제였다는 것을 알게 되면서부터였다. 메시지를 보내는 여러 객체들의 역할을 다루는 actor model과 message passing의 문제였으며 일부는 lambda 함수의 문제이기도 했다. 그때나 지금이나 까다로운 문제다. 다시 붙잡고 보아도 과거보다 이해력이 좋아졌다는 증거는 없었다. 누구나 오래 생각해보던 문제들은 있는 법이다. 필자의 경우는 예전에 만들어보고 싶어 했던 어떤 에이전트를 표현할 수 없던 표현력의 문제를 갖고 있었다. 수학도 그렇고 코딩을 하는 것도 그랬다. 그런데 10년 동안 전혀 변화가 없었다. 

많은 시간을 들인 일이 답 없이 끝날 수 있고 필요한 시간은 1년이 아니라 몇 년이 될 수도 있으며 그동안 많은 일들을 못할 뿐만 아니라 별로 생산성을 내지 못할 수도 있다. 그리고 무엇보다 머리는 자꾸만 더 나빠질 것이 확실하다. 비관적인 결론을 내리면 어떤 문제의 일반화는 1년이 아니라 10년이 걸릴 수도 있다. 다른 중요한 선택들처럼 판돈이 큰 도박이다. 그리고 기다라는 보상은 대박과 같은 것이 아니라 자기만족이다. 어느 정도 좋아서 하지 않으면 안되는 것이다. 

아마추어 프로그래머가 이 정도의 스트레스를 느낄 정도라면 현장에 있는 프로그래머나 관리자의 시간적인 압박은 상당할 것임에 틀림없다. 하지만 현장은 해결할 수 있는 해결책 안에서 고민하는 것이라 압박의 성질이 다르다. 현장은 것은 할 수 있는 일을 열심히 하고 할 수 없으면 포기하거나 운에 따르는 수밖에 없는 곳이다. 현장에서는 쓸데없는 일로 고민하지 않는다. 고민할 시간을 주지 않기 때문이며 이번에 못한 일이라면 다음에 잘 하는 수밖에 없다. 프로젝트만 놓고 보자면 이번에 잘한 팀이 훨씬 유리해지는 게임이다. 물론 생각이나 공부는 그 프로젝트의 시간 안에서 일어난다. (예전의 학생에서 이제는 교수가 된 친구들이 자주 하는 이야기가 있다. 시험을 통과하지 않은 공부는 흔들린다는 것이다. 수업이 중요한 것이 아니라 시험 기간 동안 쌓이는 집중이 기본기를 만든다는 것이다. 다 수긍할 수는 없지만 많은 부분이 사실인 것은 어쩔 수 없다. 현실에서는 더 무서운 시험인 현장의 프로젝트가 있다.)

그러나 아무리 성공적으로 프로젝트를 진행한다고 해도 사람들마다 그 안에서 무언가 중요하다고 생각하던 주제는 반드시 있었을 것이라고 생각한다. 없었다면 그것은 너무나 바빴던 것이 틀림없다. 몇 번의 프로젝트를 진행하고 나면 보통 몇 년의 세월이 흐른다. 하던 일들은 대체로 비슷하기 때문에 문제를 일으키는 어떤 걸림돌 같은 부분이 있다. 개선이나 변혁을 기다리는 요소들이다. 성공적인 프로젝트를 오랜 기간 진행하고 나서도 경험곡선을 상승시킬 그 무엇이 없었다면 역시 무엇인가가 부족한 것임에 분명하다. 그리고 실패한 프로젝트는 원래 배울 것이 많은 것이니 말할 필요도 없다. 성공을 하건 실패를 하건 시간은 흘러간다. 

피터 노빅은 왜 10년이라 했을까?
오랜 기간이 필요하다는 생각이 들자 첫 번째로 떠오르는 생각이 피터 노빅의 글이었다. 노빅은 작년까지 구글의 Search Quality의 책임자였다가 요즘은 연구 책임자로 있다. 구글에 오기 전까지는 NASA AMES의 컴퓨터분과 책임자로 있었다. 인공지능과 머신러닝 분야에서 잘 나가는 연구자이기도 했다. 피터 노빅의 글중에 10년동안 프로그래밍 배우기(Teach Yourself Programming in Ten Years)라는 유명한 에세이가 있다. 우선 제목을 잘 붙였다. “10년 동안 프로그래밍 배우기” 아니면 책방의 책들처럼 “프로그래밍 10년 완성”. 인상적인 제목이다.

10년이면 상당히 긴 세월이다. 단 몇 줄을 읽고 싶지 않아 건너뛰기도 하는 필자와 같은 사람들에게 10년이면 거의 영원에 가까운 세월이다. 그러나 10년은 돌이켜 보면 금방 흐르는 세월이다. 프로그래밍이나 전자공학의 흐름에서 10년은 아주 긴 것 같으면서(많이 변한다.) 덧없이 금방 흘러버리고 마는 시간이다. 만약 이 10년이라는 시간이 잘 사용할 수 있으면, 그리고 성취의 흐름을 10년 정도로 잡는다면 그렇게 조급해 하지는 않아도 될지도 모른다. 만약 시간의 흐름을 1년이나 3년 정도로 잡는다면 약간 조급해 질지도 모른다. 1달이나 몇 개월의 흐름으로 잡는다면 조급해져서 복잡한 일은 할 수 없을 것이다. 세월이 아무리 빨리 흘러도 일들의 진행에는 시간이 필요한 법이다. 프로그래밍을 소화하는 정도가 아니라 밥을 소화하는 데에도 몇 시간이 필요하다. 필자 역시 조급해져서 하던 일을 중간에 팽개친 것이 한두 번이 아니기 때문에 10년이라는 척도를 다시 생각해 보았다.

정말 긴 시간이기는 하지만 어떤 일의 마스터링에는 대략 10년 정도가 걸린다는 것이 노빅의 주장이다. 

글의 시작은 서점에 들어서면 “자바 7일 완성 (Teach Yourself JAVA in 7 days)” 과 비슷한 제목의 인터넷, 윈도우, 비주얼 베이직에 대한 책들이 끝없이 늘어선 것에 대한 비판으로 시작한다. 아마존을 검색해보면 이런 서적이 대부분 컴퓨터분야에 몰려있다는 것이다. 노빅은 이 검색의 결론을 컴퓨터를 배우려는 사람들의 엄청난 붐이 있거나 컴퓨터를 배우는 일이 너무나 쉽기 때문에 그럴지도 모른다고 했다. 물리학이나 베토벤에 대해서는 당연히 며칠 만에 배우기가 없으며 개의 손질법마저도 몇 일만에 배우는 책은 없다고 했다. 이를테면 “3일 동안 Pascal 배우기” 같은 책이 알려줄 수 있는 것은 Pascal과 비슷한 그 무엇이다. 비슷한 언어를 잘 알고 있다고 해도 그 동안에 배울 수 있는 것은 문법정도라는 것이다. 3일이나 일주일 동안에 일어날 수 있는 변화는 그것뿐이다. 인생이 바뀌지도 않는다고 한다.

노빅이 제시한 것은 “10년”이라는 긴 시간이었다. 10년이라는 시간을 잡은 데에는 이유가 있다. 보통 한 분야에서 정통하거나 대가가 되기까지 일반적으로 10년 정도의 세월이 걸린다는 연구 결과를 인용한 것이다. 체스, 음악 작곡, 미술, 피아노, 수영, 테니스, 정신심리학, 위상 수학 기타 다양한 분야에서 전문가가 되기 위해서는 보통 십년 정도가 걸린다는 것이 정설이라는 것이다. 지름길이나 단축코스가 없었다고 한다. 

신동이라 불린 모짜르트도 최고의 음악을 만들기까지 13년 이상이 걸렸다. 비틀즈 역시 비교적 빨리 유명세를 타긴 했지만 훨씬 이전인 1957년부터 작은 클럽에서 활동을 시작했다. 결정적인 작품들은 10년 정도 지난 1967년 Sgt. Peppers에 이르러서야 만들 수 있었다. 그러니 일반적인 사람들 역시 목표의 눈높이는 낮을지 몰라도 어느 정도 정통해지기 까지는 당연히 세월이 필요한 것은 분명하다. 그리고 이 기간 동안 부단히 개선하고 노력해야 한다는 당연한 글을 쓴 것이다. 

노빅의 프로그래밍을 배우는 방법
노빅이 제시한 프로그래밍을 배우는 방법은 아주 간단하다. 

- 프로그래밍에 관심을 가져보고 정말 재미가 있다고 생각해야 10년 정도를 기꺼이 쏟아 부을 수 있다(필자의 생각에 이것은 당연한 것 같다.). 

- 다른 사람의 프로그램을 읽어보고 다른 사람과 이야기해야 하는데 이 과정은 어떤 책이나 교육과정보다 중요하다(다른 사람의 작품을 읽어보지 않으면 당연히 다른 사람에게 읽힐 작품을 쓸 수 없다.).

- 가장 좋은 배우기는 실제로 해보면서 배우는 것이고 이 방법을 더 적극적으로 체계화해야 한다는 것이다. 최고의 성취는 오랜 기간 경험을 쌓으면서 생기는 것이 아니라 노련한 사람의 경우에 있어서도 끊임없는 개선으로 이루어지기 때문이다(이 과정에서 엄청난 에너지가 필요하다는 것을 알고 있다. 버전업과 점진적인 발전 앞에는 장사가 없다.).

- 컴퓨터 학과가 가르쳐주는 것이 전부가 아니며 일을 하면서 배울 수도 있다. 

- 프로젝트를 다양하게 해보면서 어떤 프로젝트에서는 최고의 프로그래머가 되어 다른 사람들을 리드하고 비전을 제시해 보기도 하고 어떤 프로젝트에서는 다른 사람으로부터 지도 받을 필요가 있다(다른 사람에게 무엇인가를 가르쳐보는 것이 최고의 학습이라는 말이 있다.).

- 다른 사람이 이끄는 프로젝트에 참여하여 다른 사람의 프로그램을 이해한 후 원래의 작성자가 놓친 부분을 고쳐보기도 하고 자기의 프로그램을 관리할 다른 사람들이 쉽게 작업할 수 있는 프로그램을 작성하기도 해야 한다(작가의 표현력은 여러 번 고쳐 써 보면서 증가한다고 한다.최고의 글쓰기는 다시 써보기라는 말도 있다.). 

- 다양한 프로그래밍 언어를 배워라(여러가지의 패러다임을 배울 필요가 있다.).

그리고 몇 가지가 더 있다. 

읽다보면 10년 정도의 기간으로 부족할 것 같기도 하다. 10년 동안 이렇게 배우는 것은 10년을 열심히 살라는 이야기와 다를 것이 없어 보인다. 써보고 가르치고 배우고 참여하여 몸으로 체득하는 일을 게을리 하면 안 되는 것이다., 

프로그래밍은 스스로 인지하는 과정에서 배운다
노빅의 주장 가운데에는 몇 가지의 핵심적인 요소가 있다. 책이나 문서라는 것은 스스로 배우거나 사람들에게 배우는 것보다 훨씬 약하다는 사실이다. 때로는 책이나 문서를 읽는 것 보다 그냥 프로그램을 만들고 그 안에 빠져 들어가는 편이 더 낫다는 것이다. 그리고 많은 일들은 일 그 자체를 해나가는 과정이 바로 배우는 과정이라는 사실도 바로 이해할 수 있다. 어떻게 보면 책이나 문서라는 것은 이 과정을 배우는 데 필요한 하나의 주석이라고 볼 수 있다. 결국은 프로그래밍을 배우는 것은 하나의 커다란 인지과정이다. 다른 분야와 다를 것도 없다. 10년이라는 것은 소모되는 세월이기도 하지만 변화에 투입되는 기본적인 자원이다. 

글의 뒷부분에는 노빅 자신의 이야기가 나온다. 노빅은 첫째 아이가 태어날 무렵 수없이 많은 "How to.." 책을 읽었다고 한다. 그러나 정말 어쩔 수 없는 초보자라는 느낌을 지울 수 없었다고 한다. 30 개월이 지나 둘째가 태어날 무렵 노빅은 책을 새로 읽은 것이 아니라 자신의 경험을 믿기로 했다. 그러자 자신의 경험을 바탕으로 하는 일이 전문가가 쓴 수 천 페이지의 책보다 유용하고 더 확실한 것이었다고 한다. 차라리 프로그래머에게 How To가 아니라 How Not To를 가르치는 편이 어떨까하고 이야기한다. 스스로 배운다는 것은 HowTo에 지배되지 않는다는 사실이다. 그래서 어떤 사람들은 잘 할 수 있는 일과 함께 하는 경우에 커다란 능력을 발휘할 수 있다고 한다. 소질을 타고나는 경우도 있다. . 

노빅은 글의 끝머리에서 책방에 가서 책을 사서 읽으면 어떤 유용한 가르침을 줄지는 모르지만 그 것이 며칠이나 몇 달 안에 인생을 변화시키지도 않을 것이고 통달을 가르쳐 주지도 않을 것이라고 말한다. 당연한 말이다. 

필자의 생각은 책의 제목이 Teach Yourself XXX in Ten Years 라고 쓰여 있다고 해도 답은 종잇장에 있는 것이 아니라 문제를 풀어나가는 사람에게 속해있다는 것이다. 실제로 생각하고 풀어보고 시간을 들여서 답을 만드는 사람 자체가 답이며 문제들과 함께 변한다. 꼭 정신수양의 과정처럼 보이지만 이런 것들을 잘 엮어서 생각해보면 답이 나올 것 같기도 하다. 그리고 한편으로는 필자 스스로의 변화에 대한 기대이기도 하다. 기대가 없으면 행동은 나오지 않는다. 

필자의 생각에 이 게임에서 10년 동안 가르치고 배우는 사람은 바로 자신(Yourself)이다

 

 

출처 : ZDNet Korea IT 비지니스

글쓴이 : 안윤호(아마추어 커널해커)


저작자 표시
신고
Trackback 0 Comment 0


티스토리 툴바