Điểm số từng bài học của Trẩu, điểm số cuối khoá của Trẩu được tính dựa theo điểm số từng bài và điểm số của bài tập cuối khoá
3. Vòng lặp (loop):
Tham gia các buổi học live mỗi tuần cùng các thầy cô và làm bài tập về nhà ôn tập các khái niệm và lập trình.
Bắt đầu loop: khoá học khai giảng
Điều kiện để kết thúc loop: ngày khoá học kết thúc
Step: thời gian 1 tuần học
Action for every iteration: Tham gia và tương tác trong các buổi học. Ôn tập tài liệu và làm bài tập về nhà
4. Câu điều kiện (conditional):
Ví dụ đơn giản nhỏ:
Điểm số: nếu bạn Trẩu làm đúng bài sẽ được cộng điểm. Nếu điểm bạn Trẩu trong khoảng … sẽ được tuyên dương
5. Kết hợp câu điều kiện trong vòng lặp:
Ngoài các hành động bạn Trẩu chắc chắn sẽ thực hiện mỗi lần đi qua vòng lặp (mỗi tuần), bạn Trẩu sẽ kết hợp cùng các câu điều kiện để có thể hoàn thành khoá học tốt hơn.
Bạn Trẩu muốn được điểm cao và là một trong những học sinh xuất sắc khi tốt nghiệp khoá CS 101 nên đã đặt ra một số thói quen để bản thân cố gắng hơn mỗi tuần
Mỗi cuối tuần (một iteration của vòng lặp): bạn Trẩu sẽ tự ôn tập và làm bài tập về nhà.
Nếu bạn Trẩu không hiểu khái niệm được học trên lớp -> bạn Trẩu sẽ lên đọc lại tài liệu trên LMS và hỏi câu hỏi để các anh chị trợ giảng có thể giúp đỡ
Nếu bạn Trẩu nhận được điểm không được như mong muốn trong một bài tập về nhà: bạn Trẩu sẽ cố gắng tự tìm hiểu lý do cho lỗi sai của mình và ôn tập lại kiến thức.
— — —
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
Ở bài học số 1 của lớp CS 101, chúng ta đã học về số nhị phân và bảng mã ASCII. Sang bài học số 2, chúng ta sẽ tìm hiểu về khái niệm biến trong Python. Biến được dùng để lưu dữ liệu. Trong Python, có một số kiểu dữ liệu cơ bản sau:
1. Kiểu số (Numbers):
Integer (số nguyên): Số nguyên là số không có phần thập phân.
Ví dụ: x = 20
Trong máy tính, chúng ta có một loại số gọi là số nguyên. Số nguyên này có thể là các số như 1, 2, 3, -1, -2, -3, và nhiều hơn nữa. Trong Python, số nguyên không có giới hạn về số lượng chữ số, nghĩa là nó có thể là một số rất lớn hoặc rất nhỏ. Nói cách khác, Python có thể tính toán các số nguyên rất lớn mà không cần phải lo lắng về giới hạn số lượng chữ số.
Điều này khác với một số ngôn ngữ lập trình khác, nơi số nguyên có giới hạn số lượng chữ số. Ví dụ, nếu một số nguyên vượt quá giới hạn này, thì nó sẽ không thể biểu diễn được. Nhưng trong Python, không có giới hạn số lượng chữ số, vì vậy chúng ta có thể tính toán các số nguyên rất lớn hoặc rất nhỏ mà không cần phải lo lắng về nó.
Float (số thực): Số thực là số có phần thập phân.
Ví dụ: x = 20.5
Số thực trong Python là các số có phần nguyên và phần thập phân, ví dụ như 3.14 hoặc 2.5. Nhưng các số thực này có thể bị sai số vì máy tính chỉ có thể tính toán chúng một cách chính xác trong một giới hạn nhất định.
Ví dụ, nếu bạn yêu cầu máy tính tính toán 1/3, kết quả trả về sẽ là một số gần đúng, không chính xác là 0.33333333333… Máy tính chỉ có thể tính toán với một độ chính xác hữu hạn.
Do đó, khi làm việc với số thực, chúng ta cần lưu ý rằng chúng có thể bị sai số.
Trong Python, toán tử chia (“/”) thực hiện phép chia dạng số thực, có nghĩa là nó trả về một số thực. Toán tử double slash ( “//”) thực hiện phép chia nguyên, có nghĩa là nó làm tròn xuống số nguyên gần nhất và trả về một số nguyên. Toán tử chia (“/”) trả về một số thực ngay cả khi một trong các toán hạng là số nguyên.
Ví dụ:
a = 1 / 3
b = 1 // 3
c = 1. / 3.
print(a) # in ra 0.3333333333333333
print(b) # in ra 0
print(c) # in ra 0.3333333333333333
Complex (số phức): Số phức là số gồm một phần thực và một phần ảo.
Ví dụ: x = 1j
2. Kiểu chuỗi (Strings):
Chuỗi (string): là một chuỗi các ký tự Unicode.
Ví dụ: x = “Hello World”
Để nối các chuỗi trong Python, bạn có thể sử dụng các phương thức sau:
Dùng dấu cộng (+):
Bạn có thể nối các chuỗi bằng cách sử dụng toán tử cộng (+).
Ví dụ:
str1 = “Hello”
str2 = “world”
str3 = str1 + str2
print(str3) # In kết quả: “Helloworld”
Sử dụng phương thức format():
Phương thức format() được sử dụng để nối các chuỗi và thay đổi giá trị của các biến trong chuỗi.
Ví dụ:
name = “John”
age = 25
result = “My name is {} and I am {} years old”.format(name, age)
print(result) # In kết quả: “My name is John and I am 25 years old”
3. Kiểu Boolean (Boolean):
Boolean: chỉ có hai giá trị True hoặc False.
Ví dụ: x = True
Mỗi kiểu dữ liệu có cách sử dụng và đặc điểm riêng, và Python cũng hỗ trợ nhiều phương thức để thao tác với chúng.
Đây là các cách để chuyển đổi giữa các kiểu dữ liệu khác nhau trong Python:
1. Chuyển đổi từ kiểu dữ liệu float sang int:
Bạn có thể chuyển đổi một số thực sang một số nguyên bằng cách sử dụng hàm int(). Lưu ý rằng việc này sẽ làm mất phần thập phân của số.
Ví dụ:
x = 3.14159
y = int(x)
print(y) # Output: 3
2. Chuyển đổi từ kiểu dữ liệu int sang float:
Bạn có thể chuyển đổi một số nguyên sang một số thực bằng cách sử dụng hàm float().
Ví dụ:
x = 42
y = float(x)
print(y) # Output: 42.0
3. Chuyển đổi từ string “True” sang boolean True:
Bạn có thể chuyển đổi một chuỗi chứa giá trị “True” sang một giá trị boolean True bằng cách sử dụng hàm bool().
Ví dụ: x = “True”
y = bool(x)
print(y) # Output: True
4. Chuyển đổi từ boolean True sang string “True”:
Bạn có thể chuyển đổi một giá trị boolean True sang một chuỗi chứa giá trị “True” bằng cách sử dụng hàm str().
Ví dụ: x = True
y = str(x)
print(y) # Output: ‘True’
5. Chuyển đổi từ kiểu dữ liệu float sang complex:
Bạn có thể chuyển đổi một số thực sang một số phức bằng cách sử dụng hàm complex(). Lưu ý rằng phần thực của số phức này sẽ là giá trị của số thực ban đầu và phần ảo sẽ là 0.
Ví dụ:
x = 3.14159
y = complex(x)
print(y) # Output: (3.14159+0j)
— — —
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
Trong bài học đầu tiên của lớp CS 101 – Nhập môn khoa học máy tính với Python, chúng ta tìm hiểu về hệ thống đếm nhị phân và ứng dụng của nó trong khoa học máy tính.
1. Ôn tập về số mũ:
Trước khi tìm hiểu về các hệ thống số đếm, chúng ta cùng ôn tập về phép tính luỹ thừa và số mũ trong toán học nhé. Luỹ thừa là cách biểu diễn ngắn gọn của phép tính nhân các số giống nhau nhiều lần. Ví dụ: 23 = 2x2x2, trong đó 2 là cơ số, 3 là số mũ. Trường hợp đặc biệt với số mũ là 0 thì kết quả sẽ bằng 1. Ví dụ: 20 = 1. Phép toán ngược lại của luỹ thừa là log (logarithm). Ví dụ: log28 = 3 vì 23 = 8. Phép toán này giúp tìm số mũ khi biết cơ số.
2. Hệ thập phân (Decimal) và nhị phân (Binary):
Hệ thống đếm thập phân sử dụng 10 chữ số 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 để biểu diễn những số tự nhiên. Nguồn gốc của hệ thống đếm thập phân có thể bắt nguồn từ việc con người có 10 ngón tay. Hệ thống đếm thập phân biểu diễn số tự nhiên nhờ vào cơ số 10. Ví dụ: 2023 = 3×100 + 2×101 + 0x102 + 2×103. Hệ thống đếm thập phân được sử dụng phổ biến cho con người đếm và tính toán. Tuy nhiên, máy tính lại cần một hệ thống đếm khác để có thể thuận tiện biểu diễn các tính toán phức tạp.
Hệ thống đếm nhị phân chỉ sử dụng 2 chữ số 0, 1 để biểu diễn những số tự nhiên. Hệ thống đếm nhị phân biểu diễn số tự nhiên nhờ vào cơ số 2. Ví dụ: 11111100111 = 1×20 + 1×21 + 1×22 + 0x23 + 0x24 + 1×25 + 1×26 + 1×27 + 1×28 + 1×29 + 1×210 = 2023. Hệ thống đếm nhị phân được sử dụng trong máy tính, biểu diễn 2 trạng thái: bật (1) và tắt (0). Hai trạng thái này được dùng để lưu trữ và truyền dữ liệu trong máy tính. Mỗi trạng trái đó được gọi là 1 bit trong máy tính. Hệ thống đếm nhị phân ngày nay được nghiên cứu ở châu Âu vào thế kỷ 16, 17 bởi nhà toán học Gottfried Leibniz. Tuy nhiên, hệ thống đếm nhị phân đã xuất hiện trước đó ở nhiều nền văn hoá cổ như Ai Cập, Trung Quốc, và Ấn Độ.
Vậy tại sao máy tính lại cần hệ thống đếm nhị phân? Chúng ta sẽ liên hệ một ví dụ đơn giản về công tắc điện. Chúng ta sẽ dễ dàng biểu diễn 2 trạng thái của công tắc điện (bật, tắt) dễ dàng hơn nếu dùng 2 chữ số 0, 1 trong hệ nhị phân thay vì dùng 10 chữ số trong hệ thập phân. Một ví dụ khác là biểu diễn phép tính cộng. Khi dạy máy tính phép tính cộng, chúng ta chỉ cần dạy máy tính sử dụng bảng sau
Nếu chúng ta dùng hệ đếm thập phân thì máy tính cần phải học bảng phức tạp sau
Với con người, hệ đếm nhị phân khá phức tạp vì để biểu diễn một số không lớn lắm như 2023 trong hệ nhị phân, chúng ta cần phải sử dụng quá nhiều chữ số. Tuy nhiên đó lại không phải là trở ngại với máy tính.
3. Ứng dụng của số nhị phân:
Một trong những ứng dụng của số nhị phân là biểu diễn các phép toán logic (boolean logic). Logic nhị phân được giới thiệu từ những năm 1930 bởi nhà toán học người Anh, George Boole. Kể từ đó, số nhị phân được sử dụng nhiều trong điện tử và máy tính. Số nhị phân được sử dụng trong xử lý ảnh, thu tiếng audio và phim HD, lưu trữ và xử lý số liệu. Một bức ảnh sẽ gồm những pixel được biểu diễn bởi số nhị phân. Chuỗi số nhị phân biểu diễn hình ảnh còn thể hiện màu sắc của bức ảnh. Ngoài ra vì số nhị phân được dùng để lưu dữ liệu nên dung lượng bộ nhớ của máy tính, điện thoại thường là luỹ thừa của 2. 1 byte tương ứng với 8 bits, 1 KB = 1024 bytes, 1 MB = 1024 KBs. Ngoài ra luỹ thừa của 2 còn xuất hiện trong trò chơi 2048 nổi tiếng.
Một ứng dụng quan trọng khác của số nhị phân đó là bảng mã ASCII. Bảng mã ASCII dùng để mã hoá các ký tự trong máy tính và trên internet. Bảng mã ASCII cơ bản có thể biểu diễn được 128 ký tự, bao gồm bảng chữ cái tiếng anh viết hoa và viết thường, chữ số từ 0 đến 9, và một vài ký tự đặc biệt. Ký tự trong bảng mã ASCII có thể được biểu diễn bởi hệ thập phân và hệ nhị phân. Vì máy tính sử dụng 7 bits để biểu diễn một ký tự nên bảng mã ASCII cơ bản có thể biểu diễn được 27 = 128 ký tự. Tuy nhiên vẫn có những bảng mã ASCII có thể biểu diễn được 256 ký tự bằng cách sử dụng 8 bits. Hệ nhị phân còn có thể được sử dụng để biểu diễn emoji như chúng ta đã học ở bài 1 của lớp CS 101.
4. Cách đổi số từ hệ thập phân sang nhị phân và ngược lại:
Để đổi từ số nhị phân sang thập phân, chúng ta chỉ cần sử dụng các luỹ thừa của 2 tương ứng với các vị trí của từng chữ số. Ví dụ: 11111100111 = 1×20 + 1×21 + 1×22 + 0x23 + 0x24 + 1×25 + 1×26 + 1×27 + 1×28 + 1×29 + 1×210 = 2023. Trong Python, chúng ta có thể sử dụng câu lệnh int(“11111100111”, 2).
Để đổi từ số trong hệ thập phân sang nhị phân, chúng ta sẽ chia số đó liên tục cho 2 và ghi lại số dư (0 hoặc 1). Sau đó chúng ta ghi lại số dư từ phép chia cuối cùng lên đầu tiên. Ví dụ:
2023 / 2 = 1011 dư 1
1011 / 2 = 505 dư 1
505 / 2 = 252 dư 1
252 / 2 = 126 dư 0
126 / 2 = 63 dư 0
63 / 2 = 31 dư 1
31 / 2 = 15 dư 1
15 / 2 = 7 dư 1
7 / 2 = 3 dư 1
3 / 2 = 1 dư 1
1 / 2 = 0 dư 1
Như vậy: 2023 trong hệ nhị phân là 11111100111. Trong Python, chúng ta có thể sử dụng câu lệnh format(2023, “b”).
5. Tổng kết:
Hệ đếm nhị phân được máy tính sử dụng thay vì hệ thống thập phân. Hệ nhị phân dựa trên luỹ thừa của 2. Một vài ứng dụng của hệ nhị phân bao gồm lưu trữ dữ liệu dưới dạng bits, xử lý ảnh, tín hiệu, và biểu diễn ký tự bằng bảng mã ASCII. Các bạn học sinh còn thấy ứng dụng nào hữu ích của số nhị phân thì có thể chia sẻ trên STEAMese Profile nhé.
Xin chào các bạn, mình là Trẩu của lớp CS 101 đây! Mình rất vui khi được quay lại đồng hành với các bạn ở kỳ học mùa Xuân năm nay. Chắc các bạn cũng biết là chúng mình sẽ cùng học ngôn ngữ lập trình Python ở lớp CS 101 đúng không nào? Nhưng mình tin rằng cũng sẽ có nhiều bạn học sinh có thắc mắc: “Sau khi hoàn thành khóa học CS 101 thì chúng mình sẽ sử dụng kỹ năng lập trình Python như thế nào?”. Để giải đáp thắc mắc này, các bạn hãy cùng Trẩu tìm hiểu một số ứng dụng của Python mà các bạn học sinh của lớp CS 101 đãlàm nhé.
1. Phần mềm giúp quản lý các việc cần làm trong ngày (To-do list):
Có bao giờ các bạn quên mất ngày nộp bài tập về nhà hay lỡ một buổi sinh nhật của bạn mình chưa?? Có bao giờ bạn từng sử dụng những công cụ hay phần mềm hỗ trợ quản lý thời gian và hoạt động của mình như Google Calendar? Các bạn có thấy những sản phẩm đó “kool” không nào. Thật tuyệt vời là với Python, chúng mình hoàn toàn có thể tự tạo ra một công cụ hữu ích như vậy. Hãy cùng Trẩu khám phá hai sản phẩm “To do list” của các bạn học sinh đến từ nhóm Vipers và Staregos của lớp CS 101 nhé.
Nhóm Vipers đã sử dụng Python và Tkinter để tạo ra phần mềm giúp kiểm tra tiến độ hoàn thành của các công việc, cũng như thêm và bớt công việc. Vipers còn tạo ra cả game để các bạn thư giãn nữa đấy. Các bạn trong team Vipers đã sử dụng rất nhiều kiến thức được học từ lớp CS 101 như kiểu cấu trúc dữ liệu từ điển (dictionary) để lưu dữ liệu của từng công việc, hàm trong Python (function) để viết các tính năng của phần mềm, câu điều kiện (if condition), mảng (array), và lập trình hướng đối tượng (OOP) để làm game.
Phần mềm của các bạn nhóm Staregos thì đầy màu sắc với giao diện bắt mắt. Phần mềm được tạo ra từ Python và Pygame. Các bạn đã sử dụng kỹ năng hội họa được dạy trong bài Lớp học hoạt họa của khóa học CS 101. Ngoài ra, các bạn còn sử dụng các kiến thức khác như lập trình hướng đối tượng để tạo ra các thành phần của phần mềm như thẻ công việc, nút bấm, mảng và từ điển để lưu dữ liệu của các thẻ công việc. Phần mềm của nhóm Staregos giúp người dùng sắp xếp các công việc theo ngày, theo tuần.
2. Phần mềm giúp mô phỏng các thí nghiệm vật lý (Virtual Physics Experiments – VPE):
Các bạn học sinh có sợ học môn vật lý và hóa học không? Trước đây một số kiến thức Trẩu cảm thấy rất khó hiểu nhưng nhờ các bạn học sinh của lớp CS 101 mà giờ Trẩu thấy dễ dàng hơn rất nhiều bằng cách được thực hành các khái niệm trên lớp. Các bạn có tin là mình có thể làm thí nghiệm mà không cần trang thiết bị và đến phòng thí nghiệm không? . Với Python, các bạn nhóm Dragonfly của lớp CS 101 đã tạo ra “phòng thí nghiệm ảo” mà mình có thể cùng nhau làm các thí nghiệm vật lý. Với từng thí nghiệm, phần mềm cho phép người dùng thay đổi các tham số để hiểu hơn về thí nghiệm và khái niệm. Phần mềm có các hệ thống nút bấm, menu giúp người dùng dễ dàng tương tác. Phần mềm có rất nhiều thí nghiệm như về ánh sáng, con lắc, rơi tự do, và ném xiên. Nhờ Dragonfly mà Trẩu cảm thấy môn vật lý “dễ nhằn” hơn nhiều và cảm thấy hứng thú tìm hiểu hơn. Để tạo ra phòng thí nghiệm ảo như này, các bạn trong nhóm Dragonfly đã sử dụng thành thạo các kiến thức được học trong lớp CS 101 như lập trình hướng đối tượng, câu điều kiện, vòng lặp, và mảng. Ví dụ như trong thí nghiệm con lắc, mảng giúp lưu vị trí của con lắc theo thời gian, cùng với kiến thức về vòng lặp để vẽ đồ thị tọa độ và đường quay của con lắc.
3. Trò chơi giúp tìm hiểu kiến thức địa lý Việt Nam (Wordle Vietnamese Geography):
Các bạn có biết đến trò chơi Wordle không? Trẩu và các bạn học sinh lớp CS 101 rất thích trò chơi này. Lấy cảm hứng từ Wordle, nhóm Wero của lớp CS 101 đã tạo ra một trò chơi thú vị giúp các bạn học sinh có thể tìm hiểu thêm về các thành phố tại Việt Nam bằng Python và Pygame. Người chơi sẽ đoán tên các tỉnh thành ở Việt Nam dựa trên các đặc điểm như hình dạng lãnh thổ địa lý và danh lam thắng cảnh. Trò chơi cũng sẽ hiển thị hướng và khoảng cách từ nơi người chơi đoán đến đáp án và gợi ý được thay đổi qua mỗi lần đoán để người chơi có thể dễ dàng đoán được địa điểm ở Việt Nam. Với mỗi lượt chơi, một địa điểm ngẫu nhiên sẽ được tạo ra. Để tao ra trò chơi này, các bạn trong nhóm Wero đã sử dụng rất nhiều kiến thức học được từ lớp CS 101 như mảng, lập trình hướng đối tượng, vòng lặp và thư viện random để tạo câu hỏi ngẫu nhiên.
4. Ứng dụng liên quan đến robot và trí tuệ nhân tạo (Robotics):
Trẩu xin được giới thiệu nhóm Robotics của lớp CS 101 bao gồm các bạn có hứng thú với tự động hóa và trí tuệ nhân tạo. Các bạn đã nâng cấp trò chơi Ai là triệu phú, là dự án cuối khóa của lớp CS 101, tích hợp trí tuệ nhân tạo. Nhóm đã tạo ra một tính năng sử dụng thuật toán trí tuệ nhân tạo nhận diện số đếm qua các ngón tay trên thư viện opencv. Người chơi chỉ cần có một webcam và với mỗi câu hỏi, người chơi sẽ đưa số ngón tay tương ứng với đáp án lựa chọn. Trò chơi sẽ nhận diện xem đó là đáp án nào và kiểm tra đáp án đúng. Ngoài ra, nhóm cũng đã sử dụng thành thạo thư viện Pygame và các câu lệnh đọc, viết file text được học trong khóa CS 101, để thêm chức năng cho chép người dùng thêm câu hỏi mới. Hãy cùng tham gia khóa học CS 101 kỳ học mùa xuân năm nay để trải nghiệm cùng làm trò chơi này nhé!
5. Các ứng dụng khác sử dụng Python:
Trong khóa học CS 101, các thầy cô cũng lồng ghép rất nhiều ứng dụng của Python trong các bài học. Một số bạn học sinh tạo ra các trò chơi, phần mềm giải mã Caesar, phần mềm giúp giải bài toán, phần mềm tính chỉ số IBM… Các bạn biết không các kiến thức của lớp CS 101 tuy cơ bản nhưng cũng đủ để tạo ra các ứng dụng hay và hữu ích trong đời sống. Đồng thời đó cũng là nền tảng để các bạn học sinh có thể phát triển, tìm hiểu thêm các kiến thức mới như lập trình game, làm website, hay trí tuệ nhân tạo. Thời gian gần đây ChatGPT của công ty OpenAI đã gây ra một cơn sốt trong giới công nghệ đúng không nào. ChatGPT sử dụng mô hình trí tuệ nhân tạo trên một cơ sở dữ liệu lớn về ngôn ngữ. Các kiến thức nền tảng về khoa học máy tính được học trong lớp CS 101 cũng xuất hiện một phần nhỏ trong quá trình hình thành nên ChatGPT: từ việc lưu trữ dữ liệu, đọc dữ liệu, hàm, thuật toán, cấu trúc dữ liệu, đến lập trình hướng đối tượng. Ngoài ra ChatGPT cũng sẽ rất hữu ích cho các bạn học sinh muốn tìm hiểu thêm về ngôn ngữ Python và khoa học máy tính bằng cách đặt câu hỏi cho ChatGPT.
STEAM for Vietnam hi vọng kiến thức cơ bản về khoa học máy tính và lập trình Python sẽ được tiếp cận đến nhiều bạn trẻ Việt Nam hơn, để có thể tạo ra những ứng dụng, công cụ hữu ích cho cuộc sống. Hiện tại, khoá học CS 101 của chúng mình đang được mở đơn từ ngày 25/02 đến ngày 25/03/2023! Đây cũng sẽ là lần duy nhất trong năm 2023 mà các bạn có thể gặp chúng mình – Trẩu và Tre đó! Chính vì thế, các bạn học sinh đừng bỏ lỡ cơ hội này và hãy đăng kí học ngay nhé!
Trẩu xin bật mí một xíu xìu về hoạt động Hè 2023 này, sẽ có một cuộc thi Hackathon diễn ra. Và các bạn sẽ cần phải ứng dụng kiến thức Python để tham gia thi đấy! Nhanh tay đăng kí học ngay hôm nay để trang bị kiến thức trước thềm cuộc thi nhé!
📌 Tìm hiểu thêm về các lớp học: https://www.steamforvietnam.org/courses
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
1. Tên biến chỉ có thể chứa các ký tự: A-Za-z0-9_ (alpha-numeric và underscore)
2. Tên biến không được bắt đầu bằng số.
3. Tên biến phải bắt đầu bằng các ký tự A-Z, a-z hoặc _.
Ví dụ:
a = 1 # Hợp lệ
__a = 1 # Hợp lệ
_a = 1 # Hợp lệ
...
â = 1 # Không hợp lệ : Chứa ký tự không thuộc A-Za-z0-9_
1a = 1 # Không hợp lệ : Bắt đầu bằng số
~a = 1 # Không hợp lệ : Chứa ký tự không thuộc A-Za-z0-9_
Lưu ý: Biến trong Python phân biệt chữ hoa-thường. Ví dụ:
a = 1
A = 2
print(a, A)
# Output: 1 2
Virtual Environment (môi trường ảo) là môi trường có các thư viện độc lập, tách biệt khỏi môi trường Python chính (môi trường hệ thống). Trong môi trường này chỉ có các thư viện cơ bản và các binary cơ bản của Python. Các thư viện (ngoài Python Standard Library) phải được cài lại.
Tạo Virtual Environment Trên Windows, mở “Command Prompt” hoặc “Powershell”. Trên Linux, mở “Terminal”.
python3 -m venv <tên-venv>
<tên-venv>: Thay bằng tên của venv, ví dụ “env”, “venv”, “pyvenv”
Kích hoạt Virtual Enviroment Windows CMD
CALL <tên-venv>\Scripts\activate.bat
Windows Powershell
<tên-venv>\Scripts\Activate.ps1
Vấn đề với Powershell trên Windows 10: Powershell trên Windows 10 có thể ngăn bạn chạy script kích hoạt. Đó là do ExecutionPolicy. Làm theo bước ở dưới chỉ khi không thể chạy script kích hoạt. Mở powershell với quyền Administrator
git clone <repo> # Clone repo về máy
git checkout <branch> # Đổi branch
git checkout -b <branch> # Tạo branch tên <branch> đồng thời checkout vào branch đó
git branch # Hiện các branch, tương tự git branch --list.
git branch <branch> # Tạo branch tên <branch>. Nhưng không checkout vào branch đó
git branch -d <branch> # Xóa branch, chỉ khi các commit đã merge
git branch -D <branch> # Xóa branch, kể cả khi các commit chưa merge
git branch -m <branch> # Đổi tên branch hiện tại thành <branch>
git branch -a # Hiện danh sách các branch, local và remote
git fetch # Fetch remote, download các thay đổi từ remote về nhưng không ghi dè local.
git pull <remote> <branch> # Download <branch> từ <remote> và ghi đè lên local
git push <remote> <branch> # Đẩy local lên <branch> qua <remote>
git init # Tạo folder .git tại thư mục hiện hành, làm thư mục hiện tại thành 1 local
repo
git remote add <remote-name> <repo-url> # Tạo remote với <remote-name> tới <repo-url>.
Khi clone repo về thì mặc định có sẵn remote, không cần add.
git remote -v # Kiểm tra (các) remote của thư mục hiện tại.
Cách 1: IDE Mỗi IDE có một cách riêng để chạy file code. Vui lòng sử dụng Google để tìm hiểu cách sử dụng IDE của bạn. Cách 2a: Trực tiếp chạy như một executable Từ terminal:
C:\Users\phanm\OneDrive\Desktop> <tên-file>.py
Lưu ý: Tuy có thể gọi tên file để chạy trên Command Prompt (cmd), cmd sẽ không chạy file python, mà chuyển sang cho Python Interpreter (hoặc bất cứ ứng dụng nào được sử dụng làm mặc định để chạy file .py). Vì .PY không nằm trong biến môi trường (Environment Variables) PATHEXT. Từ File Explorer: Double-click vào file python để chạy. Cách này tương tự như cách dưới, nhưng không cần phải dùng Terminal. Thường sử dụng trên Windows.
Cách 2b: Chạy qua Python interpreter Từ terminal:
# Cmd hoặc Powershell
C:\Users\phanm\OneDrive\Desktop> python <tên-file>.py
# Terminal trên Mac/Linux
phanm@nhatlong ~
$ python3 <tên-file>.py
ls (Linux) / dir (Windows CMD) / gci (PS): Liệt kê các file/folder trong thư mục. Cú pháp: ls <thư-mục> hoặc ls
tree (Chung): Vẽ cây thư mục.
Ví dụ:
# Output sẽ khác nhau tùy vào hệ điều hành. Đây là của Windows
Folder PATH listing for volume New Volume
Volume serial number is 00000091 78E6:EB3A
G:.
├───assets
│ ├───fonts
│ ├───items
│ ├───npcs
│ └───player
├───data
│ ├───dialogues
│ └───levels
└───src
cat (Linux) / type (Windows CMD) / gc (PS): Đọc nội dung file và xuất lên màn hình.
Tác giả: Bạn Phan Mai Nhật Long – Học sinh STEAM for Vietnam
Mọi câu hỏi thắc mắc khác về học phần Get Started Course các phụ huynh học sinh và các con học sinh có thể gửi câu hỏi lên mục “Thảo luận” (Discussion) trên hệ thống LMS, hoặc thông qua email hello@steamforvietnam.org.
————————
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
Một số yếu tố toán học và hình học để lập trình game
Giới thiệu trò chơi
Bóng bàn là một trong những môn thể thao phổ biến trên toàn thế giới và điều đó cũng biến game ping pong trở thành một trong những game máy tính đầu tiên được ra đời vào năm 1972. Trò chơi có quy tắc chơi rất là đơn giản. Hai bên sẽ đỡ trả những quả bóng cho đến khi một bên không đánh trả được nữa. Ở đây chúng ta sẽ là một người chơi và đánh quả bóng bàn không bị rơi xuống đất. Các bạn học sinh hãy cùng trải nghiệm trò chơi trước khi bắt tay vào lập trình ở link sau: https://replit.com/@STEAM4VNOfficial/Pingpong#main.py
Bắt tay vào lập trình thôi nào
Bước 1: Khai báo thư viện sử dụng để lập trình trò chơi
Giống như các bài blog khác trong Pygame series (Link), chúng ta sẽ cần sử dụng thư viện pygame. Ngoài ra, chúng ta cũng cần có thư viện random để khởi tạo ngẫu nhiên hướng đi của quả bóng bàn khi mới bắt đầu trò chơi.
import pygame
import random
Bước 2: Khởi tạo một vài yếu tố cơ bản của trò chơi:
Hàm pygame.init() giúp chúng ta bắt đầu khởi tạo trò chơi. Thêm vào đó, các bạn hãy sử dụng vòng lặp while với biến start để lặp lại liên tục các hành động của người chơi và quả bóng, cho đến khi quả bóng rơi xuống đất. Biến start sẽ được khởi tạo với giá trị True. Khi bóng rơi xuống đất, biến start sẽ được thay đổi thành False.
Chúng ta cũng cần khởi tạo một số màu cơ bản dùng trong trò chơi, cho quả bóng, vợt bóng bàn, và màn hình. Giống như blog cờ caro (link), chúng ta sẽ sử dụng bảng mã RGB.
Black = (0,0,0)
Green = (0, 250, 0)
Yellow = (250, 250, 0)
Sau đó, các bạn tiếp tục khởi tạo màn hình cửa sổ trò chơi với kích thước 800×500 pixels bằng câu lệnh pygame.display.set_mode. Chúng ta cũng cài đặt màn hình màu đen bằng câu lệnh fill. Ngoài ra, câu lệnh pygame.display.set_caption sẽ giúp hiển thị tên của trò chơi.
Tương tự như game cờ caro, chúng ta sẽ sử dụng font freesansbold với kích thước 20 cho chữ trong game. Đồng thời, ta sử dụng thư viện random để khởi tạo chọn ngẫu nhiên một trong hai số 0 và 1, ứng với hướng di chuyển của quả bóng lúc bắt đầu trò chơi. Để cho game thêm phần thú vị, chúng ta sẽ tính điểm của người chơi và lưu vào biến score. Biến score sẽ được khởi tạo bằng 0:
direct = random.randint(0,1)
font = pygame.font.Font('freesansbold.ttf', 20)
score = 0
Bước 3: Khởi tạo 2 đối tượng chính của người chơi là quả bóng và trò chơi.
Chúng ta sẽ sử dụng khái niệm đối tượng và lớp đã được học ở bài 8 của khoá CS 101 để tạo quả bóng và người chơi. Chúng ta sẽ tạo lớp (class) Player với hai thuộc tính x và y, để lưu toạ độ của người chơi. Sau đó chúng ta sẽ tạo đối tượng (object) player của lớp Player để tạo một người chơi trong trò chơi. Trong trường hợp này người chơi sẽ là cái vợt bóng bàn ở vị trí (400,200) trên màn hình trò chơi khi bắt đầu.
Tương tự như vậy, chúng ta sẽ tạo lớp Ball và đối tượng ball để tạo một quả bóng ở vị trí (350,400) cho trò chơi. Vì chúng ta sử dụng khái niệm lập trình hướng đối tượng nên chúng ta có thể tạo ra rất nhiều người chơi và quả bóng khác nhau. Tất cả người chơi và quả bóng đều có hai thuộc tính là toạ độ x, y.
class Player:
def __init__(self, x, y):
self.x = x
self.y = y
class Ball:
def __init__(self, x, y):
self.x = x
self.y = y
ball = Ball(400, 200)
player = Player(350, 400)
Bước 4: Vẽ các yếu tố đồ hoạ lúc bắt đầu game
Trong trò chơi này, quả bóng sẽ là hình tròn, người chơi và mặt đất sẽ là hình chữ nhật. Chúng ta sẽ bắt đầu với câu lệnh pygame.display.flip(). Để vẽ hình tròn, ta sẽ sử dụng câu lệnh pygame.draw.circle() với 4 inputs: màn hình game (screen), màu sắc, toạ độ của tâm hình tròn, và bán kính của hình tròn. Toạ độ của tâm hình tròn sẽ là 2 thuộc tính x và y của đối tượng ball. Chúng ta sẽ lấy thuộc tính của đối tượng bằng câu lệnh đã học ở bài 8 của khoá CS 101. Bán kính của quả bóng là 20 và quả bóng màu xanh lá cây.
Để vẽ hình chữ nhật, chúng ta sẽ sử dụng câu lệnh pygame.draw.rect() với 3 inputs: màn hình, màu sắc, và đối tượng hình chữ nhật trong pygame. Đối tượng hình chữ nhật được định nghĩa bởi câu lệnh pygame.Rect() với 4 inputs. Hai inputs đầu tiên xác định toạ độ của đỉnh bên trái trên cùng của hình chữ nhật. Input thứ ba là chiều dài của hình chữ nhật. Input thứ tư là chiều rộng của hình chữ nhật. Ví dụ, hình chữ nhật biểu diễn người chơi có chiều dài là 100 và chiều rộng là 20. Ngoài ra, toạ độ của đỉnh trên cùng bên trái được xác định bằng thuộc tính x, y của đối tượng player. Chúng ta sẽ vẽ hình chữ nhật biểu diễn người chơi bằng màu vàng và hình chữ nhật biểu diễn mặt đất bằng màu đỏ.
Ngoài ra, chúng ta sẽ sử dụng vòng lặp for để đi qua tất cả các tương tác của người dùng với trò chơi, và đóng game khi người dùng ấn vào nút đóng. Chúng ta cũng định nghĩa biến move để lấy ra nút người chơi bấm trên bàn phím để di chuyển hình chữ nhật màu vàng.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
move = pygame.key.get_pressed()
Bước 5: Code phần di chuyển của người chơi
Người chơi sẽ có 2 hướng di chuyển: sang trái hoặc sang phải. Khi người chơi ấn nút sang trái, toạ độ x của người chơi sẽ giảm đi 0.5. Khi người chơi ấn nút sang phải, toạ độ x sẽ tăng thêm 0.5. Toạ độ x sẽ bằng 0 nếu người chơi đi ra khỏi góc trái màn hình (x < 0). Toạ độ x sẽ bằng 700 nếu người chơi đi ra khỏi góc phải màn hình (x > 700).
if move[pygame.K_LEFT]:
player.x -= 0.5
if player.x < 0:
player.x = 0
elif move[pygame.K_RIGHT]:
player.x += 0.5
if player.x > 700:
player.x = 700
Bước 6: Code phần di chuyển quả bóng:
Chúng ta quy định hướng di chuyển của quả bóng bằng các chỉ số như hình vẽ trên. Bây giờ chúng ta sẽ nhận xét và vẽ hình khi mà quả bóng va chạm với các cạnh với các hướng thì nó sẽ thay đổi sao. Khi mà quả bóng va vào người chơi hay va vào bức tường thì quả bóng sẽ bật lại theo hướng ngược với nó va chạm vào.
Hướng 0 là hướng đi lên trên bên trái. Khi đi theo hướng này, toạ độ x và y của quả bóng đều bị giảm đi 0.4. Vì quả bóng có bán kính 20 nên khi toạ độ tâm của quả bóng bé hơn 20 ở x thì quả bóng đã va vào bức tường bên trái và bị bật lại theo hướng 1. Tương tự, khi toạ độ y bé hơn 20, quả bóng va vào bức tường ở trên và bật lại theo hướng 3. Hướng 1 là hướng đi lên bên phải. Hướng 3 là hướng đi xuống bên trái. Khi bóng đi theo hướng 1, toạ độ x được thêm 0.4 và toạ độ y bị trừ đi 0.4. Vì màn hình có kích thước 800 theo chiều x và quả bóng có bán kính 20 nên khi bóng đi theo hướng 1, nếu toạ độ x lớn hơn 780, bóng đã va vào bức tường bên phải. Bóng sẽ bật ra theo hướng 0. Tương tự, nếu toạ độ y của quả bóng bé hơn 20, bóng đã va vào bức tường ở trên và bật ra theo hướng 2. Khi bắt đầu trò chơi, quả bóng sẽ được ngẫu nhiên chọn di chuyển theo hướng 0 hoặc hướng 1.
# BALL
if direct == 0: # LEFT UP
ball.x -= 0.4
ball.y -= 0.4
if ball.x < 20:
direct = 1
if ball.y < 20:
direct = 3
if direct == 1: # RIGHT UP
ball.x += 0.4
ball.y -= 0.4
if ball.x > 780:
direct = 0
if ball.y < 20:
direct = 2
Hướng 2 là hướng đi xuống bên phải. Khi quả bóng đi theo hướng này, toạ độ x và y được cộng thêm 0.4. Nếu quả bóng va vào cạnh dưới và ở vị trí người chơi thì họ sẽ được cộng điểm, còn không họ sẽ thua. Để kiểm tra điều kiện này, chúng ta có thể sử dụng câu lệnh điều kiện if và phép toán and để kết hợp nhiều điều kiện. Chúng ta có thể dễ dàng đặt các điều kiện với lưu ý là quả bóng có bán kính 20 và hình chữ nhật biểu diễn người chơi có chiều dài là 100. Khi quả bóng ở vị trí người chơi, điểm sẽ được cộng 1 và quả bóng bật lại theo hướng 1. Ngoài ra chúng ta phải kiểm tra xem quả bóng có va vào bức tường bên phải chưa. Nếu quả bóng va vào bức tường bên phải, quả bóng sẽ bật lại theo hướng 3 là hướng đi xuống bên trái. Tương tự, chúng ta có trường hợp quả bóng theo hướng 3. Ngoài ra, người chơi sẽ thua khi quả bóng chạm đất. Vì chiều rộng của màn hình trò chơi là 500 nên khi toạ độ y của tâm quả bóng ở 480, biến start sẽ chuyển sang False và người chơi đã thua.
if direct == 2: # RIGHT DOWN
ball.x += 0.4
ball.y += 0.4
if ball.y >= player.y - 20 and ball.y <= player.y + 20 and ball.x >= player.x and ball.x <= player.x + 100:
direct = 1
score += 1
if ball.x > 780:
direct = 3
if direct == 3: # LEFT DOWN
ball.x -= 0.4
ball.y += 0.4
if ball.y >= player.y - 20 and ball.y <= player.y + 20 and ball.x >= player.x and ball.x <= player.x + 100:
direct = 0
score += 1
if ball.x < 20:
direct = 2
if ball.y >= 480:
start = False
Bước 7: Hoàn thiện phần kết thúc trò chơi:
Phần kết thúc trò chơi sẽ có màn hình màu trắng và có chữ You Lose cùng với điểm số. Chúng ta có thể sử dụng các câu lệnh font.render, screen.blit, text.get_rect tương tự game cờ caro (link) để in thông báo ra màn hình. Đồng thời sử dụng câu lệnh pygame.quit() để kết thúc trò chơi.
Trò chơi ping pong này thật thú vị phải không các bạn! Sau khi hoàn thành trò chơi, chúng ta đồng thời đã áp dụng được ngay các kiến thức lập trình với pygame, kiến thức toán và kiến thức vật lý về phản xạ của quả bóng khi đập vào tường. Các bạn học sinh hãy thử sáng tạo và cải tiến code bằng cách áp dụng các định luật vật lý về phản xạ như định luật Snell (học ở chương trình vật lý 7) để có thể tạo được hiệu ứng bật lại của quả bóng đúng hơn. Ngoài ra, các bạn có thể tạo thêm người chơi, thêm quả bóng cho trò chơi nhé.
Sau khi hoàn thành dự án cá nhân, các bạn đừng quên chia sẻ chương trình của mình lên STEAMese Profile để thầy cô và các bạn cùng trải nghiệm và nhận xét.
— — —
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
Các bạn học sinh hẳn đã rất quen thuộc với trò chơi caro truyền thống. Cách chơi trò này rất đơn giản, 2 người chơi đại diện cho 2 quân X và O. Mỗi lượt đi, người chơi lần lượt đánh quân của họ lên bàn cờ. Trò chơi chỉ xác định người thắng bại khi mà có 5 quân cờ của họ cùng nằm liên tiếp trên một hàng ngang hoặc một hàng dọc hoặc một đường chéo.
Chúng ta sẽ chọn một bảng kích cỡ khá lớn để bắt đầu. Ở đây các bạn học sinh hãy chọn bảng 33×64 là dễ nhìn và tiện thao tác nhất.
Bảng ở đây sẽ biểu diễn dưới dạng mảng 2 chiều. Mỗi khi chúng ta click chuột vào một ô để đánh dấu thì sẽ xem lại cả bảng để kiểm tra các điều kiện về đường dọc, đường ngang, đường chéo. Khi đó các bạn sẽ biết được mình có chiến thắng không. Không chỉ vậy, các bạn sẽ dùng vòng lặp để đếm các ô trong mảng 2 chiều, chỉ khi nào mà 5 ô cùng màu được tô liên tiếp theo hàng dọc hoặc hàng ngang hoặc hàng chéo chúng ta sẽ in ra kết quả người chơi chiến thắng.
Nếu có người thắng cuối, trò chơi sẽ in ra kết quả người thắng cuộc và kết thúc trò chơi, còn không, trò chơi vẫn tiếp tục. Nếu trong trường hợp 2 người chơi đã tô hết cả bảng mà vẫn không xác định trò chơi, máy sẽ thông báo kết quả hòa và kết thúc trò chơi.
b. Các bước triển khai dự án
Bước 1: Khai báo thư viện sử dụng để code trò chơi.
Ở đây ngoài các hàm tiêu chuẩn có sẵn của ngôn ngữ lập trình python ra, ta sẽ sử dụng thêm 2 thư viện đó là pygame và sys. Thư viện pygame là một thư viện python giúp chúng ta có thể code các trò chơi dễ dàng hơn. Còn thư viện sys liên quan đến điều khiển các chương trình trên máy tính. Để khai báo chương trình, ta dùng 2 câu lệnh sau.
import pygame
import sys
Bước 2: Khai báo một số yếu tố cơ bản trong trò chơi
Đầu tiên, chúng ta sẽ định nghĩa một số màu hiển thị trong trò chơi theo bảng mã RGB.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0,0,255)
Trong bảng mã RGB, mỗi một màu sẽ được biểu diễn bằng 3 phần tử tương ứng cường độ của 3 màu cơ bản: đỏ (Red), xanh lá (Green), xanh dương (Blue). Hoà trộn 3 màu này lại, chúng ta sẽ được một màu mới.
Ta sẽ giả định con x là con đi trước và khởi tạo FPS – Frames Per Second (độ mượt của game) là 120
XO = 'x'
FPS = 120
Tiếp đó, chúng ta sẽ khởi tạo các kích cỡ bảng và ô caro. Biến WIDTH và HEIGHT chỉ chiều dài và chiều rộng mỗi ô caro là 28×28. Biến MARGIN chỉ độ dày cạnh mỗi ô caro là 2. Biến rownum và colnum lần lượt là số hàng và số cột của bảng caro. Chúng ta có 33 hàng và 64 cột.
# This sets the WIDTH and HEIGHT of each board location
WIDTH = 28
HEIGHT = 28# This sets the distance between each cell
MARGIN = 2
rownum = 33
colnum = 64
Các bạn học sinh hãy biểu bảng caro dưới dạng mảng 2 chiều với rownum hàng và colnum cột. Đầu tiên khởi tạo grid là một mảng đơn. Sau đó, chúng ta dùng vòng lặp với số lần lặp tương ứng với số hàng (rownum) để khởi tạo mỗi phần tử của grid là một mảng, ứng với một hàng trong bảng caro. Chúng ta tiếp tục sử dụng vòng lặp thứ hai với số lần lặp tương ứng với số cột (colnum). Chúng ta sử dụng 2 vòng lặp để tạo một mảng hai chiều, giống như bảng caro hoặc mê cung trong bài 6 của khoá CS 101. Giá trị ở mỗi vị trí trong bảng là 0. Vậy là các bạn học sinh đã khởi tạo được bảng caro với kích cỡ rownum * colnum rồi đấy!
# Create a 2 dimensional array. A two dimensional
# array is simply a list of lists.
grid = []
for row in range(rownum):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(colnum):
grid[row].append(0) # Append a cell
Giờ thì các bạn phải khởi tạo trò chơi. Muốn chạy một trò chơi thì trước tiên các bạn hãy dùng hàm pygame.init(). Ngoài ra để game hiển thị chúng ta phải khởi tạo về cửa sổ game: Biến WINDOW_SIZE chứa 2 kích cỡ chiều dài và chiều rộng của màn hình game ở đây sẽ để kích cỡ là 1920 * 990. Khi đó, biến screen chính là màn hình game trong python. Chúng ta sẽ khởi tạo nó bằng cách khai báo screen = pygame.display.set_mode(WINDOW_SIZE). Vậy chúng ta đã khởi tạo xong cửa sổ game với kích cỡ chúng ta yêu cầu.
# Set the HEIGHT and WIDTH of the screen
WINDOW_SIZE = [1920,990]
screen = pygame.display.set_mode(WINDOW_SIZE)
Về yếu tố hình ảnh, chúng ta có hình ảnh quân X và quân O trên bàn cờ. Ở đây, chúng ta chuẩn bị hình ảnh quân X là file ảnh X_modified-100×100.png và quân O là o_modified-100×100.png. (Các bạn học sinh có thể lấy hình ở link). Sau đó, ta sẽ đưa hai hình ảnh đó vào trò chơi bằng các câu lệnh sau:
Ở đây, ta có thể thấy hàm pygame.transform.smoothscale chính là hàm giúp chúng ta chuyển đổi các hình ảnh thành các phần tử ta muốn trong game. Còn hàm pygame.image.load() sẽ đưa hình ảnh vào. Hàm convert() sẽ giúp ta chuyển hình ảnh thành các ô pixel. Và cuối cùng (28,28) chính là kích cỡ một ô vuông trong bảng caro ta đã nói ở trên.
Bước 3: Viết hàm kiểm tra điều kiện thắng của trò chơi
Làm thế nào để các bạn học sinh có thể biết trò chơi kết thúc và kết quả người chiến thắng?
Như các bạn đã biết, trò chơi chỉ có người chiến thắng khi tồn tại 5 quân cùng loại cùng nằm trên một hàng ngang hoặc một hàng dọc hoặc một đường chéo. Vậy trên một bảng, điều kiện đó sẽ được biểu diễn như thế nào?
Chúng ta gọi ô (i, j) là ô có địa chỉ tại hàng thứ i và cột thứ j. Khi đó, ta giả sử ô (i, j) là ô bắt đầu hàng ngang thì các ô tiếp theo của hàng ngang đó sẽ là (i, j + 1), (i, j + 2), (i, j + 3), (i, j + 4). Nếu ô đó là ô bắt đầu một hàng dọc thì các ô tiếp theo sẽ là (i + 1,j), (i + 2, j), (i + 3, j), (i + 4, j). Chúng ta có 2 loại đường chéo. Với loại đường chéo thứ nhất thì các ô tiếp theo sẽ là (i + 1, j – 1), (i + 2, j – 2), (i + 3, j – 3), (i + 4, j – 4). Còn lại với loại đường chéo thứ 2 thì là (i + 1, j + 1), (i + 2, j + 2), (i + 3, j + 3), (i + 4, j + 4). Chúng ta đã được học cách để lấy địa chỉ cho một ô trong mảng hai chiều ở bài 6 trong khoá CS 101.
Như vậy để kiểm tra điều kiện thắng thì ta có thể kiểm tra các ô cùng hàng, cùng cột, cùng đường chéo một cách dễ dàng hơn. Ta có hàm kiểm tra như sau:
def checkwin(board):
indices = [i for i,x in enumerate(board) if 'x' in x]
for index in indices:
xrowindices = [i for i, x in enumerate(board[index]) if x == "x"]
for xs in xrowindices:
if xs<=len(board[0])-5:
if board[index][xs] == board[index][xs+1] == board[index][xs+2] == board[index][xs+3] == board[index][xs+4]:
return 1
if index<=len(board)-5:
if board[index][xs] == board[index+1][xs] == board[index+2][xs] == board[index+3][xs] == board[index+4][xs]:
return 1
if xs<=len(board[0])-5:
if board[index][xs] == board[index+1][xs+1] == board[index+2][xs+2] == board[index+3][xs+3] == board[index+4][xs+4]:
return 1
if board[index][xs] == board[index+1][xs-1] == board[index+2][xs-2] == board[index+3][xs-3] == board[index+4][xs-4]:
return 1
indices1 = [i for i,x in enumerate(board) if 'o' in x]
for index1 in indices1:
orowindices = [i for i, x in enumerate(board[index1]) if x == "o"]
for os in orowindices:
if os<=len(board[0])-5:
if board[index1][os] == board[index1][os+1] == board[index1][os+2] == board[index1][os+3] == board[index1][os+4]:
return 2
if index1<=len(board)-5:
if board[index1][os] == board[index1+1][os] == board[index1+2][os] == board[index1+3][os] == board[index1+4][os]:
return 2
if os<=len(board[0])-5:
if board[index1][os] == board[index1+1][os+1] == board[index1+2][os+2] == board[index1+3][os+3] == board[index1+4][os+4]:
return 2
if board[index1][os] == board[index1+1][os-1] == board[index1+2][os-2] == board[index1+3][os-3] == board[index1+4][os-4]:
return 2
count = 0
for rows in board:
for cells in rows:
if cells == 'x' or cells == 'o':
count+=1
if count == rownum*colnum:
return 3
return 0
Về cách đoạn code hoạt động, ta sẽ tách rõ ra làm 3 điều kiện kiểm tra. Phần thứ nhất là kiểm tra điều kiện thắng của con X, phần thứ 2 kiểm tra điều kiện thắng của con O và phần còn lại sẽ giúp chúng ta kiểm tra hai người chơi hòa hay không. Chúng ta sẽ đặt nếu người chơi X thắng thì trả kết quả chương trình về 1. Nếu người chơi O thắng sẽ trả kết quả về 2. Nếu giải đấu caro hòa thì về giá trị 3. Còn nếu trò chơi tiếp tục chúng ta trả về giá trị 0.
Các bạn có thể thấy ở đoạn code trên có một cách tạo mảng theo điểu kiện rất hay như sau:
indices = [i for i,x in enumerate(board) if 'x' in x]
Cách tạo mảng trên được gọi là list comprehension và cấu trúc của nó như sau:
newlist = [expression for value in array if true]
Cách tạo mảng này sẽ giúp chúng ta tạo một mảng mới từ mảng cũ bằng cách dựa vào các giá trị mảng cũ theo điều kiện nào đó. Các bạn có thể để ý hàm enumerate() sẽ giúp chúng ta tạo ra một danh sách gồm các cặp chỉ số – phần tử trong mảng như kiểu 0 – board [0] rất thuận tiện. Trong đoạn code này, ta sẽ thấy mảng indices chứa các chỉ số hàng của mảng board tồn các con X, tương tự với mảng indices1 sẽ chứa các chỉ số hàng của mảng board tồn tại các con O.
Các bạn học sinh hãy để ý hai đoạn code kiểm tra điều kiện thắng của X và O. Ở vòng lặp thứ hai, chúng ta lại bắt gặp cách tạo mảng tương tự như vậy. Mảng thứ hai sẽ giúp chúng ta lấy chỉ số cột của các ô trong hàng index.
Ngoài việc kiểm tra các hàng, các cột, các đường chéo, trước hết chúng ta cần đảm bảo các ô chúng ta kiểm tra không bị vượt ra ngoài mảng 2 chiều. Nếu không, chương trình sẽ bị lỗi. Như khi kiểm tra một hàng, chúng ta phải kiểm tra đúng xs <= len(board[0]) – 5 để xem các ô chúng ta kiểm tra sau đó có bị tràn ra khỏi bảng caro không. Các bạn nhớ chú ý khi kiểm tra một đường chéo thỏa mãn thì phải xem chỉ số hàng, cột và ô bắt đầu để có thể kiểm tra được cả 5 ô.
Về phần kiểm tra người chơi hòa, các bạn hãy xem các ô tô X hoặc O hết chưa. Nếu có thì trò chơi hòa. Còn nếu không trò chơi tiếp tục
Bước 4: hoàn thiện các phần còn lại để trò chơi chạy
Đầu tiên, chúng ta sẽ khởi tạo hai biến là done và status để thể hiện trò chơi “đã kết thúc” và “đã có người chiến thắng”. Ban đầu, chúng ta để hai biến này là False và None tại vì trò chơi chưa kết thúc và chưa xác định kết quả trò chơi.
# Loop until the user clicks the close button.
done = False
status = None
Sau đó, các bạn sẽ dùng một vòng lặp while để chạy trò chơi. Nếu mà biến done chưa đúng thì nghĩa là trò chơi vẫn tiếp tục và vòng lặp vẫn chạy. Trong pygame, các hoạt động của người chơi sẽ là các event. Chúng ta sẽ dùng một vòng lặp để lấy các event mà chúng ta tác động lên trò chơi.
Trong đó, nếu mà chúng ta kết thúc trò chơi tức là loại event chúng ta thực hiện sẽ là pygame. QUIT thì pygame sẽ kết thúc và chúng ta sẽ để biến done là True để kết thúc vòng lặp. Còn nếu chúng ta click chuột vào một ô trên màn hình thì thao tác này là pygame .MOUSEBUTTONDOWN tức là người chơi chọn đánh dấu một quân lên bảng và chúng ta sẽ dùng hàm pygame.mouse.get_pos() để lấy vị trí ô chúng ta click vào. Nếu ô đó đã được đánh dấu là X hoặc O thì chúng ta bỏ qua. Còn không, chúng ta sẽ đánh dấu nó là biến xo và đổi biến xo ngược lại để đến lượt người chơi thứ hai. Sau đó, chúng ta sẽ gắn biến status với giá trị của hàm checkwin(grid).
while not done:
for event in pygame.event.get(): # User did something if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop # Set the screen backgroundif event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
col = pos[0] // (WIDTH + MARGIN)
row= pos[1] // (HEIGHT + MARGIN)
if grid[row][col] == 0:
if XO == 'x':
grid[row][col] = XO
XO = 'o'
else:
grid[row][col] = XO
XO = 'x'
status = checkwin(grid)
Ở đoạn code trên, các bạn có thể thấy chỉ số hàng và cột mà chúng ta lấy đã bị đảo lại. Nguyên nhân là vì hàm python.mouse.get_pos() sẽ trả về cột trước hàng sau..
Trong vòng lặp while trên, sau khi đánh dấu ô và kiểm tra điều kiện chiến thắng, giờ chúng ta sẽ vẽ hình bảng caro. Đầu tiên, chúng ta sẽ để cả cái bảng màu đen. Sau đó, vẽ các ô caro là các hình vuông màu trắng có kích cỡ WIDTH * HEIGHT có khoảng cách là MARGIN. Như vậy, chúng ta đã xong bảng ô vuông caro. Giờ các bạn hãy dùng vòng lặp để xem ô đó có điền X hay O thì chúng ta chèn hình ảnh X hoặc O vào ô nhé! Ta có đoạn code sau:
for row in range(rownum):
for column in range(colnum):
color = WHITE
pygame.draw.rect(screen,
color,
[(MARGIN + WIDTH) * column + MARGIN,
(MARGIN + HEIGHT) * row + MARGIN,
WIDTH,
HEIGHT])
if grid[row][column] == 'x':
screen.blit(x_img,((WIDTH + MARGIN)*column+2,(HEIGHT + MARGIN)*row+2))
if grid[row][column] == 'o':
screen.blit(o_img,((WIDTH + MARGIN)*column+2,(HEIGHT + MARGIN)*row+2))
Ở đây, chúng ta thấy tọa độ một ô vuông màu trắng ứng với ô row, column sẽ là (MARGIN + WIDTH) * column + MARGIN, (MARGIN + HEIGHT) * row. Các bạn hãy vẽ hình vuông kích cỡ WIDTH * HEIGHT. Để ý kỹ, các bạn sẽ thấy chúng ta vẽ theo thứ tự cột trước hàng sau tại vì pygame sẽ vẽ hình chữ nhật theo kích cỡ là chiều ngang trước chiều dọc sau. Hàm screen.blit giúp chúng ta có thể chèn hình ảnh ta muốn vào ô vuông với tọa độ như trên.
Giờ chúng ta đã vẽ xong bảng và nếu có người chơi thắng hoặc hòa, chúng ta phải in kết quả ra và kết thúc trò chơi.
if status == 3:
font = pygame.font.Font('freesansbold.ttf', 100)
text = font.render('Draw', True, GREEN, BLUE)
textRect = text.get_rect()
textRect.center = (WINDOW_SIZE[0]/2,WINDOW_SIZE[1]/2)
screen.blit(text,textRect)
done = True
if status == 1:
font = pygame.font.Font('freesansbold.ttf', 100)
text = font.render('X wins', True, GREEN, BLUE)
textRect = text.get_rect()
textRect.center = (WINDOW_SIZE[0]/2,WINDOW_SIZE[1]/2)
screen.blit(text,textRect)
done = True
if status == 2:
font = pygame.font.Font('freesansbold.ttf', 100)
text = font.render('O wins', True, GREEN, BLUE)
textRect = text.get_rect()
textRect.center = (WINDOW_SIZE[0]/2,WINDOW_SIZE[1]/2)
screen.blit(text,textRect)
done = True
Ở đây, các bạn sẽ thấy hàm pygame.font.Font có thể chọn lần lượt font chữ và kích cỡ chữ hiển thị. Ở đây ta sẽ chọn là font freesansbold và file của font đó là freesansbold.ttf, kích cỡ 100. Nếu status là 3 thì chúng ta có kết quả hòa. Còn nếu status là 2 chúng ta cho người chơi O thắng. Còn là 1 thì người chơi X thắng.
Hàm font.render sẽ giúp chúng ta biểu thị dòng chữ mà mình cần. Còn biến True trong hàm font.render giúp chữ hiển thị nét hơn trên máy tính. GREEN chính là màu của chữ cái ta chọn. BLUE chính là màu phông nền đằng sau. Chúng ta đã tạo các màu này bằng giá trị RGB ở phần đầu chương trình. Hàm get_rect sẽ giúp lấy hình chữ nhật chứa các từ mà các bạn muốn. Sau đó, các bạn hãy nhớ chỉnh tọa độ của hình chữ nhật ở trung tâm là (WINDOW_SIZE[0]/2,WINDOW_SIZE[1]/2).
Ngoài ra, hàm screen.blit sẽ giúp trò chơi hiển thị chữ cái ta cần ở vị trí hình chữ nhật đó. Và nếu trò chơi kết thúc chúng ta phải đặt biến done là True.
Sau đó, các bạn sẽ làm trò chơi cập nhật và hiện lên bằng câu lệnh sau:
clock.tick(FPS)
# Go ahead and update the screen with what we've drawn.
pygame.display.update()
Hàm clock.tick(FPS) sẽ giúp trò chơi chúng ta mượt hơn và hàm python.display.update() sẽ giúp ta hiện những gì vừa thực hiện lên. FPS là số khung hình trong một giây chúng ta đã tạo ở đầu chương trình.
Kết thúc trò chơi, chúng ta sẽ dừng trò chơi trong 10s để nó giữ kết quả người chơi chiến thắng và thoát khỏi trò chơi.
Hàm pygame.time.delay(10000) sẽ giữ trò chơi tầm 10 giây để chúng ta có thể nhìn thấy kết quả trò chơi và sau đó thoát game ra bằng hàm pygame.quit().
4. Tadaa !
Sau trò chơi thú vị này, các bạn học sinh lại được cập nhật thêm những kiến thức thú vị về lập trình python như toán, hàm, câu điều kiện, các vòng lặp…
Đây là một chương trình cần kiến thức khá là khó và dài, nhưng cũng không kém phần thú vị. Các bạn học sinh hãy thử sáng tạo, cải tiến code bằng cách thay hình ảnh của X và O bằng bất cứ hình ảnh nào các bạn thích. Hoặc chúng ta có thể tạo một bảng caro to hơn để chơi đã hơn.
Sau khi hoàn thành dự án cá nhân, các bạn đừng quên chia sẻ chương trình của mình lên STEAMese Profile để thầy cô và các bạn cùng trải nghiệm nhé!
— — —
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
Chúng ta sẽ áp dụng kiến thức đã được học ở bài 6 của khoá CS 101 để hoàn thành trò chơi này:
Stack và Queue trong Python.
Câu lệnh điều kiện trong Python.
Vòng lặp while và for trong Python.
Câu lệnh input() để nhập dữ liệu trong Python.
Câu lệnh print() để in thông báo ra màn hình.
Nội dung trò chơi
Một vật dụng không thể thiếu với các bạn học sinh khi học Toán đó là máy tính cầm tay. Máy tính cầm tay giúp chúng ta tính toán những phép toán cộng, trừ, nhân, chia, và kết hợp với dấu ngoặc đơn. Hẳn bạn học sinh nào cũng biết đến ba câu thần chú quen thuộc khi tính một biểu thức nào đó theo thứ tự tính toán: “Nhân chia trước, cộng trừ sau. Trong ngoặc trước, ngoài ngoặc sau. Tính từ trái sang phải”. Chúng ta có thể sử dụng Python để mô phỏng lại máy tính cầm tay và giúp tính toán nhanh hơn các biểu thức đơn giản với số tự nhiên. Chúng ta có thể chơi thử trò chơi ở đây nhé: https://s4v.trinket.io/sites/calculator
Bắt tay vào lập trình thôi nào!!!
a. Thuật toán
Mỗi biểu thức người chơi nhập vào sẽ có dạng chuỗi (string). Chuỗi có thể xem là một mảng. Chúng ta sẽ lấy lần lượt từng phần tử của mảng. Trong trò chơi, chúng ta sẽ có số tự nhiên và phép toán (cộng, trừ, nhân, chia, ngoặc đơn). Chúng ta sẽ tạo hai mảng. Một mảng để lưu các kết quả tính toán và một mảng để lưu các phép toán.
Vì chúng ta chỉ có thể lấy ra được từng chữ số nên cần tạo một biến để lưu kết quả số có nhiều chữ số. Ví dụ số có một chữ số: 5. Chúng ta thấy 5 = 0 * 10 + 5. Với số có hai chữ số: 35 = (0 * 10 + 3) * 10 + 5. Với số có ba chữ số: 475 = ((0 * 10 + 4) * 10 + 7) * 10 + 5. Như vậy với số, chúng ta có thể lấy các chữ số từ trái sang phải và sử dụng quy luật ở trên. Với mỗi số như vậy, chúng ta sẽ thêm vào mảng chứa kết quả.
Chúng ta có 4 phép toán: cộng, trừ, nhân, chia, dấu ngoặc đơn. Chúng ta sẽ chia các phép toán thành 3 nhóm: Nhóm 1: cộng và trừ, Nhóm 2: nhân và chia, Nhóm 3: dấu ngoặc đơn. Mỗi nhóm sẽ có một thứ tự ưu tiên, từ lớn đến bé là: Nhóm 2, Nhóm 1, Nhóm 3.
Khi đi qua các phần tử của chuỗi được nhập vào ban đầu, nếu chúng ta gặp phải phép toán cộng, trừ, nhân, chia, dấu mở ngoặc, chúng ta sẽ kiểm tra thứ tự ưu tiên của nó với phép toán xuất hiện ở trước nó tính từ trái sang phải trong biểu thức. Vì chúng ta phải thực hiện phép toán từ trái sang phải và ưu tiên cho phép toán nhân và chia nên nếu phép toán phía trước có độ ưu tiên lớn hơn hoặc bằng phép toán hiện tại thì chúng ta sẽ thực hiện phép toán phía trước trước. Sau đó, chúng ta sẽ xoá phép toán đó ra khỏi mảng lưu phép toán và thêm vào mảng phép toán hiện tại.
Khi đi qua các phần tử của chuỗi được nhập vào ban đầu, nếu chúng ta gặp phải phép toán mở ngoặc thì chúng ta sẽ thêm nó vào trong mảng phép toán và đợi đến khi gặp phép toán đóng ngoặc. Khi gặp phép toán đóng ngoặc, chúng ta sẽ thực hiện phép toán trong ngoặc và xoá hết các phép toán trong ngoặc và phép toán mở, đóng ngoặc sau khi thực hiện xong.
Chúng ta có thấy mảng lưu kết quả phép tính và mảng lưu phép toán giống những ngăn xếp (stacks) không nào? Chúng ta đã học ở bài 6 hai câu lệnh với ngăn xếp là push và pop, cùng với câu thần chú LIFO (Last In First Out). Vì chúng ta thực hiện phép toán từ trái sang phải và chúng ta cũng lấy các phép toán theo thứ tự từ trái sang phải nên nó sẽ tuân theo LIFO.
b. Code:
Bước 1: Viết chương trình chính của trò chơi
Tương tự với blog “Câu chuyện ngẫu nhiên”, chúng ta sẽ sử dụng biến cont và vòng lặp while để tiếp tục hoặc dừng lại trò chơi theo yêu cầu của người chơi. Ngoài ra, chúng ta sẽ sử dụng câu lệnh input() để hỏi người dùng nhập vào biểu thức cần tính. Câu lệnh input() cùng với câu lệnh điều kiện còn giúp hỏi người chơi có muốn tiếp tục trò chơi không. Câu lệnh print() sẽ in ra màn hình kết quả tính toán của hàm evaluate sẽ được viết ở bước 4.
cont = True
while cont:
formula = input('Nhập biểu thức cần tính với số tự nhiên (gồm các phép tính cộng, trừ, nhân, chia và dấu ngoặc đơn)')
print('Kết quả của biểu thức là: %s' % str(evaluate(formula)))
tiep = input('Bạn có muốn tiếp tục không (Y/N)?')
if tiep.upper() == 'Y':
cont = True
else:
cont = False
Bước 2: Viết hàm kiểm tra phép toán và thứ tự ưu tiên của phép toán:
Chúng ta sẽ viết hàm is_op để kiểm tra xem input có phải là một trong những phép toán cộng, trừ, nhân, chia hay không. Chúng ta sẽ sử dụng câu lệnh in. Câu lệnh trả về True hoặc False.
def is_op(c):
return c in ['+', '-', '*', '/']
Tiếp theo, chúng ta sẽ viết hàm priority để trả về thứ tự ưu tiên của phép toán. Phép toán nhân chia sẽ được thực hiện trước, nên có thứ tự ưu tiên là 2. Phép toán cộng trừ có thứ tự ưu tiên 1. Phép toán mở ngoặc có thứ tự ưu tiên là -1. Những phép toán nào có thứ tự ưu tiên cao hơn sẽ được thực hiện trước.
def priority(op):
if op == '+' or op == '-':
return 1
if op == '*' or op == '/':
return 2
return -1
Bước 3: Viết hàm thực hiện phép toán:
Chúng ta sẽ viết hàm process_op nhận vào ngăn xếp lưu kết quả phép toán và phép toán. Hàm thêm kết quả phép toán mới vào ngăn xếp và trả về ngăn xếp. Với mỗi phép toán mới, chúng ta sẽ lấy ra kết quả trước và sau phép toán đó từ ngăn xếp bằng câu lệnh .pop(). Sau đó hàm sẽ thực hiện phép toán và thêm kết quả vào ngăn xếp.
Trường hợp đặc biệt: Số chia bằng 0 trong phép chia thì chúng ta sẽ thêm vào ngăn xếp kết quả vô cùng (∞). Trong Python sẽ là float(“inf”). Chúng ta sẽ sử dụng ký tự đặc biệt này để dừng vòng lặp ở hàm chính được viết ở bước 4.
def process_op(st, op):
r = st.pop()
l = st.pop()
if op == '+':
st.append(l + r)
elif op == '-':
st.append(l - r)
elif op == '*':
st.append(l * r)
elif op == '/':
if r == 0:
print('Biểu thức có phép chia cho 0: ' + str(l) + '/' + str(r))
st.append(float("inf"))
else:
st.append(l / r)
return st
Bước 4: Viết hàm evaluate:
Hàmevaluatenhận vào chuỗi s và in ra kết quả tính toán cuối cùng. Chúng ta sẽ tạo 2 ngăn xếp bằng mảng. Ngăn xếp st để lưu các kết quả tính toán và ngăn xếp op để lưu các phép toán. Chúng ta sẽ sử dụng vòng lặp for cùng với hàm range và len để đi qua các phần tử của chuỗi. range(len(s)) dùng để tạo một mảng gồm các số tự nhiên bắt đầu từ 0 với các phần tử nhỏ hơn chiều dài của mảng s. Các phần tử này tương ứng với index của các phần tử của chuỗi s.
Trường hợp thứ nhất khi phần tử trong chuỗi là khoảng trắng thì chúng ta sẽ không làm gì, và tiếp tục đi đến phần tử khác của chuỗi bằng câu lệnh continue. Trường hợp thứ hai khi phần tử trong chuỗi là dấu mở ngoặc, chúng ta sẽ thêm phép toán mở ngoặc vào ngăn xếp op. Trường hợp thứ ba khi phần tử trong chuỗi là một chữ số, chúng ta sẽ tìm tiếp từ phần tử đó đến hết chuỗi xem có chữ số nào nối tiếp không để tạo thành một số có nhiều chữ số. Để tìm xem phần tử có phải là số không, chúng ta có thể sử dụng câu lệnh isnumeric(). Để lấy ra các phần tử tiếp theo chúng ta có thể sử dụng vòng lặp for cùng với hàm range. range(i, len(s)) dùng để tạo một mảng gồm các số tự nhiên bắt đầu từ i với các phần tử nhỏ hơn chiều dài của mảng s. Để dừng lại khi không còn gặp các chữ số liên tiếp trong chuỗi, chúng ta dùng câu lệnh break.
Chúng ta sẽ tính ra giá trị của số có nhiều chữ số bằng công thức ở phần Thuật toán. Khi tính ra số, chúng ta sẽ thêm số đó vào ngăn xếp st (push) bằng câu lệnh .append(). Vì vòng lặp khi đi qua từng phần tử của chuỗi sẽ tăng index lên 1 đơn vị, nên để tránh bị lỗi khi có nhiều chữ số liền nhau, tạo thành một số có nhiều chữ số, chúng ta sẽ sử dụng một mảng có kích thước bằng với kích thước của chuỗi. Mảng này sẽ có kiểu dữ liệu boolean và được khởi tạo bằng False với tất cả các phần tử của mảng. Các phần tử của mảng này sẽ được gán là True nếu nó tương ứng với các chữ số đã đi qua trong chuỗi s. Như vậy chúng ta chỉ xét những vị trí có giá trị False.
st = []
op = []
mst = [False] * len(s)
for i in range(len(s)):
if s[i] == ' ':
continue
elif s[i] == '(':
op.append('(')
elif not mst[i]:
num = 0
for j in range(i, len(s)):
if s[j].isnumeric():
num = num * 10 + int(s[j])
mst[j] = True
else:
break
st.append(num)
Trường hợp thứ tư khi phần tử trong chuỗi là một trong các phép toán cộng, trừ, nhân, chia. Chúng ta có thể kiểm tra việc này bằng hàm is_op. Chúng ta sẽ so sánh thứ tự ưu tiên của phép toán đó với thứ tự ưu tiên của phép toán trước đó. Nếu phép toán trước đó có thứ tự ưu tiên lớn hơn hoặc bằng thứ tự ưu tiên của phép toán hiện tại thì chúng ta sẽ thực hiện phép toán trước đó bằng hàm process_op và bỏ phép toán trước đó ra khỏi mảng op bằng câu lệnh .pop() với ngăn xếp cho đến khi ngăn xếp op không còn phần tử nào. Hàm process_op nhận vào 2 inputs là mảng st để lưu kết quả của phép tính và phép toán trước đó. Chúng ta có thể dùng vòng lặp while để làm việc này. Cuối cùng chúng ta sẽ thêm phép toán hiện tại vào mảng op (push) bằng câu lệnh .append().
elif is_op(s[i]):
cur_op = s[i]
while len(op) != 0 and priority(op[-1]) >= priority(cur_op):
st = process_op(st, op[-1])
op.pop()
op.append(cur_op)
Trường hợp thứ năm khi phần tử trong chuỗi là dấu đóng ngoặc thì chúng ta sẽ thực hiện các phép toán trước đó bằng hàm process_op cho đến khi gặp dấu mở ngoặc trong ngăn xếp op. Sau khi thực hiện mỗi phép toán, chúng ta phải bỏ phép toán vừa thực hiện ra khỏi ngăn xếp op bằng câu lệnh .pop(). Và cuối cùng là phải bỏ dấu mở ngoặc tương ứng ra khỏi ngăn xếp op.
elif s[i] == ')':
while op[-1] != '(':
st = process_op(st, op[-1])
op.pop()
op.pop()
Chúng ta sẽ dừng vòng lặp đi qua các phần tử của s nếu trong ngăn xếp st có kết quả vô cùng (khi chia cho 0). Cuối cùng sau khi đi hết các phần tử của chuỗi s, chúng ta sẽ phải thực hiện các phép toán còn lại trong ngăn xếp op và bỏ phép toán vừa thực hiện ra khỏi ngăn xếp cho đến khi hết phần tử trong ngăn xếp.
while op:
st = process_op(st, op[-1])
op.pop()
Code hoàn chỉnh của hàm evaluate là
def evaluate(s):
st = []
op = []
mst = [False] * len(s)
for i in range(len(s)):
if s[i] == ' ':
continue
elif s[i] == '(':
op.append('(')
elif s[i] == ')':
while op[-1] != '(':
st = process_op(st, op[-1])
op.pop()
op.pop()
elif is_op(s[i]):
cur_op = s[i]
while len(op) != 0 and priority(op[-1]) >= priority(cur_op):
st = process_op(st, op[-1])
op.pop()
op.append(cur_op)
elif not mst[i]:
num = 0
for j in range(i, len(s)):
if s[j].isnumeric():
num = num * 10 + int(s[j])
mst[j] = True
else:
break
st.append(num)
if float("inf") in st:
break
while op:
st = process_op(st, op[-1])
if float("inf") in st:
break
op.pop()
return st[0]
4. Tada!!!
Như vậy chúng ta đã hoàn thành trò chơi rồi đấy. Thật đơn giản đúng không nào. Chúng ta cần thêm một điều kiện nếu kết quả từ hàmevaluatekhác vô cùng thì sẽ in kết quả ra màn hình.
Code hoàn chỉnh sẽ là:
# -*- coding: utf-8 -*-
def is_op(c):
return c in ['+', '-', '*', '/']
def priority(op):
if op == '+' or op == '-':
return 1
if op == '*' or op == '/':
return 2
return -1
def process_op(st, op):
r = st.pop()
l = st.pop()
if op == '+':
st.append(l + r)
elif op == '-':
st.append(l - r)
elif op == '*':
st.append(l * r)
elif op == '/':
if r == 0:
print('Biểu thức có phép chia cho 0: ' + str(l) + '/' + str(r))
st.append(float("inf"))
else:
st.append(l / r)
return st
def evaluate(s):
st = []
op = []
mst = [False] * len(s)
for i in range(len(s)):
if s[i] == ' ':
continue
elif s[i] == '(':
op.append('(')
elif s[i] == ')':
while op[-1] != '(':
st = process_op(st, op[-1])
op.pop()
op.pop()
elif is_op(s[i]):
cur_op = s[i]
while len(op) != 0 and priority(op[-1]) >= priority(cur_op):
st = process_op(st, op[-1])
op.pop()
op.append(cur_op)
elif not mst[i]:
num = 0
for j in range(i, len(s)):
if s[j].isnumeric():
num = num * 10 + int(s[j])
mst[j] = True
else:
break
st.append(num)
if float("inf") in st:
break
while op:
st = process_op(st, op[-1])
if float("inf") in st:
break
op.pop()
return st[0]
cont = True
while cont:
formula = input('Nhập biểu thức cần tính với số tự nhiên (gồm các phép tính cộng, trừ, nhân, chia và dấu ngoặc đơn)')
result = evaluate(formula)
if result != float("inf"):
print('Kết quả của biểu thức là: %s' % str(evaluate(formula)))
tiep = input('Bạn có muốn tiếp tục không (Y/N)?')
if tiep.upper() == 'Y':
cont = True
else:
cont = False
Chương trình của chúng ta mới chỉ thực hiện các phép toán đơn giản với số tự nhiên. Các bạn học sinh hãy thử sáng tạo, cải tiến code để có thể thực hiện các phép toán với cả số thập phân và luỹ thừa, căn bậc hai nhé! Sau khi hoàn thành dự án cá nhân, các bạn đừng quên chia sẻ chương trình của mình lên STEAMese Profile để thầy cô và các bạn cùng trải nghiệm.
— — —
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
Các bạn học sinh có còn nhớ dự án ““Nhà thám hiểm và cánh cửa bí mật” hay không? Ở dự án đó, nhà thám hiểm đã phải trải qua hành trình thật khó khăn khi phải lựa chọn 4 căn phòng bí ẩn, thế nhưng bạn ấy đã thành công lấy được kho báu và rời khỏi lâu đài. Trở lại với tòa lâu đài cổ kính đầy rẫy nguy hiểm, các con quái vật sau khi để mất kho báu đã họp bàn với nhau để tìm cách bảo vệ tòa lâu đài tốt hơn. Vậy là, nhân sư đã nâng cấp trò chơi của mình, không còn chỉ là game đoán số thông thường, mà là một thử thách sắp xếp đòi hỏi khả năng tính toán chính xác.
Lần này, nhà thám hiểm lại quyết định quay trở lại tòa lâu đài bí ẩn. Làm thế nào để các bạn học sinh có thể giúp cho nhà thám hiểm an toàn rời khỏi nơi nguy hiểm đó? Để vượt qua thử thách của nhân sư, nhiệm vụ của chúng ta là sắp xếp các dãy số lộn xộn theo thứ tự từ lớn đến bé hoặc từ bé đến lớn. Chúng ta sẽ được chọn mình sắp xếp bao nhiêu số. Đặc biệt, các số trong dãy số sẽ ở dưới dạng các biểu thức cộng trừ, đòi hỏi sự tính toán thật nhanh và chính xác. Hãy thử sức chơi game với nhân sư ngay nào:
Một số kiến thức chúng ta đã được học ở khoá CS 101 sẽ được áp dụng để hoàn thành game nhập vai đơn giản này:
Thư viện randomđể tạo số ngẫu nhiên.
Vòng lặp for và while trong Python.
Hàm (function) trong Python
Chuỗi ký tự gồm nhiều dòng (Multi-line String)
Mảng trong Python
Bắt đầu code thôi nào !!!!!
Luật chơi:
Trò chơi bắt đầu khi nhân sư tạo một dãy số ngẫu nhiên dưới dạng các biểu thức cộng, trừ. Nếu sắp xếp theo thứ tự từ bé đến lớn, nhân sư sẽ hỏi người chơi lần lượt từ số bé nhất, số bé thứ hai, số bé thứ ba,… đến số lớn nhất.
Ví dụ: Một dãy số gồm các biểu thức: 3+1, 3-2, 1+1, 2+3. Sau khi tính toán, dãy số đó sẽ là 4, 1, 2, 5. Nhân sư yêu cầu người chơi sắp xếp từ bé đến lớn. Nhân sư sẽ hỏi: Số thứ nhất là số nào? Câu trả lời đúng là số 1. Nếu người chơi trả lời sai, trò chơi sẽ kết thúc. Nếu người chơi trả lời đúng, nhân sư sẽ tiếp tục hỏi: Số thứ hai là số nào? Câu trả lời đúng là 2. Nếu người chơi trả lời sai, trò chơi sẽ kết thúc. Nếu người chơi trả lời đúng, nhân sư sẽ tiếp tục hỏi số thứ ba. Trò chơi tiếp tục như thế đến số cuối cùng. Nếu người chơi trả lời đúng hết thì người chơi sẽ chiến thắng.
Luật chơi tương tự với trường hợp sắp xếp từ lớn đến bé.
Thuật toán:
Chúng ta sẽ tạo một thuật toán đơn giản để có thể mô phỏng trò chơi này. Chúng ta sẽ sử dụng hai mảng. Một mảng lưu các biểu thức dưới dạng chuỗi. Mảng còn lại lưu kết quả các biểu thức đó. Ví dụ: Mảng lưu dãy các biểu thức: [‘3+1’, ‘3-2’, ‘1+1’, ‘2+3’]. Sau khi tính toán, mảng còn lại sẽ lưu kết quả dãy số đó sẽ là [4, 1, 2, 5]. Ở đây, mục đích của mảng gồm các chuỗi là dùng để in ra màn hình cho người chơi. Mảng kết quả gồm các số sẽ dùng để sắp xếp.
Trong luật chơi, nhân sư sẽ hỏi lần lượt các số theo thứ tự từ bé đến lớn (hoặc từ lớn đến bé). Vì vậy, chúng ta có thể tìm số bé nhất (hoặc lớn nhất) trong mảng. Qua mỗi lần nhân sư hỏi, chúng ta sẽ bỏ số bé nhất (hoặc lớn nhất) ra khỏi mảng, và tiếp tục tìm số bé nhất (hoặc lớn nhất) của mảng mới đến khi mảng không còn phần tử nào.
Ví dụ: Dãy gồm các biểu thức: 3+1, 3-2, 1+1, 2+3. Sau khi tính toán, dãy kết quả sẽ là 4, 1, 2, 5. Nhân sư yêu cầu người chơi sắp xếp từ bé đến lớn.
Ở lượt thứ nhất, số bé nhất là 1. Sau lượt thứ nhất, chúng ta sẽ bỏ số 1 ra khỏi mảng. Mảng mới sẽ gồm 3 số là 4, 2, 5.
Ở lượt thứ hai, số bé nhất là 2. Sau lượt thứ hai, chúng ta sẽ bỏ số 2 ra khỏi mảng. Mảng mới sẽ gồm 2 số là 4, 5.
Ở lượt thứ ba, số bé nhất là 4. Sau lượt thứ ba, chúng ta sẽ bỏ số 4 ra khỏi mảng.
Mảng mới sẽ còn lại số 5. Số 5 là số cuối cùng. Như vậy, chúng ta đã gián tiếp sắp xếp dãy số ban đầu từ bé đến lớn.
3. Code:
Bước 1: Viết hàm giới thiệu game
Trước tiên, chúng ta sẽ tạo một hàm sử dụng câu lệnh print() để in ra màn hình luật chơi cũng như giới thiệu về game:
def intro():
print('''
---
NUMBER SORTING ++
---
RULE: Nhiệm vụ của trò chơi là sắp xếp 1 dãy số lộn xộn theo thứ tự từ bé đến lớn hoặc từ lớn đến bé.
Người chơi sẽ được chọn sắp xếp bao nhiêu số trong dãy số
Đặc biệt: Các số trong dãy sẽ được cho dưới dạng các biểu thức cộng trừ, đòi hỏi chúng ta cần kĩ năng tính toán cực cao nữa đó!
''')
Ở bài số 2, chúng ta đã biết về kiểu dữ liệu chuỗi (string). Từ trước đến nay, ta đều nhận thấy dữ liệu string phải ở trong cùng 1 dòng bắt đầu và kết thúc với dấu “”. Tuy nhiên, nếu ta sử dụng ”’ ”’ (3 dấu ‘), dữ liệu chuỗi có thể gồm nhiều dòng khác nhau (multi-line string).
Bước 2: Viết câu lệnh tương tác với người dùng ở đầu game
Tương tự như dự án “Nhà thám hiểm và cánh cửa bí mật”, chúng ta sẽ tạo một vòng lặp while để hỏi người chơi muốn tiếp tục trò chơi hay dừng lại. Đồng thời chúng ta sẽ in ra luật chơi bằng cách gọi hàm intro đã viết ở bước 1. Chúng ta lưu ý để gọi hàm intro, chúng ta chỉ cần dùng intro() vì hàm không return gì cả. Chúng ta cũng sẽ tạo một biến để hỏi người chơi muốn sắp xếp bao nhiêu số bằng câu lệnh input.
condition = Truewhile condition == True:
intro()
number_guest = int(input("Bạn muốn sắp xếp bao nhiêu số nhỉ? >> "))
again = input('Bạn muốn chơi tiếp không? [Y/N]')
if again == 'N':
condition = False
Bước 3: Viết hàm tạo dãy số ngẫu nhiên
Trò chơi sẽ gồm bốn loại biểu thức: a+b, a-b, a+b-c, a-b+c. a, b, c là các số nguyên ngẫu nhiên từ 1 đến 60. Chúng ta sẽ sử dụng câu lệnh random.randint(1,60) tương tự như dự án “Nhà thám hiểm và cánh cửa bí mật”. Mỗi biểu thức trong dãy số sẽ được chọn ngẫu nhiên từ bốn loại biểu thức bằng câu lệnh random.choice tương tự như dự án “Câu chuyện ngẫu nhiên”.
Chúng ta sẽ sử dụng hai mảng raw_list1 và raw_list2. Mảng raw_list1 lưu biểu thức dưới dạng chuỗi và mảng raw_list2 lưu kết quả của biểu thức. Ở bài số 3, chúng ta đã biết câu lệnh append dùng để lưu dữ liệu vào mảng. Ngoài ra để đổi số thành chuỗi chúng ta sẽ sử dụng hàm str. Để kết nối hai chuỗi, chúng ta sẽ sử dụng phép toán +. Ngoài ra chúng ta cũng không muốn các số trong dãy số lặp lại nên sẽ dùng câu lệnh notin để kiểm tra. “Not in” có nghĩa là không ở trong cái gì đó.
Chúng ta sẽ tạo hai mảng trống rawlist1 và rawlist2. Để dãy số có đủ số mà người chơi muốn sắp xếp, chúng ta sẽ sử dụng vòng lặp while và biến đếm i. Chúng ta sẽ đặt tên cho hàm tạo dãy số ngẫu nhiên là prep. Hàm nhận vào số biểu thức người chơi muốn sắp xếp và trả về hai mảng:
def prep(number_sort):
rawlist1 = []
rawlist2 = []
i = 0
while i < number_sort:
a = random.randint(1,60)
b = random.randint(1,60)
c = random.randint(1,60)
options = ["a+b", "a-b", "a+b-c", "a-b+c"]
option = random.choice(options)
if option == 'a+b' and a+b not in rawlist1:
rawlist1.append(str(a)+ ' + '+ str(b))
rawlist2.append(a+b)
elif option == 'a-b' and a-b not in rawlist2:
rawlist1.append(str(a)+ ' - '+ str(b))
rawlist2.append(a-b)
elif option == 'a+b-c' and a+b-c not in rawlist2:
rawlist1.append(str(a) + "+" + str(b) + "-" + str(c))
rawlist2.append(a+b-c)
elif option == 'a-b+c' and a-b+c not in rawlist2:
rawlist1.append(str(a) + "-" + str(b) + "+" + str(c))
rawlist2.append(a-b+c)
i = i + 1
return rawlist1, rawlist2
Bước 4: Viết hàm trả về số bé nhất (hoặc lớn nhất)
Chúng ta sẽ sử dụng hai hàm có sẵn ở trong Python. Hàm min dùng để tìm số bé nhất trong mảng và hàm max để tìm số lớn nhất trong mảng. Chúng ta sẽ đặt tên hàm cần viết là sorting. Hàm nhận vào mảng (dãy số) và kiểu sắp xếp. Kiểu sắp xếp nhận một trong hai giá trị: 0 (sắp xếp từ bé đến lớn) hoặc 1 (sắp xếp từ lớn đến bé). Hàm trả về số bé nhất (hoặc lớn nhất) tương ứng với cách sắp xếp.
Sau khi hỏi người chơi muốn sắp xếp bao nhiêu số, chúng ta sẽ chọn ngẫu nhiên cách sắp xếp bằng sử dụng câu lệnh random.randint(0,1). Nếu kết quả là 0 thì sắp xếp từ bé đến lớn. Nếu kết quả là 1 thì sắp xếp từ lớn đến bé.
Chúng ta sẽ gọi hàm prep để tạo dãy số ngẫu nhiên đã viết ở bước 2. Chúng ta sẽ in ra màn hình mảng gồm các biểu thức cần sắp xếp và cách thức sắp xếp.
import random
condition = Truewhile condition == True:
intro()
number_guest = int(input('Bạn muốn sắp xếp bao nhiêu số ? >>'))
sort_type = random.randint(0,1)
raw_list1, raw_list2 = prep(number_guest)
if sort_type == 0:
print('Sắp xếp dãy số theo thứ tự từ bé đến lớn: ' + str(raw_list1))
else:
print('Sắp xếp dãy số theo thứ tự từ lớn đến bé: ' + str(raw_list1))
again = input('Bạn có muốn chơi tiếp không? [Y/N]')
if again == 'N':
condition = False
Chúng ta sẽ tạo một vòng lặp while với biến đếm counter để đi qua số lượt nhân sư sẽ hỏi người chơi (bằng với số phần tử của mảng). Với mỗi lượt hỏi, chúng ta sẽ thực hiện ba công việc:
Tìm số bé nhất (hoặc lớn nhất) trong mảng.
Hỏi người chơi xem số tiếp theo trong dãy sau khi được sắp xếp là số nào. Kiểm tra đúng hay sai. Nếu đúng thực hiện bước tiếp theo. Nếu sai thoát khỏi vòng lặp.
Bỏ số tìm được ở công việc đầu tiên ra khỏi mảng.
Để tìm số lớn nhất (bé nhất), chúng ta sử dụng hàm đã viết ở bước 3. Chúng ta sử dụng câu lệnh điều kiện giống như thuật toán Cánh cửa bí mật ở bài số 2 để kiểm tra người chơi có nhập đúng số không. Để bỏ một số ra khỏi mảng, chúng ta sẽ sử dụng hàm remove:
turn = len(raw_list2)
counter = 0
while counter < turn:
number = sorting(raw_list2, sort_type)
guess = int(input('Sau khi sắp xếp, số ở vị trí số '+ str(counter + 1) + ' là: >>'))
if guess == int(number):
if counter == turn - 1:
print('Chúc mừng chiến thắng')
else:
print('Đúng rồi! Tiếp tục nào!')
else:
print('Bạn đã thua, câu trả lời là ' + str(number))
break
raw_list2.remove(number)
counter = counter + 1
4. Tada!!!
Như vậy chúng ta đã hoàn thành xong một game rất thú vị đúng không nào. Các bạn học sinh đã thành công áp dụng kiến thức về hàm đã học ở bài số 4 để viết một thuật toán sắp xếp một dãy số. Ngoài ra, chúng ta cũng biết thêm một số hàm mới có sẵn trong Python giúp chúng ta code thuận tiện hơn
Chương trình Python hoàn chỉnh của game sẽ là:
# -*- coding: utf-8 -*-
import random
def intro():
print('''
---
NUMBER SORTING ++
---
RULE: Nhiệm vụ của trò chơi là sắp xếp 1 dãy số lộn xộn theo thứ tự từ bé đến lớn hoặc từ lớn đến bé.
Người chơi sẽ được chọn sắp xếp bao nhiêu số trong dãy số
Đặc biệt: Các số trong dãy sẽ được cho dưới dạng các biểu thức cộng trừ, đòi hỏi chúng ta cần kĩ năng tính toán cực cao nữa đó!
''')
def prep(number_sort):
rawlist1 = []
rawlist2 = []
i = 0
while i < number_sort:
a = random.randint(1,60)
b = random.randint(1,60)
c = random.randint(1,60)
options = ["a+b", "a-b", "a+b-c", "a-b+c"]
option = random.choice(options)
if option == 'a+b' and a+b not in rawlist1:
rawlist1.append(str(a)+ ' + '+ str(b))
rawlist2.append(a+b)
elif option == 'a-b' and a-b not in rawlist2:
rawlist1.append(str(a)+ ' - '+ str(b))
rawlist2.append(a-b)
elif option == 'a+b-c' and a+b-c not in rawlist2:
rawlist1.append(str(a) + "+" + str(b) + "-" + str(c))
rawlist2.append(a+b-c)
elif option == 'a-b+c' and a-b+c not in rawlist2:
rawlist1.append(str(a) + "-" + str(b) + "+" + str(c))
rawlist2.append(a-b+c)
i = i + 1
return rawlist1, rawlist2
def sorting(arr, sort_type):
if sort_type == 0:
return min(arr)
else:
return max(arr)
condition = True
while condition == True:
intro()
number_guest = int(input('Bạn muốn sắp xếp bao nhiêu số ? >>'))
sort_type = random.randint(0,1)
raw_list1, raw_list2 = prep(number_guest)
if sort_type == 0:
print('Sắp xếp dãy số theo thứ tự từ bé đến lớn: ' + str(raw_list1))
else:
print('Sắp xếp dãy số theo thứ tự từ lớn đến bé: ' + str(raw_list1))
turn = len(raw_list2)
counter = 0
while counter < turn:
number = sorting(raw_list2, sort_type)
guess = int(input('Sau khi sắp xếp, số ở vị trí số '+ str(counter + 1) + ' là: >>'))
if guess == int(number):
if counter == turn - 1:
print('Chúc mừng chiến thắng')
else:
print('Đúng rồi! Tiếp tục nào!')
else:
print('Bạn đã thua, câu trả lời là ' + str(number))
break
raw_list2.remove(number)
counter = counter + 1
again = input('Bạn có muốn chơi tiếp không? [Y/N]')
if again == 'N':
condition = False
Các bạn học sinh hãy tự do sáng tạo theo những ý tưởng của riêng mình. Chúng ta có rất nhiều cách để cải tiến game khác lạ hơn. Thầy cô gợi ý các bạn có thể sắp xếp dãy số bằng hàm có sẵn trong Python là sorted. Sắp xếp dãy số trước khi hỏi người chơi sẽ giúp chương trình chúng ta chạy nhanh hơn. Ngoài ra, các bạn có thể thêm vào những loại biểu thức khác nhau, và thêm phép tính nhân, chia. Các bạn học sinh hãy thử tạo nên dự án của riêng mình và chia sẻ game của mình trên STEAMese Profile nhé!
— — —
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.
Mã hoá là phương pháp để biến thông tin (hình ảnh, văn bản) từ định dạng bình thường sang dạng thông tin mà chúng ta không thể hiểu được nếu không có phương tiện giải mã. Đồng thời, mã hoá có vai trò quan trọng trong giao dịch điện tử để đảm bảo độ bảo mật, toàn vẹn của thông tin khi truyền trên mạng. Thông thường, mã hóa được áp dụng nhiều trong các ví điện tử quen thuộc với chúng ta như Momo, Zalopay, Shopee Pay….Trái lại, giải mã là quá trình ngược của mã hoá, biến thông tin từ dạng được mã hoá về dạng thông tin ban đầu.
Mật mã Caesar là một dạng mật mã thay thế, trong đó mỗi ký tự ở văn bản ban đầu sẽ được thay thế bằng một ký tự khác, có vị trí cách nó một khoảng xác định trong bảng chữ cái. Cũng giống như các loại mật mã thay thế khác, mật mã Caesar rất dễ bị phá giải. Tuy nhiên đây là một bài toán hay để chúng ta áp dụng kiến thức đã học về “vòng lặp” và “mảng” ở bài 3 của khoá CS 101. Hãy thử tưởng tượng các bạn muốn kể một câu chuyện bí mật cho người bạn thân của mình. Để bảo mật câu chuyện riêng tư không bị lộ ra ngoài, chúng ta cần mã hóa câu chuyện và gửi cho bạn mình kèm với phương pháp giải mã. Cách làm này hết sức thú vị phải không nào!
Người đã sáng chế ra cách mã hóa Caesar thú vị là vị hoàng đế Julius Caesar. Kỹ thuật này đã được phát triển vào khoảng năm 100 Trước Công nguyên. Hoàng đế Caesar đã dùng nó để gửi những mệnh lệnh quan trọng cho những tướng sĩ trên chiến trường. Do đó, nếu bọn giặc có bắt được người truyền tin thì cũng không thể đọc và hiểu được nội dung của bức thư mã hóa đó. Kiến thức này thật sự rất hữu ích và được áp dụng cho tới ngày hôm nay.
Kiến thức lập trình:
Một số kiến thức chúng ta đã được học ở bài 3 của khoá CS 101 sẽ được áp dụng để hoàn thành chương trình mã hoá này:
Mảng và cách lấy phần tử của mảng trong Python.
Vòng lặp for và while trong Python.
Câu lệnh input() để nhập dữ liệu trong Python.
Câu lệnh print() để in thông báo ra màn hình.
Kiểu dữ liệu booleantrong Python với so sánh ==.
Bài toán:
Chúng ta sẽ sử dụng Thonny để xây dựng một chương trình vừa giúp mã hoá, vừa giúp giải mã Caesar. Chương trình sẽ cho người dùng nhập một câu muốn mã hoá và số ký tự muốn dịch chuyển trong bảng chữ cái (k). Số k dương sẽ dịch chuyển văn bản sang phải (theo thứ tự từ A sang Z). Số k âm sẽ dịch chuyển văn bản sang trái (theo thứ tự từ Z sang A).
Ví dụ 1:
Văn bản gốc (Văn bản chưa mã hóa): ABCDEF
Văn bản mã hóa: CDEFGH
Trong ví dụ trên, các kí tự trong văn bản gốc được mã hóa bằng cách dịch sang phải 2 kí tự. k=2.
Gốc
A
B
C
D
E
F
…
X
Y
Z
Mã hóa
C
D
E
F
G
H
…
Z
A
B
Vì được dịch sang phải 2 ký tự nên A được mã hóa thành C, B mã hóa thành D… Đặc biệt, Y được mã hóa thành A, Z được mã hóa thành B, quay lại các ký tự đầu tiên.
Ví dụ 2:
Văn bản gốc (Văn bản chưa mã hóa): ABCDEF
Văn bản mã hóa: YZABCD
Trong ví dụ trên, các kí tự trong văn bản gốc được mã hóa bằng cách dịch sang trái 2 kí tự. k=-2.
Gốc
A
B
C
D
E
F
…
X
Y
Z
Mã hóa
Y
Z
A
B
C
D
…
U
V
X
Vì được dịch sang trái 2 ký tự nên C được mã hóa thành A, D mã hóa thành B… Đặc biệt, A được mã hóa thành Y, B được mã hóa thành Z, quay lại các ký tự cuối cùng.
Chúng ta có thể thấy rằng k âm là phương pháp giải mã cho mã hoá với k dương và ngược lại.
Trước khi bắt tay vào viết code, chúng ta sẽ cùng suy nghĩ một thuật toán để giải quyết bài toán này nhé. Chúng ta có thể biểu diễn tất cả các ký tự trong bảng chữ cái bằng một mảng trong Python.
Mảng arr có 26 phần tử. Với một ký tự bất kỳ, chúng ta có thể tìm được vị trí (index) i của nó trong mảng. Do đó khi dịch chuyển ký tự đó sang phải k kí tự, vị trí mới sẽ là i + k. Nếu dịch chuyển ký tự đó sang trái k kí tự thì khi đó k < 0 nên vị trí mới vẫn sẽ là i + k.
Trong trường hợp chúng ta dịch chuyển qua hai đầu của bảng chữ cái thì sao nhỉ? Ví dụ: Ký tự ‘X’ ở vị trí 23 trong mảng. Khi dịch chuyển sang phải 3 ký tự, vị trí mới sẽ là 23 + 3 = 26. Tuy nhiên vị trí cuối cùng của mảng arr là 25. Do đó, chúng ta phải quay lại vị trí đầu tiên (0) của ký tự ‘A’. Trong trường hợp này, khi dịch chuyển, chúng ta đã đi hết 1 lượt mảng arr. Chúng ta có thể thấy công thức tính vị trí sau khi dịch chuyển là 23 + 3 – 26 * 1 = 0.
Lấy một ví dụ khác: Ký tự ‘X’ ở vị trí 23 trong mảng. Khi dịch chuyển sang trái 80 ký tự, vị trí mới sẽ là 23 – 80 = -57. Từ vị trí ký tự ‘X’, nếu dịch sang trái 23 ký tự, chúng ta sẽ đến vị trí của ký tự ‘A’. Như vậy, chúng ta đã đi hết 1 lượt mảng arr. Từ vị trí ký tự ‘A’, dịch tiếp sang trái 26 ký tự, chúng ta sẽ đi hết một lượt nữa mảng arr và quay lại vị trí ký tự ‘A’. Tiếp tục dịch sang trái 26 ký tự, chúng ta sẽ tiếp tục đi hết một lượt nữa mảng arr và quay lại vị trí ký tự ‘A’. Chúng ta còn phải dịch sang trái 5 ký tự nữa. Như vậy chúng ta sẽ đến vị trí ký tự ‘V’. Tóm lại, chúng ta đã đi hết 3 lượt mảng arr. Chúng ta có thể thấy công thức tính vị trí sau khi dịch chuyển là 23 – 80 + 26 * 3 = 21.
Để tính xem phải đi qua mảng arr bao nhiêu lần, chúng ta có thể sử dụng phép toán floor division trong Python. Floor division trong Python là //. Floor division sẽ trả về số nguyên lớn nhất bé hơn kết quả của phép chia thông thường. Ví dụ: Với phép chia thông thường, chúng ta có 3 / 2 = 1,5. Tuy nhiên với floor division, 3 // 2 = 1, bởi vì 1 là số nguyên lớn nhất bé hơn 1,5. Lấy một ví dụ khác: Với phép chia thông thường, -57 / 26 = -2,19. Tuy nhiên với floor division, -57 // 26 = -3, bởi vì -3 là số nguyên lớn nhất bé hơn -2,19.
Tổng kết lại, nếu chúng ta ở vị trí i trong mảng arr và chúng ta dịch k ký tự, công thức tính vị trí sau khi dịch chuyển là i + k – 26 * ((i + k) // 26).
b. Code:
Bước 1: Viết các câu lệnh khai báo cần thiết
Chúng ta sử dụng câu lệnh input() để hỏi người dùng khi nào muốn dừng trò chơi và vòng lặp while để tiếp tục trò chơi tương tự như trò chơi Nhà thám hiểm và cánh cửa bí mật ở bài 2. Chúng ta cũng tạo mảng arr để lưu bảng chữ cái:
arr = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
tiep = 'y'
while tiep == 'y':
tiep = input('Nhập y để tiếp tục hoặc n để thoát: ')
Trong vòng lặp while, chúng ta sẽ sử dụng câu lệnh input()để yêu cầu người dùng nhập câu cần mã hóa và số ký tự muốn dịch chuyển. Chúng ta cần tạo biến để lưu chuỗi sau khi được mã hoá:
plaintext = str(input("Bạn hãy nhập câu muốn mã hoá: ")).upper()
jump = int(input("Bạn muốn dịch sang mấy ký tự? "))
t = ''
Để đơn giản, chúng ta sẽ sử dụng câu lệnh .upper() để in hoa tất cả các ký tự trong câu người dùng nhập vào. Code hoàn chỉnh sẽ là:
arr = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
tiep = 'y'
while tiep == 'y':
plaintext = str(input("Bạn hãy nhập câu muốn mã hoá: ")).upper()
jump = int(input("Bạn muốn dịch sang mấy ký tự? "))
t = ''
tiep = input('Nhập y để tiếp tục hoặc n để thoát: ')
Bước 2: Xác định vị trí của ký tự trong mảng arr:
Một câu được biểu diễn bằng kiểu dữ liệu chuỗi (string) trong Python. Chúng ta đã được học ở bài 3, một chuỗi là một mảng mà phần tử là các ký tự trong chuỗi. Ví dụ: chuỗi “STEAM” là một mảng gồm 5 phần tử “S”, “T”, “E”, “A”, “M”. Như vậy để lấy các ký tự từ chuỗi, chúng ta có thể sử dụng vòng lặp for:
for character in plaintext:
print(character)
Chúng ta có thể sử dụng câu lệnh print để debug. Trong vòng lặp for, để lấy ra vị trí của ký tự ở trong mảng arr, chúng ta sử dụng thêm vòng lặp while với biến i để lưu vị trí của ký tự trong mảng. Biến i bắt đầu từ 0 và sẽ được cập nhật trong vòng lặp để đi đến vị trí mới trong mảng arr. Chúng ta sử dụng câu lệnh if để kiểm tra xem phần tử ở vị trí i trong mảng arr có giống với ký tự trong chuỗi không. Nếu giống, chúng ta sẽ break. Chúng ta vẫn có thể sử dụng câu lệnh print để debug:
i = 0
while i < len(arr):
if character == arr[i]:
print('Giống')
break
i = i + 1
Code hoàn chỉnh sẽ là:
arr = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
tiep = 'y'
while tiep == 'y':
plaintext = str(input("Bạn hãy nhập câu muốn mã hoá: ")).upper()
jump = int(input("Bạn muốn dịch sang mấy ký tự? "))
t = ''
for character in plaintext:
i = 0
while i < len(arr):
if character == arr[i]:
print('Giống')
break
i = i + 1
tiep = input('Nhập y để tiếp tục hoặc n để thoát: ')
Bước 3: Mã hoá ký tự:
Sau khi xác định được vị trí i của một ký tự trong chuỗi, chúng ta sẽ sử dụng công thức tìm vị trí mới ở trong phần thuật toán để xác định ký tự sau khi mã hoá:
Ngoài ra, chúng ta sẽ thêm một trường hợp. Nếu ký tự là khoảng trắng thì ký tự sau khi mã hoá cũng sẽ là khoảng trắng:
elif character == ' ':
character_code = ' '
Code hoàn chỉnh sẽ là:
arr = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
tiep = 'y'
while tiep == 'y':
plaintext = str(input("Bạn hãy nhập câu muốn mã hoá: ")).upper()
jump = int(input("Bạn muốn dịch sang mấy ký tự? "))
t = ''
for character in plaintext:
i = 0
while i < len(arr):
if character == arr[i]:
character_code = arr[i + jump - len(arr) * ((i + jump) // len(arr))]
breakelif character == ' ':
character_code = ' '
i = i + 1
tiep = input('Nhập y để tiếp tục hoặc n để thoát: ')
Bước 4: Kết nối các ký tự sau khi mã hoá thành chuỗi:
Các ký tự trong chuỗi có thể được xem như một chuỗi con. Để kết nối hai chuỗi thành một chuỗi, chúng ta sử dụng +:
t = t + character_code
Ở bước 1, chúng ta đã sử dụng biến t để lưu câu sau khi được mã hoá. Cuối cùng, chúng ta sẽ in ra câu sau khi được mã hoá:
print('Câu sau khi được mã hoá là: %s' % t)
Chúng ta sử dụng %s để thêm vào một biến có kiểu dữ liệu chuỗi vào câu lệnh print. Ngoài ra chúng ta sẽ thêm % cùng với tên biến.
5. Tada!!!
Như vậy, các bạn học sinh đã hoàn thành xong game giúp mã hoá và giải mã Caesar nhanh chóng rồi đấy. Tuy quá trình làm game không ít khó khăn nhưng chắc chắn thành quả của các bạn rất hữu ích để áp dụng ngay trong cuộc sống. Chúng ta hoàn toàn có thể sử dụng chương trình này để mã hoá ngay một câu đố và đem cho mọi người đau đầu giải mã.
Chương trình Python hoàn chỉnh của game sẽ là:
# -*- coding: utf-8 -*-
arr = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
tiep = 'y'
while tiep == 'y':
plaintext = str(input("Bạn hãy nhập câu muốn mã hoá: ")).upper()
jump = int(input("Bạn muốn dịch sang mấy ký tự? "))
t = ''
for character in plaintext:
i = 0
while i < len(arr):
if character == arr[i]:
character_code = arr[i + jump - len(arr) * ((i + jump) // len(arr))]
breakelif character == ' ':
character_code = ' '
i = i + 1
t = t + character_code
print('Câu sau khi được mã hoá là: %s' % t)
tiep = input('Nhập y để tiếp tục hoặc n để thoát: ')
Có rất nhiều cách chúng ta có thể cải tiến game này. Các bạn hãy nghĩ một cách nào đó chúng ta có thể loại bỏ vòng lặp while sử dụng để đi qua các phần tử trong mảng arr. Ngoài ra, các bạn có thể cải tiến game bằng cách mã hoá cả chữ hoa và chữ thường, chứ không cần phải chuyển hết sang chữ hoa.
Không chỉ vậy, thầy Harry và thầy Đức có một gợi ý hữu ích cho các bạn học sinh. Nếu chúng ta còn nhớ trong bài Vui học cùng thầy cô 1, thầy Đức đã giới thiệu cho chúng ta bảng mã ASCII. Trong bảng mã ASCII cũng có hai bảng chữ cái in hoa và in thường đấy. Chúng ta có thể chuyển một ký tự sang mã ASCII bằng câu lệnh ord() và chuyển từ mã ASCII về lại ký tự bằng câu lệnh chr(). Sau đó, chúng ta có thể chuyển từ số trong bảng mã ASCII thành vị trí của một phần tử trong mảng arr. Các bạn hãy cùng thử nhé!
Một gợi ý nữa để cải tiến game đó là chúng ta có thể sử dụng phép toán % trong Python để tính số lần chúng ta đi hết mảng arr. Phép toán này giúp chúng ta tìm số dư trong một phép chia. Ví dụ: 3 % 2 = 1.
Nhờ áp dụng ngay kiến thức của bài 3 khoá CS 101, bạn Đức Hoàng đã tạo ra được game “Mã hóa Caesar” hết sức thú vị và thực tế. Các bạn học sinh cũng hãy thử bắt tay vào sáng tạo một game cho riêng mình nhé! Sau khi hoàn thành game, các bạn có thể chia sẻ game của mình trên STEAMese Profile.
— — —
STEAM for Vietnam Foundation là tổ chức phi lợi nhuận 501(c)(3) được thành lập tại Hoa Kỳ với sứ mệnh thúc đẩy các hoạt động liên quan tới giáo dục STEAM (Science — Khoa học, Technology — Công nghệ, Engineering — Kỹ thuật, Arts — Nghệ thuật, Mathematics — Toán học) tại Việt nam. STEAM for Vietnam được thành lập và vận hành bởi đội ngũ tình nguyện viên là du học sinh và chuyên gia người Việt trên khắp thế giới.