앞과 같은 미로를 통과하기 위해서는, 슬라임이 과거에 어디를 통과했는지에 관한 기억이 필요합니다. 그래서 왔던길로 돌아가지 말아야 하는 것이죠.
내가 어디서 왔는지를 표시하기 위해 슬라임이 수액을 분비한다고 해 봅시다. 슬라임은 이동할 때마다 자신이 있는 위치를 수액으로 흠뻑 적십니다. 슬라임의 이동경로를 따라 수액의 흔적이 남을 겁니다. 이 수액은 시간이 갈수록 조금씩 말라갑니다.
그와 함께 슬라임은 자기 주위의 습기를 알 수 있는 감지기를 가지고 있습니다. 이것으로 자기가 어디서 왔는지 알 수 있겠죠.
이 젖은슬라임을 만들기 위해서는 약간의 변형이 필요합니다. 먼저 미로에 습기를 저장할 수 있도록 해야 합니다.
procedure MazeProcess(slime, maze)
// 슬라임을 출발점에 세움
slime.LocX := 1
slime.LocY := 1
maze.Clear() // 미로 안의 모든 습기 제거
// 미로 안에서 슬라임 움직임
for k := 0, 900 do // 미로 안에서 슬라임이 움직이는 횟수
// 미로가 클수록 커져야 함
// 미로 안의 습기 말리기
for x := 0, 15 do
for y := 0, 15 do
if maze.Wet[x][y] > 0 then
maze.Wet[x][y] := maze.Wet[x][y] - 1
end
end
end
// 슬라임이 수액 분비
maze.Wet[slime.LocX][slime.LocY] := 100
// 어디로 움직일지 생각
movedirect = SlimeThink(slime, maze)
// 이동할 위치
if movedirect == 'E' then
newx := slime.LocX + 1
newy := slime.LocY
elseif movedirect == 'W' then
newx := slime.LocX - 1
newy := slime.LocY
elseif movedirect == 'S' then
newx := slime.LocX
newy := slime.LocY + 1
elseif movedirect == 'N' then
newx := slime.LocX
newy := slime.LocY - 1
end
// 이동한 결과 계산
if maze.IsBlock(newx, newy) then // 블럭에 충돌
slime.Fitness := slime.Fitness - 10 // 적응도 감소
else // 충돌하지 않을 경우
slime.LocX := newx
slime.LocY := newy
slime.Fitness := slime.Fitness - 1 // 적응도 감소
// 목적지에 도착했나?
if maze.IsGoal(slime.LocX, slime.LocY) then
slime.Fitness := slime.Fitness + 1000 // 적응도 대폭 증가
break // for 루프 탈출
end
end
end
end
즉 슬라임이 있는 위치의 습도는 100, 슬라임이 떠난 후 1씩 감소합니다.
function SlimeThink(slime, maze)
// 슬라임 동서남북의 블럭정보 얻기
curstate.detect.EastBlock := maze.IsBlock(slime.LocX + 1, slime.LocY)
curstate.detect.WestBlock := maze.IsBlock(slime.LocX - 1, slime.LocY)
curstate.detect.SouthBlock := maze.IsBlock(slime.LocX, slime.LocY + 1)
curstate.detect.NorthBlock := maze.IsBlock(slime.LocX, slime.LocY - 1)
// 사방의 습기 찾기
curstate.detect.EastWet := maze.WetOrder(slime.LocX + 1, slime.LocY)
curstate.detect.WestWet := maze.WetOrder(slime.LocX - 1, slime.LocY)
curstate.detect.SouthWet := maze.WetOrder(slime.LocX, slime.LocY + 1)
curstate.detect.NorthWet := maze.WetOrder(slime.LocX, slime.LocY - 1)
// 나갈 입구의 방향 찾기
curstate.detect.ExitEast := maze.IsExitEast(slime.LocX, slime.LocY)
curstate.detect.ExitWest := maze.IsExitWest(slime.LocX, slime.LocY)
curstate.detect.ExitSouth := maze.IsExitSouth(slime.LocX, slime.LocY)
curstate.detect.ExitNorth := maze.IsExitNorth(slime.LocX, slime.LocY)
// GeneList(유전자들의 묶음)에서 curstate 찾기
fnd := slimt.GeneList.Find(curstat)
if fnd == nil then // 처음 만나는 상황
// effect부분을 랜덤으로 만듦
for k := 0, 10 do
curstate.effect[k] = Random("EWSN") // EWSN 중에서 하나 선택
end
slime.GeneList.Append(curstate) // 현재 상황 추가
fnd = curstate
end
// 여기까지 해서 fnd에는 현재상황에 맞는 유전자가 들어있음
return fnd.effect[Random(0, 9)]
end
이때 EastWet~NorthWet을 설정하는 데는 각 방향의 습기를 그대로 저장할 수도 있지만, 그렇게 된다면 유전자 수가 너무 많아질 수 있습니다. 동서남북 최대 100단계이니 100000000개 가까이 유전자가 늘어날 수 있죠(물론 불가능한 조합도 있습니다만)
그러므로 여기서는 각 방향의 습기 등수를 가져오도록 했습니다(가장 많이 젖은 곳이 0, 그다음 젖은 순서대로 1, 2, 3). 그 외는 앞의 슬라임과 동일합니다.
9. 젖은 슬라임의 결과
'수액에 젖은' 슬라임으로 100세대를 진화시킨 결과입니다.
그리고 앞의 슬라임이 통과하지 못했던 미로를 통과한 결과입니다.
두 개의 미로 모두 최적의 슬라임이 탄생했습니다. 단, 두개의 미로를 모두 통과할 수 있는 슬라임이 태어난 것은 아닙니다. 첫째 미로를 돌파하는 슬라임을 둘째 미로에 넣는다면 제대로 못찾을 것입니다.
이러한 현상을 막기 위해서는 미로 자체를 변화시켜야겠죠.
댓글 없음:
댓글 쓰기