2025-04-30
NalMokG
NalMokE
2025-04-29
NalMok
내가 생각한 오목 변형 게임. 규칙은 오목과 비슷. 다른 점은 하나. 날일자 모양 방향으로 다섯 개 놓으면 됨. 가로 세로 대각선이 아니라.
Python만 가지고는 그림이 안 나오니 PyQt 활용. 프로그램 개발을 chatGPT에게 시킴. 수준은 향상 필요하나 일단 동작은 함. 그 뜻은 5개 놓았는데, 이겼는지 졌는지도 모르지는 않는다는 뜻. 처음엔 엉뚱하게 두기에 chatGPT에게 규칙을 가르쳐 주는 과정이 쉽지만은 않았지만, 나름 재미있었음.
아래는 그걸 구현한 소스 코드. 수시로 업그레이드 중.
import sys
import random
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt, QTimer
BOARD_SIZE = 19
CELL_SIZE = 30
STONE_RADIUS = 12
EMPTY = 0
BLACK = 1
WHITE = 2
class NalmokGame(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("날목 (Nalmok)")
self.setFixedSize(BOARD_SIZE * CELL_SIZE, BOARD_SIZE * CELL_SIZE)
self.board = [[EMPTY for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
self.turn = WHITE # Player is WHITE, computer is BLACK
# Computer plays first in the center
mid = BOARD_SIZE // 2
self.board[mid][mid] = BLACK
self.show()
def paintEvent(self, event):
qp = QPainter()
qp.begin(self)
self.draw_board(qp)
self.draw_stones(qp)
qp.end()
def draw_board(self, qp):
qp.setBrush(QColor(222, 184, 135))
qp.drawRect(0, 0, self.width(), self.height())
qp.setPen(QPen(Qt.black, 1))
for i in range(BOARD_SIZE):
qp.drawLine(CELL_SIZE // 2, CELL_SIZE // 2 + i * CELL_SIZE,
CELL_SIZE // 2 + (BOARD_SIZE - 1) * CELL_SIZE, CELL_SIZE // 2 + i * CELL_SIZE)
qp.drawLine(CELL_SIZE // 2 + i * CELL_SIZE, CELL_SIZE // 2,
CELL_SIZE // 2 + i * CELL_SIZE, CELL_SIZE // 2 + (BOARD_SIZE - 1) * CELL_SIZE)
def draw_stones(self, qp):
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] != EMPTY:
if self.board[y][x] == BLACK:
qp.setBrush(QColor(0, 0, 0))
else:
qp.setBrush(QColor(255, 255, 255))
qp.drawEllipse(
CELL_SIZE // 2 + x * CELL_SIZE - STONE_RADIUS,
CELL_SIZE // 2 + y * CELL_SIZE - STONE_RADIUS,
STONE_RADIUS * 2,
STONE_RADIUS * 2)
def mousePressEvent(self, event):
if self.turn != WHITE:
return
x = int((event.x() - CELL_SIZE // 2 + CELL_SIZE / 2) // CELL_SIZE)
y = int((event.y() - CELL_SIZE // 2 + CELL_SIZE / 2) // CELL_SIZE)
if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE and self.board[y][x] == EMPTY:
self.board[y][x] = WHITE
if self.check_win(x, y, WHITE):
self.update()
self.game_over("플레이어(백) 승리!")
return
self.turn = BLACK
self.update()
QTimer.singleShot(500, self.computer_move)
def computer_move(self):
best_move = self.find_best_move()
if best_move is None:
self.game_over("무승부!")
return
x, y = best_move
self.board[y][x] = BLACK
if self.check_win(x, y, BLACK):
self.update()
self.game_over("컴퓨터(흑) 승리!")
return
self.turn = WHITE
self.update()
def find_best_move(self):
# 우선순위: 내 승리 > 상대 승리 방어 > 3개 막기 > 랜덤
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY:
self.board[y][x] = BLACK
if self.check_win(x, y, BLACK):
self.board[y][x] = EMPTY
return (x, y)
self.board[y][x] = EMPTY
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY:
self.board[y][x] = WHITE
if self.check_win(x, y, WHITE):
self.board[y][x] = EMPTY
return (x, y)
self.board[y][x] = EMPTY
for y in range(BOARD_SIZE):
for x in range(BOARD_SIZE):
if self.board[y][x] == EMPTY:
self.board[y][x] = WHITE
if self.count_consecutive(x, y, WHITE, 3):
self.board[y][x] = EMPTY
return (x, y)
self.board[y][x] = EMPTY
empty = [(x, y) for y in range(BOARD_SIZE) for x in range(BOARD_SIZE) if self.board[y][x] == EMPTY]
return random.choice(empty) if empty else None
def count_consecutive(self, x, y, stone, count_required):
directions = [(1, 2), (2, 1), (2, -1), (1, -2),
(-1, -2), (-2, -1), (-2, 1), (-1, 2)]
for dx, dy in directions:
cnt = 1
for step in range(1, 5):
nx = x + dx * step
ny = y + dy * step
if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
if self.board[ny][nx] == stone:
cnt += 1
else:
break
if cnt >= count_required:
return True
return False
def check_win(self, x, y, stone):
directions = [(1, 2), (2, 1), (2, -1), (1, -2),
(-1, -2), (-2, -1), (-2, 1), (-1, 2)]
for dx, dy in directions:
count = 1
for dir in [1, -1]:
for i in range(1, 5):
nx = x + dx * i * dir
ny = y + dy * i * dir
if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
if self.board[ny][nx] == stone:
count += 1
else:
break
if count >= 5:
return True
return False
def game_over(self, message):
QMessageBox.information(self, "게임 종료", message)
self.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
game = NalmokGame()
sys.exit(app.exec_())
2025-04-25
AddPdf With Python and PyQt
간단한 프로그램. 연습 삼아 만들어 봄.
pdftk 프로그램 설치. 사실 pdftk 만으로도 pdf 파일 합치는 건 가능하다. 명령어 치는 게 귀찮을 뿐.
GUI 프로그램을 만들어 보자.
창 하나. 그 창 안에 버튼 하나. 버튼 누르면 합칠 pdf 파일들을 선택하게 한다. 선택한 pdf 파일들을 합쳐서 새 파일 하나 만들기.
말로는 간단한데 프로그램 만드는 것은 말처럼 쉽지는 않다.
인공지능의 도움을 받아 프로그램 완성. 처음 프로그램 하는데 그 과정에서 에러가 안 나면 오히려 이상한 일. 에러 해결 역시 인공지능의 도움을 받음. 아래는 그 소스 코드.
import sys
import subprocess
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QFileDialog, QMessageBox, QVBoxLayout
class PDFMerger(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle('PDF 합치기 도구')
self.setGeometry(100, 100, 300, 100)
self.button = QPushButton('PDF 합치기', self)
self.button.clicked.connect(self.merge_pdfs)
layout = QVBoxLayout()
layout.addWidget(self.button)
self.setLayout(layout)
def merge_pdfs(self):
files, _ = QFileDialog.getOpenFileNames(
self,
"PDF 파일 선택",
"",
"PDF Files (*.pdf)"
)
if not files:
return
save_path, _ = QFileDialog.getSaveFileName(
self,
"저장할 파일 이름",
"merged.pdf",
"PDF Files (*.pdf)"
)
if not save_path:
return
try:
# pdftk 명령어로 파일 합치기
command = ['pdftk'] + files + ['cat', 'output', save_path]
subprocess.run(command, check=True)
QMessageBox.information(self, "성공", f"PDF가 성공적으로 저장되었습니다:\n{save_path}")
except subprocess.CalledProcessError:
QMessageBox.critical(self, "오류", "PDF를 합치는 중 오류가 발생했습니다.")
if __name__ == '__main__':
app = QApplication(sys.argv)
merger = PDFMerger()
merger.show()
sys.exit(app.exec_())
A poem made by AI
바람이 머물다 간 자리
가만히 눈을 감으면
내 마음 속에도 바람이 분다
세찬 날엔 흔들리고
고요한 날엔 울먹인다
그래도 괜찮아
바람은 머물지 않고
언제나 지나가는 거니까
한숨도, 눈물도,
결국엔 지나가고 나면
조금은 단단해진 나를 남기지
오늘은 그냥
그 바람 속에 잠시 기대어
쉬어가도 괜찮아
AI에게 시 하나 지어 달라고 하니 뚝딱. 참 좋은 세상.
2025-04-24
chatGPT and AI with Python
2025-04-23
2025-04-21
nephron superbin
빈 캔을 넣으면 포인트 적립하고 어느 정도 모이면 현금처럼 쓸 수 있는 서비스가 있다.
자동판매기 비슷하게 생긴 기계.
수퍼빈 앱을 설치하고, 해당 기계에 빈 캔을 넣으면 갯수에 따라 포인트적립.
전에 없던 절차가 하나 더 생겼다.
기계에 휴대전화번호를 입력하면 그 전화에 4자리 숫자가 문자로 온다. 그 숫자를 기계에 입력해야 포인트 쌓인다. 전에는 없던 절차.
아마도 여러 사람이 한 사람 것을 적립해주는 것을 막으려는 장치인 듯.
각자 내 것은 내가 적립하라는 얘기. 다른 사람 시키지 말고.
2025-04-20
LGUplus Boot touch not work. Solved
2025-04-17
Find Fourier expansion of x² where x in (-2𝜋,2𝜋)
\[ f(x)=a_0 + \sum_{n=1}^{\infty} a_n \cos(\frac{n \pi x}{2 \pi}) + \sum_{n=1}^{\infty} b_n \sin(\frac{n \pi x}{2 \pi}) \]
\[ f(x)=a_0 + \sum_{n=1}^{\infty} a_n \cos(\frac{n x}{2}) \]
\[ a_0 = \frac{1}{4 \pi}\int_{-2\pi}^{2\pi} x^2 \, dx = \frac{2}{4 \pi}\int_{0}^{2\pi} x^2 \, dx = \frac{8\pi^{2}}{3} \]
\[ a_n = \frac{1}{L} \int_{-L}^{L} x^{2} \cos (\frac{n \pi x}{L}) dx = \frac{16}{n^{2}}(-1)^{n} \]
Find Fourier expansion of x² where x in (-2𝜋,2𝜋)
LaTeX Laplace transform
\[ \mathcal{L}\{f(t)\} = F(s) = \int_0^{\infty} e^{-st} f(t) \, dt \] For example, the Laplace transform of \( f(t) = e^{at} \) is: \[ \mathcal{L}\{e^{at}\} = \int_0^{\infty} e^{-st} e^{at} \, dt = \int_0^{\infty} e^{-(s-a)t} \, dt = \frac{1}{s-a}, \text{for } s > a \]
2025-04-16
Fourier series exta
Fourier seriese
다음 함수를 Fourier 급수로 전개하라
f(x) = x, -1 < x < 1
1단계
f(x)=x 는 기함수(odd fuction) 이므로 Fourier 급수는 sin 항만 포함
f(x) = Σ ∞ n=1 bn sin(n𝜋x)
2단계: bn 계산하기
bn = ∫ 1 -1 x sin(n𝜋x) dx
x sin(n𝜋x)는 기함수이므로
bn = 2 ∫ 1 0 x sin(n𝜋x) dx
부분적분 이용
u = x 로 놓으면 du = dx
dv=sin(n𝜋x) dx, v= -(1/n𝜋) cos(n𝜋x)
bn =2(-x/(n𝜋) cos(n𝜋x) | 1 0 + 1/(n𝜋) ∫ 1 0 x cos(n𝜋x) dx )
-x/(n𝜋) cos(n𝜋x) | 1 0 = -1/(n𝜋) + 0 = -(-1)n/(n𝜋)
1/(n𝜋) ∫ 1 0 x cos(n𝜋x) dx = 1/(n𝜋) sin(n𝜋x) = 0
bn = 2(-1)n+1 n𝜋
f(x) = Σ ∞ n=1 2(-1)n+1 n𝜋 sin(n𝜋x)
LaTeX Test Sigma
신기하네요. blogspot에서 LaTeX 쓸 수 있다는 것을 이제서야 알았네요.
\( \sum_{n=0}^{1} f(n) \)
\[ \sum_{n=0}^{1} f(n) \]
\[ f(x) = \sum_{n=1}^{\infty} \frac{2(-1)^{n+1}}{n\pi} \sin(n\pi x) \]
2025-04-15
inverse Laplace transform
F(s) = 5s+6 s(s²+1) 일 때 L-1(F(s))를 구하라
1단계: 부분 분수
5s+6 s(s²+1) = A s + (Bs+C) (s²+1)
5s + 6 = A(s²+1) + (Bs+C)s = (A+B)s²+ Cs + A
A+B = 0, C = 5, A = 6
So, B = -6
5s+6 s(s²+1) = 6 s + (-6) s (s²+1) + 5 1 (s²+1)
2단계: 라플라스 변환 표 이용
- L-1{ 1 s } = 1
- L-1{ s s²+1 } = cos(t)
- L-1{ 1 s²+1 } = sin(t)
를 이용하면
L-1{ 5s+6 s(s²+1) } = 6 - 6cos(t) + 5sin(t)
2025-04-14
Laplace Transform. L{e^(2t) sin(t)}
Laplace Transform
L{e2t sin(t)}
L{eat f(t)} = F(s-a) where F(s) = L{f(t)}
L{sin(t)} = 1 s² + 1
Since a = 2, s → s - 2
L{e2t sin(t)} = 1 (s-2)² + 1
2025-04-12
20250411Kyobo
2025-04-10
Laplace Transform with step function
L{f(t)} 를 구하라. 단 f(t) = 0 if t in (0,1), t if t>1
f(t) = t u(t-1)
f(t) = ((t-1)+1) u(t-1)
2nd Shifting Theorem
If f(t) = g(t-a) u(t-a)
then L{f(t)} = e-as L{g(t)}
f(t) = ((t-1)+1) u(t-1) = (t-1)u(t-1) + u(t-1)
L{u(t-1)} = e-s/s
L{(t-1)u(t-1)} = e-s L{t} = e-s(1/s²)
L{f(t)} = e-s/s + e-s/s²
How to write upper small number 2
How can I write upper small number 2?
I found two methods.
Normal 2 upper 2
Normal 2 upper ²
First upper 2 is written with html tag sup.
Second upper 2 is written with unicode U+00B2
2025-04-09
gimp 3 release and Manual
gimp 3 나왔는데 모르고 있었다.
https://www.gimp.org/news/2025/03/23/gimp-3-0-2-released/
설명서, 한국어 번역: https://docs.gimp.org/3.0/ko/
한국어 번역률 그다지 높지 않다. 번역에 참여하는 분도 많지 않고. 덕분에 번역자 명단에 내 이름과 메일 주소가 아직도 남아있다. 오래 전에 번역 참여하다가 손 놓은 지 오래됨.
요즘은 저 공식 번역이 큰 의미가 있나 모르겠다. 매뉴얼 안 보고 그냥 감으로 익혀서 쓰는 분이 많아서.
2025-04-07
y''+2y' = 2x+5-e^(-2x)
y'' + 2y' = 2x + 5 - e-2x
Step1:
Solve y'' + 2y' = 0
characteristic equation: r2 + 2r = 0
r(r+2) = 0
r = 0 or r = -2
General solution:
yh = c1 + c2 e-2x
Step2: Find particular solution
1) 2x + 5:
yp1 = Ax2 + Bx
y' = 2Ax + B
y'' = 2A
y'' + 2y = 2A + 2(2Ax+ B) = 4Ax + 2B + 2A
4Ax + 2B + 2A = 2x + 5
4A = 2
A = 1/2
2A + 2B = 5
1 + 2B = 5
B = 2
yp1 = x2/2 + 2x
2) -e-2x:
yp2 = Ae-2x
y' = -2Ae-2x
y'' = 4Ae-2x
y'' + 2y' = 4Ae-2x - 4Ae-2x = 0
yp2 = Axe-2x
y' = Ae-2x - 2Ax-2x
y'' = -2Ae-2x - 2Ae-2x + 4Axe-2x = (4Ax - 4A)e-2x
y'' + 2y' = (4Ax - 4A)e-2x + 2(Ae-2x - 2Axe-2x) = (-2A)e-2x
-2Ae-2x = -e-2x
A = 1/2
yp2 = xe-2x/2
Step3: General solution
y(x) = yh + yp1 + yp2 = c1 + c2 e-2x + x2/2 + 2x + xe-2x/2
y(x) = yh + yp1+ yp2 = c1 + c2 e-2x + x2/2 + 2x + xe-2x/2
2025-04-03
y'' - 2y' + y = 3sin(2x)
y'' - 2y' + y = 3sin(2x)
Step1: 특성방정식
r2 - 2r + 1 = 0
(r - 1)2 = 0
r = 1 (중근)
일반해 yh = (c1 + c2x)ex
Step2: 미정계수법
yp = A cos(2x) + B sin(2x)
yp' = -2A sin(2x) + 2B cos(2x)
yp'' = -4A cos(2x) - 4B sin(2x)
원 식에 대입
y'' - 2y' +y = 3sin(2x)
(-4A cos(2x) - 4B sin(2x) ) - 2(-2A sin(2x) + 2B cos(2x)) +(A cos(2x) + B sin(2x)) = 3sin(2x)
(-3A - 4B) cos(2x) + (4A - 3B - 3) sin(2x) = 0
(-3A - 4B) = 0
(4A - 3B - 3) = 0
A = -4B/3
A(-4B/3) - 3B = 3
B = -9/25, A = (-4/3)(-9/25) = 12/25
y = (c1+c2x)ex + (12/25) cos(2x) - (9/25) sin(2x)
pdf compress
pdf 파일 압축하는 프로그램 여럿 있다.
그 중 하나가 Adobe 에 있다. 원래의 파일을 인터넷으로 전송하면 그 파일을 압축해서 내려받는 방식.
다른 곳도 여럿 있는데, 비교해보고 편한 것으로 골라 쓰면 될 듯.
2025-04-02
DE y'' - 4y' + 8y = 0
y'' - 4y' + 8y = 0
Step1:
r2 - 4r + 8 = 0
Step2:
r = -(-4)±√(-4)²- 4x1x8 2x1
r = -(-4) ± √-16 2x1
r = 2 ± 2i
Step 3:
y = eax(c1 cos(bx) + c2 sin(bx))
Substitute a = 2, b = 2
y = e2x(c1 cos(2x) + c2 sin(2x))
DE y''-5y-14=0
Differential Equation y'' - 5y - 14 = 0 을 풀어라
Step 1: r2 - 5r - 14 = 0
Step 2: (r+2)(r-7) = 0. So, r = -2 or r = 7
Step 3: y = c1e-2x + c2e7x
convolution
Convolution 정의 주의
(f*g)(t) = ∫ ∞ ∞ f(𝜏) g(t-𝜏) dt
위의 정의에서 주의할 것이 있다.
컴퓨터에서 곱하기를 *로 표시하는데(영어 소문자 x와 구별하기 위함), 수학에서 convolution을 나타낼 때도 * 기호를 쓴다.
수학에서는 위와 같이 f(𝜏)와 g(t-𝜏) 사이에 * 표시를 안 넣으면 곱하기로 알고 있으면 된다.
컴퓨터 프로그램에서는 * 표시를 생략하면 안 된다.
수학에서 convolution 나타내는 기호 *와 컴퓨터 프로그램에서 쓰는 기호 *는 같은 기호를 쓰지만, 뜻이 다르므로 주의.