no image
파이썬 슬랙 챗봇 만들기 Slack Python ChatBot 코드 최신정보
파이썬 웹 크롤링 공부를 하면서 슬랙이라는 플랫폼을 알게되었고 파이썬으로 챗봇을 만들 수 있다는 것을 알게되었다. 이번에 파이썬으로 챗봇을 만들고 채팅오게 하는 방법을 써보려고 한다. 1. Slack 슬랙 회원가입 및 로그인 클라우드 기반의 비즈니스 커뮤니케이션 플랫폼 워크스페이스에서 팀원들과 협업이 가능하고 파일 및 공유가 가능하며 화상 회의도 가능하다 Slack은 생산성 플랫폼입니다 Slack은 팀과 커뮤니케이션할 수 있는 새로운 방법입니다. 이메일보다 빠르고, 더 조직적이며, 훨씬 안전합니다. slack.com 먼저 슬랙 사이트에 들어가서 회원가입 또는 로그인을 해준다. 구글 로그인 혹은 애플 로그인 연동이 가능하다. 이미 로그인된 상태라면 2번으로 넘어가면 된다. 2. Slack 슬랙 워크스페이스..
2023.07.11
no image
반복하지 않는 수, 중복되지 않는 수, 0부터 9까지 순열 만들기 코드
0부터 9까지 총 10개의 숫자로 만들 수 있는 순열의 개수는 8877690개이다. 아래 코드는 반복하지 않는 수를 txt 파일로 저장하는 파이썬 코드이다. from itertools import permutations, chain, islice import math def make_no_repeats(length): my_iter = permutations(range(10), length) no_zero_start_index = math.perm(9, length - 1) no_lead_zeros = islice(my_iter, no_zero_start_index, None) return no_lead_zeros if __name__ == '__main__': my_list = [] iter_no_re..
2023.05.14
no image
[인공지능 학습 노트] 파이썬 UCS 구현 상태 공간 그래프에 대한 균일 비용 탐색 알고리즘
균일 비용 탐색 UCS (Uniform Cost Search) 정의 무정보 탐색 알고리즘의 한 종류, 최소 경로 비용을 기준으로 아직 방문하지 않은 노드를 탐색하는 기법 무정보 탐색이란 상태공간에 대한 아무런 정보 없이 정해진 순서에 따라 진행 하며 얻은 정보만 활용하여 탐색하는 방법 최소 경로 비용이란 우선 UCS에서 경로 비용이란 시작 노드에서 현재 노드까지 발생되는 모든 비용의 합이다. 예를 들면 시작노드 A 노드에서 C 노드로 갈 때 발생하는 비용은 4이다. 그리고 D 노드를 가는데 C 노드를 통해서 가게 되었다면 A -> C -> D 즉 7이다. 노드를 탐색할 때 방문되지 않은 노드의 경로 비용들에서 가장 최소가 되는 노드를 선택하여 탐색하는 방법이 최소 경로 비용을 선택하는 것 즉, 균일 비용..
2023.05.01
no image
BFS, DFS, 최선우선탐색, 휴리스틱 알고리즘, a* 알고리즘 3X3 8퍼즐 공부
퍼즐 맞추기인데 교수님이 억까 코드로 실습하라고 했음... 그래서 일단 억까코드 수정하고 저렇게 만들어봤는데 bfs는 교수님 원본 코드에서 딱히 바뀐건 없고 주석이랑 조건문 위치랑 moves 프린트 수정했고 dfs는 실습이었는데 저렇게 만드는게 맞나 모르겠다.. 일단 무한적으로 탐색하던건 조건문 위치랑 조건 수정해서 고쳐졌고 set으로 중복체킹하는데 시간복잡도 O(1)로 수정함 BFS class State: def __init__(self, board, goal, moves=0): self.board = board self.moves = moves self.goal = goal # i1과 i2를 교환하여서 새로운 상태를 반환한다. def get_new_board(self, i1, i2, moves): n..
2023.03.26
no image
파이썬 학습 노트 기초 (1)
파이썬의 연산자 연산자 뜻 + 더하기 - 빼기 * 곱하기 / 나누기(소수점) ** 제곱 // 몫 % 나머지 () 괄호 안을 먼저 연산 파이썬의 변수 변수 이름 뒤 등호(=)로 값을 저장한다 C언어나 JAVA 처럼 자료형을 지정해주지 않는다 변수 이름은 대/소문자, 숫자, 밑줄로 사용 대소문자는 구분됨 파이썬의 변수 네이밍룰은 소문자로 _ 를 사용하여 구분하여 사용한다고 한다 출력 print(변수), print("hello") def print_hi(name): print("I like", end='') print(" money") if __name__ == '__main__': print_hi('PyCharm') 판단 파이썬의 참 값은 True, 거짓 없은 False ==, !=, , = 와 같은 비교 ..
2023.03.04
no image
네이버 금융 주식 데이터 웹 크롤링 - 일별시세 csv파일에 저장하기
파이썬으로 웹 크롤링 파이썬으로 빅데이터 공부를 하면서 웹 크롤링에 대해 배우게 되었다. 증시 관련 데이터를 크롤링 하려는데 네이버에서 증시 api는 제공하지 않는다. 그래서 html 태그에서 직접 크롤링을 해야했다. from bs4 import BeautifulSoup import requests import pandas as pd from selenium import webdriver import time 밑의 코드들은 위의 라이브러리를 사용한다. 종목 코드 크롤링 주식 데이터를 검색하려면 보통 종목코드를 입력하여 크롤링 하는것이 일반적이다. 하지만 일반 사람들에게는 삼성전자, 구글 이러한 이름이 익숙하기 때문에 먼저 종목 코드 부터 크롤링 할것이다. 크롬 네이버에서 삼성 전자를 검색하고 종목코드가 ..
2022.09.21
no image
[파이썬] 달력 만들기 import turtle 사용 calendar 없이 만들기
우리 학교 파이썬 수업 과제였습니다 ㅋㅋㅋㅋ 정말 한참 수정할게 많지만 나중에 하는걸로 하고 지금은 백업용으로 올립니다. 나름 리스트에 해당 년도 달력을 전부 넣고 싶어서 고민좀 했습니다. WOD.py # 모듈 import turtle import returnday # 터틀 입력창으로 연도 입력 받기 및 터틀 설정 turtle.title("달력 만들기") turtle.hideturtle() turtle.speed(0) inputYear = int(turtle.numinput("달력 만들기", "표시할 달력의 연도를 입력하시오.")) print("%d" % (inputYear)) print() # 터틀 창 테두리 꾸미기 turtle.penup() turtle.pensize(3) turtle.goto(-45..
2019.11.28
no image
[파이썬] 숫자 맞추기 게임 from random import randint
[파이썬] 숫자 맞추기 게임 from random import randint random 모듈로 1부터 100까지 랜덤 숫자를 불러와서 숫자맞추기 게임을 만들었습니다 시험에 나올줄알았는데 안나오누 ## 숫자 맞추기 게임 from random import randint tries = 0 myNumber = 0 correctNumber = randint(1, 100) print("1부터 100사이의 숫자를 맞추시오") while tries correctNumber: print("정답보다 높습니다!"..
2019.10.23
728x90
반응형

파이썬 웹 크롤링 공부를 하면서 슬랙이라는 플랫폼을 알게되었고 파이썬으로 챗봇을 만들 수 있다는 것을 알게되었다.

이번에 파이썬으로 챗봇을 만들고 채팅오게 하는 방법을 써보려고 한다.

 

1. Slack 슬랙 회원가입 및 로그인

클라우드 기반의 비즈니스 커뮤니케이션 플랫폼

워크스페이스에서 팀원들과 협업이 가능하고 파일 및 공유가 가능하며 화상 회의도 가능하다


 

Slack은 생산성 플랫폼입니다

Slack은 팀과 커뮤니케이션할 수 있는 새로운 방법입니다. 이메일보다 빠르고, 더 조직적이며, 훨씬 안전합니다.

slack.com

 

 

먼저 슬랙 사이트에 들어가서 회원가입 또는 로그인을 해준다. 구글 로그인 혹은 애플 로그인 연동이 가능하다.

이미 로그인된 상태라면 2번으로 넘어가면 된다.

 

 

2. Slack 슬랙 워크스페이스 생성

 

팀원들과 채팅, 파일 공유, 화상 회의를 할 수 있는 공간이다.


 

만약 로그인을 하게되면 이러한 화면이 나오는데 워크스페이스 생성 버튼을 눌러서 워크스페이스를 만들어주면 된다.

 

 

Slack 슬랙 워크스페이스는 무료로 만들 수 있다. 위 동의 체크를 하고 워크스페이스 생성 버튼을 누르면된다. 마케팅 소식도 받고 싶으면 체크해도 된다.

 

 

워크스페이스 이름은 원하는대로 사용하려는 의미에 맞게 적고 다음 버튼을 누르면된다. 나는 MyMacroChatBotServer 이걸로 적고 다음 버튼을 눌렀다. 

 

 

그리고 워크스페이스에서 사용할 이름과 프로필 사진을 설정하고 다음 버튼을 누르면 된다. 

 

 

그리고 워크스페이스에 초대할 사람의 이메일을 적고 다음 버튼을 누르거나 "이 단계 건너뛰기"를 눌러서 건너뛰면된다

나중에 다시 초대할 수 있으니 걱정하지말고 넘어가면 된다.

 

 

그리고 뭘또 적으라고 하는데 하고싶은 채널명으로 적으면된다. 나는 해당 채널에 봇을 추가하고 알림을 오게할것이므로

매크로 알림이라고 적고 다음 버튼을 눌렀다. 채널 이름은 아무거나 적어도 상관없다.

 

 

그러면 이렇게 워크스페이스가 만들어진다. 디스코드 서버랑 비슷하게 생겼는데 이제 봇을 만들고 난 다음에 워크스페이스 채널에 추가해보도록 하겠다. 

 

 

3. Slack 슬랙 API 봇 만들기

Slack API로 챗봇을 만들고 권한을 설정해준다.


https://api.slack.com/

 

Slack은 생산성 플랫폼입니다

Slack은 팀과 커뮤니케이션할 수 있는 새로운 방법입니다. 이메일보다 빠르고, 더 조직적이며, 훨씬 안전합니다.

slack.com

 

https://api.slack.com/

 

위 API 사이트로 들어가서 우측 상단에 "Your apps" 글자를 클릭하자.

 

 

그러면 이런 화면으로 오게 되는데 위에 "Create an App" 초록색 버튼을 눌러주자

 

 

그러면 뭔가 선택하는 창이 뜨게 되는데 위에 "From scratch" 로 되어있는 곳을 선택하자.

 

 

그리고 만들려는 봇의 이름과 아까 만들었던 워크스페이스를 선택하고 "Create App" 버튼을 눌러주자 App 이름은 나중에 변경할 수 있다고 한다. 사용하려는 의미에 맞게 설정하는 것이 좋을 것 같다.

 

 

그러면 이런 화면으로 오게 되는데 여기는 기본적인 설정을 하는 곳인데 위 6개 버튼으로 바로갈 수 있다.

그러나 딱히 건드릴건 없고 채팅 권한만 설정해주면 되기 때문에 "Permissions" 버튼을 눌러주자

 

 

그리고 화면을 조금 내리면 Scopes 라는 곳이 보일텐데 여기 "Add an OAuth Scope" 버튼을 누르고 "chat" 이라고 검색을 하면 chat:write 가 나오는데 눌러주자

 

 

그러면 이렇게 상단에 Success 가 뜨면서 적용이 완료된다. 그리고 다시 위로 올라가자

 

 

위로 올라가면 "Install to Workspace" 버튼이 있는데 누르면 된다. 눌러보면

 

 

이런 창이 뜨는데 허용 버튼을 눌러주면 토큰이 생성된다.

 

 

이걸 Copy 버튼을 눌러서 복사해두면 된다.

 

이제 다시 우측 상단에 "Your App" 버튼을 눌러주자

 

 

그러면 이런 화면이 뜨는데 "I Agree" 버튼을 눌러주고 워크스페이스로 다시 가보자

 

 

그런다음 봇을 추가하려는 채널을 마우스 오른쪽 클릭하면 나오는 창에서 "채널 세부정보 보기" 버튼을 클릭한다.

 

 

그리고 "통합" 탭으로 가서 "앱 추가" 버튼을 눌러준다.

 

 

그러면 "워크스페이스에서" 라는 구역이 생기는데 여기에 본인이 만든 봇이 나타날것이다. 추가 버튼을 눌러서 추가해주면

봇생성과 추가가 완료된다.

 

 

이제 파이썬으로 메시지를 보내는 코드를 작성해보자

 

 

4. 파이썬 코드로 Slack 슬랙 챗봇 메시지 보내기 

파이썬으로 Slack 봇 메시지를 보내는 코드를 작성한다.


 

원하는 파이썬 개발 환경으로 시작하면 된다. 나는 VS CODE로 하고 따로 파이썬 가상환경을 만들어서 하고 있다. 파이썬 버전은 3.10.7이다.

 

먼저 Slack API 를 사용하기에 앞서 slack sdk 라이브러리를 추가해준다.

 

pip install slack_sdk

 

 

sdk 라이브러리를 설치했으면 이제 진행하면 된다.

 

# Slack SDK 라이브러리 추가
from slack_sdk import WebClient

# API 인증 토큰키
myToken = '아까 복사 붙여넣었던 토큰키'

# Slack API에 접근하기 위해 토큰을 인자로 클라이언트 객체 생성
client = WebClient(token=myToken) 

# 생성한 클라이언트 객체로 메시지를 전송
client.chat_postMessage(channel='매크로-알림', text='안녕하세요')

 

우선 해당 코드를 복사해서 붙여넣어자 그리고 아까 복사 해뒀던 토큰키를 myToken 변수에 넣고

맨 아래 코드 channel에 자신의 채널 이름을 그대로 적어주자 이 두가지를 꼭 수정하고 실행해야한다.

 

다 수정했으면 실행해보자

 

 

워크스페이스에 봇이 채팅을 쳤고 제대로 채팅이 들어왔다. 제대로 됐는가?

 

코드를 다시보자

 

# Slack SDK 라이브러리 추가
from slack_sdk import WebClient

 

이 코드는 pip 추가 했던 라이브러리를 불러오는 코드이며 꼭 있어야한다.

 

만약 WebClient 말고 다른 것도 쓰려면 그냥 import slack_sdk.WebClient 이렇게 해도 된다. 이럴 경우 아래 코드도 수정해줘야한다.

 

# API 인증 토큰키
myToken = "아까 복사 했던 API 인증 토큰키"

 

만들었던 봇의 인증 토큰키를 설정하는 변수이다. 이름은 아무렇게나 해도된다.

 

# Slack API에 접근하기 위해 토큰을 인자로 클라이언트 객체 생성
client = WebClient(token=myToken)

 

토큰을 매개변수로 넣어서 API에 접근하는 객체를 생성하는 코드이다. post 방식으로 채팅을 보내도 되지만 이 방식이 좀 더 코드로 작성하기에는 간단하다.

 

# 생성한 클라이언트 객체로 메시지를 전송
client.chat_postMessage(channel='작성한 채널 이름', text='안녕하세요')

 

클라이언트 객체를 이용해서 채팅을 보내는 코드이다. channel 인자에는 봇이 들어있는 채널의 이름을 적고

text 인자에는 보낼 메시지 텍스트를 넣으면 된다.

 

이러면 Slack API 를 이용해서 채팅 봇을 만드는 과정은 다 끝났다. 이제 파이썬 코드로 알아서 자신의 상황에 맞게 수정하면 된다. 메서드로 만들어서 매개변수를 적게 작성하는 방법도 한가지 방법일 수 있겠다.

 

챗봇의 사용 용도로는 알림 용도로도 쓸 수 있겠고 진짜 챗봇으로도 쓸 수 있겠는데 일단 챗봇에서 일방적으로 메시지를 보내는 방법을 알아봤다. 나같은 경우에는 일단 사이트 웹크롤링하는 코드를 여러개 돌리고 있는데 오류가 나면 다시 돌려줘야하는데 오류가났는지 매번 확인하기가 힘들기 때문에 이런 매크로 알림 챗봇이 있으면 상당히 편리하다. 다음에 시간나면 상호작용 하는 방법을 알아보고 써보도록하겠다.

 

 

 

 

 

* 번외

참고로 request 라이브러를 추가해서 post 방식으로 채팅을 보내는 방법도 존재한다.

 

# request 라이브러리 추가
import requests

# API 인증 토큰키
myToken = '챗봇 토큰 인증키'

# request post 방식으로 api 호출 
requests.post("https://slack.com/api/chat.postMessage",
        headers={"Authorization": "Bearer " + myToken},
        data={"channel": "챗봇의 채널","text": "안녕하세요"}
    )

 

이 방법은 slack_sdk 라이브러리를 추가하지 않고 request post 방식으로 호출하는 방법이다.

위처럼 토큰과 채널을 수정해서 보내면 된다.

 

headers를 저렇게 하는 이유는 저것이 Slack API의 인증 방법이라고 한다.

 

 

 

728x90
반응형
728x90
반응형

0부터 9까지 총 10개의 숫자로 만들 수 있는 순열의 개수는 8877690개이다.

아래 코드는 반복하지 않는 수를 txt 파일로 저장하는 파이썬 코드이다.

from itertools import permutations, chain, islice
import math


def make_no_repeats(length):
    my_iter = permutations(range(10), length)
    no_zero_start_index = math.perm(9, length - 1)
    no_lead_zeros = islice(my_iter, no_zero_start_index, None)

    return no_lead_zeros


if __name__ == '__main__':
    my_list = []
    iter_no_repeats = chain(*map(make_no_repeats, range(1, 11)))
    while True:
        try:
            my_list.append(int(''.join(map(str, next(iter_no_repeats)))))
        except StopIteration:
            break

    print(len(my_list))
    with open('test.txt', 'w') as f:
        f.write(str(my_list))

 

https://drive.google.com/file/d/1rX3Ohzw39R0q2Iv4AhPJg6swxDdczjDc/view?usp=sharing 

 

반복하지않는수.txt

 

drive.google.com

 

위 링크는 반복하지 않는 수를 txt 파일로 저장한걸 구글 드라이브로 올려뒀다... 이거 그냥 게시글에 복붙하니까 안되서 그냥 심심한김에 올려본다

728x90
반응형
728x90
반응형

균일 비용 탐색 UCS (Uniform Cost Search)

정의

무정보 탐색 알고리즘의 한 종류, 최소 경로 비용을 기준으로 아직 방문하지 않은 노드를 탐색하는 기법

무정보 탐색이란 상태공간에 대한 아무런 정보 없이 정해진 순서에 따라 진행 하며 얻은 정보만 활용하여 탐색하는 방법

 

최소 경로 비용이란

우선 UCS에서 경로 비용이란 시작 노드에서 현재 노드까지 발생되는 모든 비용의 합이다.

예를 들면 시작노드 A 노드에서 C 노드로 갈 때 발생하는 비용은 4이다.

그리고 D 노드를 가는데 C 노드를 통해서 가게 되었다면 A -> C -> D 즉 7이다.

 

노드를 탐색할 때 방문되지 않은 노드의 경로 비용들에서 가장 최소가 되는 노드를 선택하여 탐색하는 방법이

최소 경로 비용을 선택하는 것 즉, 균일 비용 탐색 기법이다.

 

그래프 변환 예시

 

그래프를 탐색하려면 그래프를 트리로 변환해야한다.

그래프를 트리로 변환하는 것은 생각보다 귀찮은데 무방향 그래프라면 더더욱 귀찮아진다.

 

무방향 그래프를 트리로 변환하는 팁은

우리는 이미 시작지점과 도착지점을 알고 있고 그 동안 발생되는 비용을 알고 있다는 점을 이용하는 것이다.

 

우선 시작 노드에서 갈 수 있는 노드를 전부 그려준다 그리고 그 자식들도 모두 그려주는 대신

방문한 노드를 되돌아 가는 경우는 그리지 않는다.

 

즉, A 노드에서 갈 수 있는 노드는 B와 C니까 B와 C 노드를 그려주고 B노드에서 갈 수 있는건 A, C, D, E인데

B는 A노드에서 왔기 때문에 A 노드는 그리지 않고 C, D, E 만 자식으로 그려준다.

그리고 C에서 갈 수 있는 노드는 A, B, D, E인데 A 노드에서 C노드로 갔기 때문에 B, D, E 만그려준다.

 

 

그 다음 자식들을 그리는 기준은 현재 레벨과 상위 레벨에서 같은 이름의 노드 비용이 현재 노드의 비용보다 작거나 같으면 자식 노드를 그리지 않는다. 

 

 

A -> B - > C 노드는 자식 노드를 그리지 않는다. 왜냐하면 위 레벨에 같은 이름의 C 노드의 비용이 더 작기 때문에

A -> B -> D 노드는 자식 노드를 그리지 않는다. 왜냐하면 같은 레벨의 다른 D 노드의 비용이 더 작기 때문에

A -> B -> E 노드는 그린다 왜냐하면 같은 레벨의 다른 E 노드보다 작기 때문에

이러한 방식으로 3 레벨 까지 그리고 그 다음 자식들도 마찬가지로 같은 방법으로 자식을 그려준다.

 

UCS 탐색 방법

우선순위 큐를 이용하여 UCS 알고리즘으로

시작 노드 A 에서 목표 노드 G까지 탐색 방법은 최소 비용을 우선으로 고른다는것이다.

우선순위큐
데이터를 우선순위에 따라 정렬하고 우선순위가 가장 높은 데이터에 접근하여 데이터를 가져오는 큐 자료구조

 

먼저 A 노드를 우선순위 큐에 넣고 A를 빼면서 시작한다.

A 노드를 방문하고 자식 노드 B와 C를 큐에 넣는다.

 

우선순위에 따라 C 노드가 최소 비용이기 때문에 C 노드 방문

C 노드의 자식들도 큐에 넣게 되면 현재 큐에는 B(5), B(9), D(7), E(12) 이렇게 정렬되어 있을 것이다.

만약 우선순위 큐를 사용하지 않고 그냥 선입선출 큐를 사용하면
중복되는 이름의 노드는 비용에 따라 제거하는 연산이 필요할 것이다.

 

다음 우선순위에 따라서 C의 자식들을 방문하지 않고 A -> B 노드로 방문

B의 자식들 큐에 삽입 C 노드는 이미 방문했기 때문에 제외

 

그리고 큐에 들어있는 노드들 중 가장 작은 값의 비용을 가지는 노드는 D이므로 D로 방문

D 자식들 큐에 삽입 이미 방문한 B 노드는 제외

 

 

그 다음 가장 작은 노드는 B인데 B는 이미 방문 했기 때문에 제외

그리고 다음 가장 작은 비용의 노드는 F 방문 F 노드의 자식 큐에 삽입

목표 노드가 큐에 삽입되었다고 해서 도착한것은 아님

 

 

그 다음 작은 노드 E 방문 E의 자식들 큐에 삽입하는데 C는 이미 방문했기 때문에 제외

 

 

그 다음 작은 노드 G 방문 목표 노드 도착!

 

방문 순서는 A, C, B, D, F, E, G이며 최단 노드의 순서는 A, C, D, F, G 이다

 

파이썬 코드 작성

from collections import defaultdict
from queue import PriorityQueue


class Node:
    def __init__(self, name, path, cost=0):
        self.name = name  # 노드 이름
        self.path = path  # 시작 노드로 부터 경로
        self.cost = cost  # 시작 노드로 부터의 가중치 합

    def expand(self, graph):
        # 그래프에서 현재 노드의 자식 노드로 생성할 수 있는 노드를 리스트로 반환
        return [Node(i, [], graph.get(self.name).get(i)) for i in graph.get(self.name).keys()]

    def __lt__(self, other):
        return self.cost < other.cost  # 비교 연산자 재정의

    def __eq__(self, other):
        return self.name == other.name

    def __hash__(self):
        return hash(self.name)


def generateGraph(edges):
    graph = defaultdict(dict)
    for u, v, dist in edges:
        graph[u][v] = dist
    return graph


def UCS(graph, src, dest):
    queue = PriorityQueue()  # 우선 순위 큐 생성
    queue.put(Node(src, [], 0))
    visited = set()

    while queue:
        current = queue.get()
        
        if current not in visited:  # 이미 방문한 노드가 아니면
            visited.add(current)  # 현재 노드를 방문 했다고 체크, set을 이용하여 O(1) 시간 복잡도를 보장
            print(f'방문: {current.name}')

            for state in current.expand(graph):  # 현재 노드의 자식 노드 생성
                if state not in visited:
                    state.cost += current.cost  # 방문된 가중치 합을 자식 노드에 넣는다
                    state.path = current.path + [current.name]  # 자식 노드의 경로에 부모 노드의 경로와 부모 노드를 추가
                    queue.put(state)  # 큐에 추가

        if current.name == dest:  # 현재 노드가 목표 노드면 종료
            current.path.append(current.name)  # 도착 목표 노드에 도달하면 path에 목표 노드를 추가한다
            print(f'Shortest distance is {current.cost}')  # 최단 거리 비용을 출력한다
            print(f'And Search path is {current.path}')  # 최단 거리 경로를 출력한다
            return


if __name__ == "__main__":
    weighted_edges = [['a', 'b', 5], ['b', 'a', 5],
                      ['a', 'c', 4], ['c', 'a', 4],
                      ['b', 'c', 5], ['c', 'b', 5],
                      ['b', 'e', 6], ['e', 'b', 6],
                      ['c', 'e', 8], ['e', 'c', 8],
                      ['b', 'd', 7], ['d', 'b', 7],
                      ['c', 'd', 3], ['d', 'c', 3],
                      ['e', 'g', 3], ['g', 'e', 3],
                      ['d', 'f', 3], ['f', 'd', 3],
                      ['f', 'g', 2], ['g', 'f', 2]]

    graph = generateGraph(weighted_edges)
    UCS(graph, 'a', 'g')

 

자바 언어가 익숙하다 보니 뭐든간에 클래스로 만들려고 하는 버릇이 있는데 오히려 좋은거같다.

노드를 클래스로 만들고 각종 연산자 메서드를 재정의하고 BFS 코드를 기반으로 코드를 작성했다.

 

큐에서 데이터를 접근할 때 선입선출 큐가 아니라 우선순위 큐를 사용하면 최소 경로 비용의 노드를 선택할 수 있다.

 

우선순위 큐를 사용하고 싶지 않다면 단순히 min 함수를 사용해서 리스트에서 뽑아 쓰면 된다. 정말 쉽다.

 

 


 

 

학교 과제

파이썬을 이용하여 아래의 State Space Graph에 대한 Uniform Cost Search 알고리즘을 구현하시오.

from collections import defaultdict
from queue import PriorityQueue


class Node:
    def __init__(self, name, path, cost=0):
        self.name = name  # 노드 이름
        self.path = path  # 시작 노드로 부터 경로
        self.cost = cost  # 시작 노드로 부터의 가중치 합

    def expand(self, graph):
        # 그래프에서 현재 노드의 자식 노드로 생성할 수 있는 노드를 리스트로 반환
        return [Node(i, [], graph.get(self.name).get(i)) for i in graph.get(self.name).keys()]

    def __lt__(self, other):
        return self.cost < other.cost  # 비교 연산자 재정의

    def __eq__(self, other):
        return self.name == other.name

    def __hash__(self):
        return hash(self.name)


def generateGraph(edges):
    graph = defaultdict(dict)
    for u, v, dist in edges:
        graph[u][v] = dist
    return graph


def UCS(graph, src, dest):
    queue = PriorityQueue()  # 우선 순위 큐 생성
    queue.put(Node(src, [], 0))
    visited = set()

    while queue:
        current = queue.get()

        if current not in visited:  # 이미 방문한 노드가 아니면
            visited.add(current)  # 현재 노드를 방문 했다고 체크, set을 이용하여 O(1) 시간 복잡도를 보장
            print(f'방문: {current.name}')

            for state in current.expand(graph):  # 현재 노드의 자식 노드 생성
                if state not in visited:
                    state.cost += current.cost  # 방문된 가중치 합을 자식 노드에 넣는다
                    state.path = current.path + [current.name]  # 자식 노드의 경로에 부모 노드의 경로와 부모 노드를 추가
                    queue.put(state)  # 큐에 추가

        if current.name == dest:  # 현재 노드가 목표 노드면 종료
            current.path.append(current.name)  # 도착 목표 노드에 도달하면 path에 목표 노드를 추가한다
            print(f'Shortest distance is {current.cost}')  # 최단 거리 비용을 출력한다
            print(f'And Search path is {current.path}')  # 최단 거리 경로를 출력한다
            return


if __name__ == "__main__":
    weighted_edges = [['a', 'b', 6], ['a', 'c', 3], ['b', 'c', 1],
                      ['c', 'b', 4], ['b', 'd', 2], ['c', 'd', 8],
                      ['c', 'e', 2], ['d', 'e', 9], ['e', 'd', 7]]

    graph = generateGraph(weighted_edges)
    UCS(graph, 'a', 'd')

 

 

 

728x90
반응형
728x90
반응형

 

 

퍼즐 맞추기인데

교수님이 억까 코드로 실습하라고 했음...

그래서 일단 억까코드 수정하고 저렇게 만들어봤는데

 

bfs는 교수님 원본 코드에서 딱히 바뀐건 없고

주석이랑 조건문 위치랑 moves 프린트 수정했고

 

dfs는 실습이었는데

저렇게 만드는게 맞나 모르겠다..

일단 무한적으로 탐색하던건 조건문 위치랑 조건 수정해서 고쳐졌고

set으로 중복체킹하는데 시간복잡도 O(1)로 수정함

 

 

 

 

BFS

class State:
    def __init__(self, board, goal, moves=0):
        self.board = board
        self.moves = moves
        self.goal = goal

    # i1과 i2를 교환하여서 새로운 상태를 반환한다.
    def get_new_board(self, i1, i2, moves):
        new_board = self.board[:]
        new_board[i1], new_board[i2] = new_board[i2], new_board[i1]
        return State(new_board, self.goal, moves)

    def expand(self, moves):
        result = []
        i = self.board.index(0)  # 숫자 0(빈칸)의 위치를 찾는다.
        if not i in [0, 1, 2]:  # UP 연산자
            result.append(self.get_new_board(i, i - 3, moves))
        if not i in [0, 3, 6]:  # LEFT 연산자
            result.append(self.get_new_board(i, i - 1, moves))
        if not i in [2, 5, 8]:  # DOWN 연산자 -> 사실 RIGHT 연산자로 추정
            result.append(self.get_new_board(i, i + 1, moves))
        if not i in [6, 7, 8]:  # RIGHT 연산자 -> 사실 DOWN 연산자로 추정
            result.append(self.get_new_board(i, i + 3, moves))
        return result

    # 객체를 출력할 때 사용한다.
    def __str__(self):
        return str(self.board[:3]) + "\n" + \
            str(self.board[3:6]) + "\n" + \
            str(self.board[6:]) + "\n" + \
            "------------------"

    def __eq__(self, other):
        return self.board == other.board


if __name__ == "__main__":
    puzzle = [2, 8, 3,
              1, 6, 4,
              7, 0, 5]

    goal = [1, 2, 3,
            8, 0, 4,
            7, 6, 5]

    # open 리스트
    not_visited = [State(puzzle, goal)]
    visited = []
    moves = 0
    while not_visited:  # 스택이 빌 때까지
        current = not_visited.pop(0)  # 방문하려는 노드를 not_visited에서 삭제
        print(current, current.moves)
        if current.board == goal:
            print("탐색 성공")
            break

        if current not in visited:
            visited.append(current)
            moves = current.moves + 1
            for state in current.expand(moves):
                if state in visited:  # 이미 거쳐간 노드이면
                    continue  # 노드를 버린다.
                else:
                    not_visited.append(state)  # 리스트 추가

 

 

DFS

class State:
    def __init__(self, board, goal, moves=0):
        self.board = board
        self.moves = moves
        self.goal = goal

    # i1과 i2를 교환하여서 새로운 상태를 반환한다.
    def get_new_board(self, i1, i2, moves):
        new_board = self.board[:]
        new_board[i1], new_board[i2] = new_board[i2], new_board[i1]
        return State(new_board, self.goal, moves)

    def expand(self, moves):
        result = []
        i = self.board.index(0)  # 숫자 0(빈칸)의 위치를 찾는다.
        if not i in [0, 1, 2]:  # UP 연산자
            result.append(self.get_new_board(i, i - 3, moves))
        if not i in [0, 3, 6]:  # LEFT 연산자
            result.append(self.get_new_board(i, i - 1, moves))
        if not i in [2, 5, 8]:  # DOWN 연산자 -> 사실 RIGHT 연산자로 추정
            result.append(self.get_new_board(i, i + 1, moves))
        if not i in [6, 7, 8]:  # RIGHT 연산자 -> 사실 DOWN 연산자로 추정
            result.append(self.get_new_board(i, i + 3, moves))
        return result

    # 객체를 출력할 때 사용한다.
    def __str__(self):
        return str(self.board[:3]) + "\n" + \
            str(self.board[3:6]) + "\n" + \
            str(self.board[6:]) + "\n" + \
            "------------------"

    def __eq__(self, other):
        return self.board == other.board

    def __hash__(self):
        return hash((tuple(self.board)))


if __name__ == "__main__":
    puzzle = [2, 8, 3,
              1, 6, 4,
              7, 0, 5]

    goal = [1, 2, 3,
            8, 0, 4,
            7, 6, 5]

    # open 리스트
    not_visited = [State(puzzle, goal)]
    visited_set = set()
    moves = 0
    while not_visited:  # 스택이 빌 때까지
        current = not_visited.pop()  # 방문하려는 노드를 not_visited에서 삭제
        print(current, current.moves)
        if current.board == goal:
            print("탐색 성공")
            break

        if current not in visited_set:
            visited_set.add(current)
            moves = current.moves + 1

            for state in current.expand(moves):
                if state not in visited_set:  # 이미 거쳐간 노드가 아니면
                    not_visited.append(state)  # 리스트 추가

 

DFS는 노드간의 간선을 미리 설정해놓지 않는 무정보탐색에서는

이렇게 정말 많은 반복을 하는것같음

 

그래서 dfs는 set 클래스로 시간복잡도를 개선했는데

뭔 2천번 넘게 탐색을해서 저렇게 수정하는게 맞나 모르겠음

 

암튼 bfs도 set 클래스를 써도 되는데 코드 차이를 보라고 저렇게 해봤음

 

 

Best-First Search (그리디 알고리즘) + a* 알고리즘

class State:
    def __init__(self, board, goal, moves=0):
        self.board = board
        self.moves = moves
        self.goal = goal

    # i1과 i2를 교환하여서 새로운 상태를 반환한다.
    def get_new_board(self, i1, i2, moves):
        new_board = self.board[:]
        new_board[i1], new_board[i2] = new_board[i2], new_board[i1]
        return State(new_board, self.goal, moves)

    def expand(self, moves):
        result = []
        i = self.board.index(0)  # 숫자 0(빈칸)의 위치를 찾는다.
        if not i in [0, 1, 2]:  # UP 연산자
            result.append(self.get_new_board(i, i - 3, moves))
        if not i in [0, 3, 6]:  # LEFT 연산자
            result.append(self.get_new_board(i, i - 1, moves))
        if not i in [2, 5, 8]:  # DOWN 연산자 -> 사실 RIGHT 연산자로 추정
            result.append(self.get_new_board(i, i + 1, moves))
        if not i in [6, 7, 8]:  # RIGHT 연산자 -> 사실 DOWN 연산자로 추정
            result.append(self.get_new_board(i, i + 3, moves))
        return result

    # 객체를 출력할 때 사용한다.
    def __str__(self):
        return str(self.board[:3]) + "\n" + \
            str(self.board[3:6]) + "\n" + \
            str(self.board[6:]) + "\n" + \
            "------------------"

    def __eq__(self, other):
        return self.board == other.board

    def __hash__(self):
        return hash((tuple(self.board)))

    def f(self):
        return self.g() + self.h()

    def g(self):
        return self.moves

    def h(self):
        return sum([1 if self.board[i] != self.goal[i] else 0 for i in range(8)])

    def __lt__(self, other):
        return self.f() < other.f()



puzzle = [2, 8, 3,
              1, 6, 4,
              7, 0, 5]

goal = [1, 2, 3,
        8, 0, 4,
        7, 6, 5]

# open 리스트
not_visited = [State(puzzle, goal)]
visited_set = set()
moves = 0
while not_visited:  # 스택이 빌 때까지

    current = min(not_visited) # 가장 휴리스틱 값이 최적인 것을 현재 노드로 선택
    not_visited.remove(current)
    print(current, current.moves)
    if current.board == goal:
        print("탐색 성공")
        break

    if current not in visited_set:
        visited_set.add(current)
        moves = current.moves + 1

        for state in current.expand(moves):
            if state not in visited_set:  # 이미 거쳐간 노드가 아니면
                state.f_value = state.f()
                not_visited.append(state)  # 리스트 추가

 

휴리스틱 값을 퍼즐이 골의 퍼즐과 다른 상태를 h() 시작 노드에서 현재 노드까지 거리를 g() 으로 합쳐서

최선탐색 알고리즘과 a스타 알고리즘으로 작성했다 그런데 정확하게 아직은 모르겠다

아직 가장 최적으로 찾는게 없어서 나중에 수정해야한다

 

 

 

728x90
반응형
728x90
반응형

파이썬의 연산자

연산자
+ 더하기
- 빼기
* 곱하기
/ 나누기(소수점)
** 제곱
//
% 나머지
() 괄호 안을 먼저 연산

 

파이썬의 변수

변수 이름 뒤 등호(=)로 값을 저장한다

C언어나 JAVA 처럼 자료형을 지정해주지 않는다

 

변수 이름은 대/소문자, 숫자, 밑줄로 사용

대소문자는 구분됨

파이썬의 변수 네이밍룰은 소문자로 _ 를 사용하여 구분하여 사용한다고 한다

 

출력

print(변수), print("hello")

def print_hi(name):
    print("I like", end='')
    print(" money")


if __name__ == '__main__':
    print_hi('PyCharm')

 

판단

파이썬의 참 값은 True, 거짓 없은 False

==, !=, <, >, <=, >= 와 같은 비교 연산자가 있다

 

if elif else

 

반복

for x in range(5) : print(x)

 

for x in range(1, 11): print(x)

 

i = 0

while i <= 10:

 print(i)

i += 1

 

함수

def 함수():

 

 

 

 

728x90
반응형
728x90
반응형

파이썬으로 웹 크롤링

파이썬으로 빅데이터 공부를 하면서 웹 크롤링에 대해 배우게 되었다.

증시 관련 데이터를 크롤링 하려는데 네이버에서 증시 api는 제공하지 않는다.

그래서 html 태그에서 직접 크롤링을 해야했다.

 

from bs4 import BeautifulSoup
import requests
import pandas as pd
from selenium import webdriver
import time

밑의 코드들은 위의 라이브러리를 사용한다.

 

종목 코드 크롤링

주식 데이터를 검색하려면 보통 종목코드를 입력하여 크롤링 하는것이 일반적이다. 하지만 일반 사람들에게는 삼성전자, 구글 이러한 이름이 익숙하기 때문에 먼저 종목 코드 부터 크롤링 할것이다.

 

크롬 네이버에서 삼성 전자를 검색하고 종목코드가 나오는 곳을 마우스 오른쪽 검사를 누르면 자동으로 종목코드가 있는 html 태그 쪽으로 이동한다. <em class="t_nm"> 태그에 종목 코드가 있는 것을 볼 수 있다.

 

https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query=%EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90

 

네이버에서 단어를 검색하면 위의 링크로 나오게 되는데 %EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90 이부분이 삼성전자를 입력했던 부분이다.

 

def searchNameForNaver(name):
    url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query="
    wd = webdriver.Chrome('./WebDriver/chromedriver.exe')
    wd.get(url+name)
    time.sleep(1) #웹 페이지 연결을 위한 기다림
    
    html = wd.page_source #wd로 웹페이지 소스를 긁어옴
    soup = BeautifulSoup(html, 'html.parser')

    tagEm = soup.find('em', attrs={'class':'t_nm'})
    print(tagEm.string)
    return tagEm.string

 

입력한 단어를 name으로 받아서 url과 합쳐주고 webdriver로 열어준다.

Selenium과 webdriver는 인터넷에 찾으면 나옴

 

BeautifulSoup로 html 객체를 만들고 t_nm 태그의 string만 return 하는 함수를 만들었다.

그러면 종목 코드만 return된다.

 

웹페이지를 열어서 html 태그에서 원하는 정보만 찾는 방법이다.

 

네이버 금융에서 일별시세 크롤링

먼저 일별 시세를 불러오기 전에 csv로 만들거라서 열을 먼저 가져올 것이다.

url = "https://finance.naver.com/item/sise_day.naver?code="
wd = webdriver.Chrome('./WebDriver/chromedriver.exe')
wd.get(url+code)
time.sleep(1)

html = wd.page_source
soup = BeautifulSoup(html, 'html.parser')

thStringList = []

thList = soup.tbody.select('th')

for th in thList:
    thStringList.append(th.string)

 

위에서 했던 것과 마찬가지로 일별시세 헤더가 있는 부분을 찾아서 리스트에 넣었다.

그리고 request.get을 사용해서 데이터들을 불러오는데 전일대비 부분에 이상한 문자열이 들어가서 없애주었다.

 

def searchFinance(code, maxPage):
    url = "https://finance.naver.com/item/sise_day.naver?code="
    wd = webdriver.Chrome('./WebDriver/chromedriver.exe')
    wd.get(url+code)
    time.sleep(1)

    html = wd.page_source
    soup = BeautifulSoup(html, 'html.parser')

	#자동으로 최대 페이지를 찾지만 아직 오류
    '''pgrr = soup.find('td', class_='pgRR')
    pgrr.a["href"].split('=')
    lastPage = int(pgrr.a["href"].split('=')[-1])'''
    
    thStringList = []
    spanStringList = []

    thList = soup.tbody.select('th')
    
    for th in thList:
        thStringList.append(th.string)
    
    #사용자가 정한 페이지 만큼 반복
    for cntPage in range(int(maxPage)):
        pageUrl = url+code+'&page='+str(cntPage+1)
        #페이지 request
        data = requests.get(pageUrl, headers={'User-agent': 'Mozilla/5.0'}).text
        
        soup = BeautifulSoup(data, 'html.parser')
        spanList = soup.select('span')
        #일별시세 제목 제거
        spanList.pop(0)

		#이상한문자열제거
        for span in spanList:
            if span.string.find('\t') != -1:
                tmp = span.string
                tmp = tmp.strip('\n')
                tmp = tmp.strip('\t')
                tmp = tmp.replace('\n', '')
                spanStringList.append(tmp)
                continue

            spanStringList.append(span.string)
    
    #2차원 배열로 만들기
    l = [spanStringList[r*7:(r+1)*7]for r in range(10*int(maxPage))]
    
    return [thStringList, l]

 

최종 코드

from bs4 import BeautifulSoup
import requests
import pandas as pd
from selenium import webdriver
import time



def searchNameForNaver(name):
    url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=1&ie=utf8&query="
    wd = webdriver.Chrome('./WebDriver/chromedriver.exe')
    wd.get(url+name)
    time.sleep(1)
    
    html = wd.page_source
    soup = BeautifulSoup(html, 'html.parser')

    tagEm = soup.find('em', attrs={'class':'t_nm'})
    print(tagEm.string)
    return tagEm.string
    

def searchFinance(code, maxPage):
    url = "https://finance.naver.com/item/sise_day.naver?code="
    wd = webdriver.Chrome('./WebDriver/chromedriver.exe')
    wd.get(url+code)
    time.sleep(1)

    html = wd.page_source
    soup = BeautifulSoup(html, 'html.parser')

    '''pgrr = soup.find('td', class_='pgRR')
    pgrr.a["href"].split('=')
    lastPage = int(pgrr.a["href"].split('=')[-1])'''
    
    thStringList = []
    spanStringList = []

    thList = soup.tbody.select('th')
    
    for th in thList:
        thStringList.append(th.string)
    
    for cntPage in range(int(maxPage)):
        pageUrl = url+code+'&page='+str(cntPage+1)
        data = requests.get(pageUrl, headers={'User-agent': 'Mozilla/5.0'}).text
        
        soup = BeautifulSoup(data, 'html.parser')
        spanList = soup.select('span')
        spanList.pop(0)

        for span in spanList:
            if span.string.find('\t') != -1:
                tmp = span.string
                tmp = tmp.strip('\n')
                tmp = tmp.strip('\t')
                tmp = tmp.replace('\n', '')
                spanStringList.append(tmp)
                continue

            spanStringList.append(span.string)
    
    l = [spanStringList[r*7:(r+1)*7]for r in range(10*int(maxPage))]
    
    return [thStringList, l]


def main():
    result = []
    print("크롤링 시작 >")
    searchName = input('검색 기업을 입력하시오: ')
    maxPage = input('최대 페이지를 입력하시오: ')
    code = searchNameForNaver(searchName)
    result = searchFinance(code, maxPage)
    
    CB_tbl = pd.DataFrame(result[1], columns = tuple(result[0]))
    CB_tbl.to_csv('./today.csv', encoding='cp949', mode='w', index=True)
    

if __name__ == '__main__':
    main()

728x90
반응형
728x90
반응형

 

 

우리 학교 파이썬 수업 과제였습니다 ㅋㅋㅋㅋ

 

정말 한참 수정할게 많지만 나중에 하는걸로 하고 지금은 백업용으로 올립니다.

 

나름 리스트에 해당 년도 달력을 전부 넣고 싶어서 고민좀 했습니다.

 

WOD.py

# 모듈
import turtle
import returnday

# 터틀 입력창으로 연도 입력 받기 및 터틀 설정
turtle.title("달력 만들기")
turtle.hideturtle()
turtle.speed(0)
inputYear = int(turtle.numinput("달력 만들기", "표시할 달력의 연도를 입력하시오."))
print("%d" % (inputYear))
print()

# 터틀 창 테두리 꾸미기
turtle.penup()
turtle.pensize(3)
turtle.goto(-457, 387)
turtle.pendown()
turtle.forward(910)
turtle.penup()
turtle.right(90)
turtle.forward(95)
turtle.right(90)
turtle.pendown()
turtle.forward(910)
turtle.penup()

# 달력 연도 꾸미기
turtle.penup()
turtle.goto(440, 308)
turtle.pencolor("black")
turtle.write("Calendar %dy" % (inputYear), align = "right", font = ("Bahnschrift", 45, "normal"))

# 일 배열 입력
arrayDay = []

for i in range(12):
    arrayDay.append(list(returnday.month_range(inputYear, i + 1)))


print(arrayDay, end="\n\n")

# 월 영어
arrEngMonth = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]

eng_y = 440
indexArrEngMonth = 0

# 월 배열 출력
for i in range(12):
    eng_x = -340
    eng_y -= 220
    for u in range(4):
        if indexArrEngMonth == 12:
            break
        turtle.goto(eng_x,eng_y)
        turtle.pencolor("black")
        turtle.write("%s" % arrEngMonth[indexArrEngMonth], align = "center", font = ("Bahnschrift", 25, "normal"))
        indexArrEngMonth += 1
        
        eng_x += 225

# 월별 일 입력 및 출력
arrayCalendarDay = []
eng_weekOfTheDay = ["S", "M", "T", "W", "T", "F", "S"]
arrColor = ["#930000", "black", "black", "black", "black", "black", "#005A81"]

# 리스트 7 * 7 * 12
for mm in range(12):
    for i in range(7):
        arrayCalendarDay.append([None] * 7)

m = 0
nummm = 0
frist_1 = 1
frist_2 = 2
wod_x = -414
wod_y = 190
wod_x_1 = 0
day_y_1 = 165
y_2 = 0

# 달력 출력
for num in range(12):
    day = 1
    isMonth = arrayDay[num][0]      # 1일이 어느 요일에 있는지
    isDay = arrayDay[num][1]        # 그 달이 며칠까지 있는지
    
    # 4열 출력후 아래로 계속 출력
    if m == 4:
        wod_x = -414
        wod_y -= 218
        day_y_1 -= 218
        m = 0

    # 요일 출력
    for i in range(7):
        arrayCalendarDay[nummm][i] = eng_weekOfTheDay[i]
        turtle.goto(wod_x, wod_y)
        turtle.pencolor(arrColor[i])
        if i == 0:
            wod_x_1 = wod_x
            wod_y_1 = wod_y - 50
        turtle.write("%s" % arrayCalendarDay[nummm][i], align = "right", font = ("Bahnschrift", 10, "normal"))
        wod_x += 26

    # 월 첫 주 먼저 출력
    for i in range(frist_1, frist_1 + 1):
        # 일 당기기
        day_x_1 = wod_x_1 + isMonth * 26
        for u in range(isMonth, 7):
            arrayCalendarDay[i][u] = day
            turtle.goto(day_x_1, day_y_1)
            turtle.pencolor(arrColor[u])
            turtle.write("%d" % arrayCalendarDay[i][u], align = "right", font = ("Bahnschrift", 10, "normal"))
            day_x_1 += 26
            day += 1

    # 그다음 출력
    for i in range(frist_2, frist_2 + 5):
        day_x_2 = wod_x_1
        day_y_2 = wod_y_1

        # 일이 해당 일보다 초과하면 다음으로 넘어감
        for u in range(7):
            if day > isDay:
                break
            arrayCalendarDay[i][u] = day
            day += 1
            turtle.goto(day_x_2, day_y_2)
            turtle.pencolor(arrColor[u])
            turtle.write("%d" % arrayCalendarDay[i][u], align = "right", font = ("Bahnschrift", 10, "normal"))
            
            day_x_2 += 26
        wod_y_1 -= 25

    wod_x += 40
    nummm += 7
    frist_1 += 7
    frist_2 += 7
    m += 1
    
print(arrayCalendarDay)
turtle.done()

# 끝



 

 

returnday.py

def month_range(year, month):
    ins_year = 1
    ins_month = 1

    ins_now_month = 0

    while True:
        now_month = 31

        if ins_month == 4 or ins_month == 6 or ins_month == 9 or ins_month == 11:
            now_month = 30

        elif ins_month == 2:
            if (ins_year % 4 == 0 and ins_year % 100 != 0) or ins_year % 400 == 0:
                now_month = 29

            else:
                now_month = 28

        if ins_year == year and ins_month == month:
            break

        ins_now_month += now_month
        ins_month += 1

        if ins_month > 12:
            ins_month = 1
            ins_year += 1

    
    wodIndex = (1 + ins_now_month) % 7

    return wodIndex, now_month

 

 

근데 교수님께서 인터넷에 있는거 배끼면 0점 준다고 했었음 ㅋㅋㅋ

 

 

 

 

정말 어이없는 곳에서 오류나가지고...

 

아직 멀었네요.

 

 

2020년 달력도 만들 수 있습니다.

 

시간이 된다면

 

공휴일은 전부 빨간색으로 출력하도록 해보려고 합니다.

 

아마 오랫동안 시간이 안될듯 ㅋㅋㅋㅋㅋㅋㅋㅋ

 

 

728x90
반응형
728x90
반응형

 

 

 

[파이썬] 숫자 맞추기 게임 from random import randint

 

random 모듈로 1부터 100까지 랜덤 숫자를 불러와서

 

숫자맞추기 게임을 만들었습니다

 

시험에 나올줄알았는데 안나오누

 

## 숫자 맞추기 게임
from random import randint
tries = 0
myNumber = 0
correctNumber = randint(1, 100)
print("1부터 100사이의 숫자를 맞추시오")
while tries < 10:
    myNumber = int(input("숫자를 입력하시오: "))
    tries += 1
    if myNumber < correctNumber:
        print("정답보다 낮습니다!")
    elif myNumber > correctNumber:
        print("정답보다 높습니다!")
    else:
        break
if myNumber == correctNumber:
    print("정답입니다. 당신의 시도 횟수는 %d입니다." % tries)
else:
    print("실패했습니다. 정답은 %d입니다. 가능한 횟수는 %d입니다." % (correctNumber, tries))

 

728x90
반응형