DataScience_TeamWork_Platoon1
# 100x100의 맵이 있고, 맵에서의 움직임은 좌,우,위,아래 (대각석 x)로 움직임이 가능하다.
#
# 처음 임의로 설정된 목표
# 처음 (0,0)에 설정된 터틀을 통해서
# 터틀이 목표에 다가가는 것을 위한 게임이다.
#
# 터틀은 사용자가 직접 입력을 통해 이동하고,
# 목표는 사용자의 움직임에 맞게 최대한 잡히지 않도록 이동한다.
#
# 터틀의 이동은 한번에 3개 좌,우,위,아래를 선택할 수 있고
# 목표의 이동은 한번에 2개 좌,우,위,아래를 통해 나타난다.
#
# 처음 이동은 목표부터 시작
# 다음에 터틀의 이동 순으로 진행한다.
#
# 이를 통해 총 5번의 게임이 이루어졌을 때 시도횟수와 사용자이름을 기록하여 이를 정렬하여 보여주어라.turtle 을 통해 100, 100 사이즈의 캔버스를 만들어줍니다.
사용자의 키보드 입력에 따라 좌 우 위 아래로 움직이도록 만들어준다.
def move_right():
if user.xcor() >= 5*scale:
user.setx(5*scale)
return
global tryCount
tryCount -= 1
user.setheading(0)
user.shape("images\packman_0.gif")
global beforemove
beforemove = 0
user.forward(1*scale)
def move_left():
if user.xcor() <= -5*scale:
user.setx(-5 * scale)
return
global tryCount
tryCount -= 1
user.setheading(180)
user.shape("images\packman_180.gif")
global beforemove
beforemove = 180
user.forward(1*scale)
def move_up():
if user.ycor() >= 5*scale:
user.sety(5 * scale)
return
global tryCount
tryCount -= 1
user.setheading(90)
user.shape("images\packman_90.gif")
global beforemove
beforemove = 90
user.forward(1*scale)
def move_down():
if user.ycor() <= -5*scale:
user.sety(-5 * scale)
return
global tryCount
tryCount -= 1
user.setheading(270)
user.shape("images\packman_270.gif")
global beforemove
beforemove = 270
user.forward(1*scale)
screen.listen()
screen.onkeypress(move_right, "Right")
screen.onkeypress(move_left, "Left")
screen.onkeypress(move_up, "Up")
screen.onkeypress(move_down, "Down")목표를 random 값으로 설정한다
target.goto(random.randint(-5, 5)*scale, random.randint(-5,5)*scale)터틀의 기본 생성위치는 0,0 이다.
user.penup()
user.goto(-5*scale, -5*scale)터틀이 목표에 도달하면 게임이 끝난다
if user.distance(target) < 1 or tryCount == 0:
time.sleep(0.3)
user.reset()
screen.reset()
target.reset()
break터틀은 사용자가 직접 입력을 통해 이동
터틀의 이동은 한번에 3개의 좌 우 위 아래
해당 내용은 터틀 회피 알고리즘에 자세히 설명됩니다.
사용자가 이동시마다 trycount 를 변경 (해당 알고리즘에선 감소)하며
3이 추가 or 감소 되었을때 목표를 2회 이동시킨다
if (tryCount+2)%3 == 0 and beforemoved != tryCount:
targetmove()
targetmove()
beforemoved = tryCount
screen.listen()
screen.onkeypress(move_right, "Right")
screen.onkeypress(move_left, "Left")
screen.onkeypress(move_up, "Up")
screen.onkeypress(move_down, "Down")게임의 진행횟수는 5번이며 stage count 를 통해 5회를 count 한다.
while True:
while stagecount < 5:
player = getname().upper()
score = gameturn()
scores.append([player, score])
stagecount += 1
gamesummary(scores)
scores = []
stagecount = 05회에 도달했을경우 score 와, name 을 정렬하여 보여준다
def gamesummary(scores):
scores.sort(key=lambda x: x[1], reverse = True)
print(scores)
fence(False)
texttuetle.clear()
texttuetle.penup()
texttuetle.hideturtle()
texttuetle.color("white")
# t.write("1st : " + scores[0][0] + " score : " + str(scores[0][1]), align="center", font=("Unispace", 15, "normal")) # 디버깅을 위해 하나만 표시
texttuetle.setposition(-3*scale, -1.5 * scale)
texttuetle.color("white")
texttuetle.write("1ST : " + scores[0][0] +
"\n2ND : " + scores[1][0] +
"\n3RD : " + scores[2][0] +
"\n4TH : " + scores[3][0] +
"\n5TH : " + scores[4][0]
, align="left", font=("Unispace", 15, "normal"))
texttuetle.setposition(3*scale, -1.5 * scale)
texttuetle.write( "SCORE : " + str(scores[0][1]) +
"\nSCORE : " + str(scores[1][1]) +
"\nSCORE : " + str(scores[2][1]) +
"\nSCORE : " + str(scores[3][1]) +
"\nSCORE : " + str(scores[4][1])
, align="right", font=("Unispace", 15, "normal"))
texttuetle.color("black")
texttuetle.setposition(0, -7 * scale)
texttuetle.color("white")
texttuetle.write("please go to target to restart", align="center", font=("Unispace", 15, "normal"))- Turtle 모듈을 불러와(import) Screen 객체를 생성합니다.
그 후 setup함수를 사용하여 캔버스를 생성합니다.
- 예시) screen.setup(100,100)
- 키보드 입력은 기본적으로 screen.listen으로 키보드의 입력을 대기시킵니다. 그 다음 onkeypress 함수로 키보드를 누르고 있을 때의 이벤트를 설정합니다.
-
우리가 이동시킬 거북이를 생성하는 것 처럼 목표 거북이 또한 Turtle 모듈을 이용하여 목표(Target)을 생성시킵니다.
target = t.Turtle()
-
이후 shape함수로 모양을 만들어 준 후 speed함수로 스피드를 지정, goto 함수로 랜덤한 좌표 위치를 생성하여 작성합니다.
target.goto(random.randint(-100,100), random.randint(-100, 100))
-
거북이는 생성한 거북이(예시 : turtle, t1…)의backward, forward 함수에 숫자를 인수로 주어 이동시킬 수 있습니다.
turtle.forward(100)
- 거북이는 이동과 비슷하게 left와 right함수에 숫자를 인수로 주어 회전시킬 수 있습니다.
- 예시)turtle.right(30) <거북이를 오른쪽으로 30도 회전
- 거북이가 정해진 울타리 밖으로 나가지 않도록 울타리를 생성해야합니다. 생성한 거북이(예시 : turtle, t1…)의 맨 왼쪽 위부터 시작하도록 하자. 이는 중앙에서 왼쪽 위까지 선이 그려지는 것을 방지합니다.
- turtle.penup()
- 그 다음 거북이를 -100, 100으로 setposition함수를 사용하여 왼쪽 위로 이동합니다.
- turtle**.**setposition(-100, 100)
- 왼쪽 위로 이동하였으면 다시 선을 긋기 위하여 펜을 아래로 내립니다.
- turtle.pendown()
- 임의로 설정된 지역에 목표가 생성되며 플레이어가 이동을 마쳤을 시 목표는 좌, 우 아래, 위방향으로 한 번에 두 번 이동합니다.
- 타겟이 이동할 수 있는 구역은 up, down, right, left 총 4가지 입니다.
- 타겟이 이동 불가능한 구역은 맵의 가장자리 (+_5 * scale ), 사용자 입니다.
- 목표(타겟)의 X좌표와 Y좌표를 다음 코드로 가져와 활용합니다.
x = target.xcor()
y = target.ycor()- 이동할 x, 이동할 y 좌표, 벽까지의 거리 를 기본으로 넣습니다.
up = [x + scale, y, abs(5*scale - (x + scale))]
down = [x - scale, y, abs(-5*scale - (x - scale))]
right = [x, y + scale, abs(5*scale - (y + scale))]
left = [x, y - scale, abs(-5*scale - (y - scale))]
allcase = [up, down, right, left]-
모든 경우의 수 중 불가능한 경우를 제거합니다
- x 및 y 의 좌표가 5scale 을 넘는경우 제거합니다
-
가능한 이동 좌표 에서는 사용자까지의 거리를 피타고라스의 정리를 통해 구합니다
- 이때 사용자와 부딛힐 경우 거리는 0이 됩니다
- 사용자까지x 거리 제곱 + 사용자까지 y 거리 제곱 의 제곱근을 구합니다.
-
구한 값을 사용자까지 거리 순으로 정렬합니다.
- 사용자의 거리가 0일 경우 가장 후순위로 밀리게 되어 사용자에 충돌하지 않습니다.
possablecase = []
for case in allcase:
casetouserx = abs(case[0]-user.xcor())
casetousery = abs(case[1]-user.ycor())
if abs(case[0]) <= 5*scale and abs(case[1]) <= 5*scale:
casetouser = math.sqrt(casetouserx**2 + casetousery**2)
case.append(casetouser)
possablecase.append(case)
possablecase.sort(key=lambda x: x[3], reverse = True)-
0순위 case 의 사용자와의 거리와 같은 값이 발생할 수 있어 해당 값을 분류해줍니다
-
아래의 코드에서는 bestcases 로 해당 값을 넣어줍니다.
-
해당 항목중 벽과의 거리가 먼 항목을 bestcase 로 지정합니다.
-
아래의 그림과 같은경우 벽에서 먼 왼쪽을 선택하게 됩니다.
-
이로써 아래의 사진과 같이 코너에 몰렸을 경우에도 사용자로부터 회피할 수 있도록 합니다.
-
for case in possablecase:
if case[3] == possablecase[0][3]:
case[0]
bestcases.append(case)
print(bestcases)
bestcases.sort(key=lambda x: x[2], reverse = True)
bestcase = bestcases[0]- 이후 bestcase의 좌표로 이동시킵니다.
target.setposition(bestcase[0], bestcase[1])사용자는 상 하 좌 우 모양이 있으며, 입을 벌리고 닫는 동작을 반복합니다.
이떄 onkeypress scan 을 위해 무한 반복되는 구간이 있어 아래의 동작을 수행합니다.
- 해당 동작이 수행하는 시점의 시간을 확인
- 0.3 초 마다 지정된 모양으로 변경 ( 원↔진행방향으로 입벌리기)
while True:
user.clear()
if abs(changedtime - time.time()) > 0.3 and userstat == 1:
user.shape("images\circle.gif")
changedtime = time.time()
userstat = 0
if abs(changedtime - time.time()) > 0.3 and userstat == 0:
if beforemove == 0:
user.shape("images\packman_0.gif")
elif beforemove == 90:
user.shape("images\packman_90.gif")
elif beforemove == 180:
user.shape("images\packman_180.gif")
elif beforemove == 270:
user.shape("images\packman_270.gif")
changedtime = time.time()
userstat = 1
screen.onkeypress(move_right, "Right")
screen.onkeypress(move_left, "Left")
screen.onkeypress(move_up, "Up")
screen.onkeypress(move_down, "Down")유령 모양 테마를 씌워줍니다.
def target():
# 타겟 Shape 추가
t.addshape("images\ghost.gif")
# 타겟 객체 생성
target = t.Turtle()
target.shape("images\ghost.gif")
target.penup()
return target테마에 맞는 검은색 배경을 적용합니다.
def init():
screen = t.Screen() # 스크린 객체 생성
screen.setup(16*scale,16*scale) # 화면의 크기는 지정된 scale 의 16배수 픽셀로 설정합니다.
screen.bgcolor("black") # 배경을 검은색으로 지정합니다.
screen.tracer(2) # 즉각적인 실행 (빠른 반응속도) 를 위해 tracer 을(를) 2로 지정합니다.
return screenUnispace 글꼴을 적용하며 폰트 사이즈를 15픽셀로 적용합니다.
해당 폰트는 윈도우11 이상에서 기본으로 제공합니다.
def showscore():
texttuetle.clear()
texttuetle.penup()
texttuetle.hideturtle()
texttuetle.setposition(-6 * scale, 6 * scale)
texttuetle.color("white")
texttuetle.write("SCORE : " + str(tryCount), align="left", font=("Unispace", 15, "normal"))
texttuetle.setposition(0, 6 * scale)
texttuetle.write("PLAYER : " + player, align="center", font=("Unispace", 15, "normal"))
texttuetle.setposition(6 * scale, 6 * scale)
texttuetle.write("STAGE : " + str(stagecount + 1), align="right", font=("Unispace", 15, "normal"))팩멘 테마에 맞는 파란 2줄의 울타리가 필요하므로, 터틀을 통해 작성해줍니다.
def fence(crossline = True):
# 울타리 그리기
fence = t.Turtle()
fence.penup()
fence.hideturtle()
fence.setposition(-5.5*scale, -5.5*scale)
fence.color("blue")
fence.pendown()
fence.pensize(4)
for x in range(4):
fence.forward(11*scale)
fence.left(90)
fence.penup()
fence.hideturtle()
fence.setposition(-5.7 * scale, -5.7 * scale)
fence.color("blue")
fence.pendown()
fence.pensize(2)
for x in range(4):
fence.forward(11.4 * scale)
fence.left(90)
if crossline:
fence.color("midnightBlue")
fence.pensize(1)
for i in range(10):
fence.penup()
fence.goto(-5.5 * scale, (i - 4.5) * scale)
fence.pendown()
fence.goto(+5.5 * scale, (i - 4.5) * scale)
fence.penup()
for i in range(10):
fence.penup()
fence.goto((i - 4.5) * scale, -5.5 * scale)
fence.pendown()
fence.goto((i - 4.5) * scale, +5.5 * scale)
fence.penup()


