Thực hành: Xoay tam giác

Hướng dẫn cách suy luận và cài đặt chương trình lầm lượt xoay một tam giác vuông cân 90 độ theo chiều kim đồng hồ.

Bài toán

Khi bắt đầu thực thi, chương trình (ctr) sẽ yêu cầu nhập vào độ dài cạnh góc vuông (h) của một tam giác vuông cân. Ctr sẽ vẽ tam giác vuông cân có cạnh vừa nhập với góc vuông nằm ở góc trái phía dưới. Sau đó lần lượt nhấn ENTER để xoay tam giác này 90 độ theo chiều kim đồng hồ. Nhấn phím bất kỳ (khác ENTER) để kết thúc.

Nhap h: 4
				
Bắt đầu chương trình
*
* *
* * *
Nhấn ENTER lần 1
* * *
* * 
*
Nhấn ENTER lần 2
* * *
  * * 
    *
Nhấn ENTER lần 3
    *
  * *
* * *
Nhấn ENTER lần 4
*
* *
* * *
Nhấn ENTER lần 5
...		
				
Tiếp tục đến khi nhấn phím khác ENTER

1. KHUNG CHƯƠNG TRÌNH BAN ĐẦU

Chương trình cần thư viện stdio để sử dụng các hàm printfscanf:

1
#include <stdio.h>

Chương trình cần thêm thư viện conio để sử dụng hàm getch (đọc 1 ký tự từ bàn phím):

1
#include <conio.h>

Trước mắt, ctr cần một biến kiểu nguyên để lưu chiều dài cạnh góc vuông. Ta đặt tên là h, chọn kiểu là int (hoặc bất kỳ kiểu số nguyên nào khác). Khung chương trình cho việc đọc dữ liệu sẽ là:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <conio.h>
int main()
{
    int h;  //khai báo biến h có kiểu int
    printf("Nhap h: "); //hiển thị ra màn hình yêu cầu nhập độ dài cạnh góc vuông
    scanf("%d", &h); //đọc độ dài cạnh góc vuông và lưu vào biến h
     
    //lệnh này chỉ để kiểm tra xem chương trình việc đọc dữ liệu đã đúng hay chưa
    printf("Ban vua nhap: %d", h);
    getch();
}

Lúc này, bạn biên dịch và chạy chương trình. Nếu thành công thì bạn có thể yên tâm rằng những đoạn mã vừa rồi là đúng, sau này nếu có lỗi thì chắc chắn sẽ không nằm trong vùng này.

2. VẼ TAM GIÁC VỊ TRÍ 1

Tiếp theo, để đơn giản, sau khi có h ta sẽ lần lượt vẽ tam giác ở từng góc xoay. Đầu tiên sẽ là vị trí 1: Góc vuông ở bên trái phía dưới.

a. Nhận xét

Ta nhận xét, để vẽ được tam giác này ta cần phải lặp. Có 3 cấu trúc để lặp đó là while, do..while, và for. Tuy nhiên, số lần lặp ở đây là biết trước (số dấu *, số hàng hay số cột biết trước), do vậy nên sử dụng cấu trúc for. Có nhiều cách sử dụng for để vẽ vị trí này, một cách là:

  • Vẽ từng hàng từ trên xuống dưới. Chắc chắn không thể vẽ từ dưới lên trên vì lệnh printf sẽ vẽ lên màn hình Console theo từng hàng từ trái sang phải, hết hàng này hoặc có lệnh \n thì sẽ xuống hàng tiếp theo.
  • Trong mỗi hàng sẽ vẽ từ trái sang phải.

b. Chạy từng hàng

Để vẽ từng hàng, ta sử dụng một biến kiểu nguyên, theo truyền thống thì đặt tên là i, và cho biến này chạy từ 1 đến h. Ý muốn rằng với mỗi giá trị của i ta sẽ vẽ dòng thứ i của tam giác. Như vậy ta sẽ có cấu trúc để duyệt h dòng là:

1
2
for (i=1; i<=h; i++)
    [Vẽ_Dòng_i]

Vậy bây giờ ta sẽ viết khối lệnh [Vẽ_Dòng_i] như thế nào để vẽ dòng i?

c. Chạy từng cột

Nhận xét tiếp: với dòng 1 ta vẽ 1 dấu *, với dòng 2 ta vẽ 2 dấu *,..., với dòng i ta vẽ i dấu **. Như vậy, với dòng i ta sẽ sử dụng một biến nguyên nữa sẽ chạy i lần từ 1 đến i để vẽ i dấu *, theo truyền thống người ta thường đặt tên biến này là j. Như vậy, lúc này ta làm rõ thêm mã lệnh phần vẽ như sau:

1
2
3
for (i=1; i<=h; i++)
    for (j=1; j<=i; j++)
        printf("*");

Tuy nhiên đến đây hình như chưa ổn ở đâu đó :-?

d. Xuống hàng

À, khi vẽ xong một hàng thì phải xuống hàng mới vẽ hàng tiếp theo. Do vậy, sau khi j chạy để vẽ i dấu * thì phải xuống hàng, nghĩa là lệnh xuống hàng sẽ cùng cấp với lệnh for của j. Như vậy, lệnh vẽ tam giác sẽ là:

1
2
3
4
for (i=1; i<=h; i++)
    for (j=1; j<=i; j++))
        printf("*");
    printf("\n");

Ui, sau lệnh for của i là 2 lệnh con (for j và xuống hàng) nên phải bọc 2 lệnh này trong cặp { .. } và để cho gọn, lệnh printf("*") có thể kéo lên:

1
2
3
4
5
for (i=1; i<=h; i++)
{
    for (j=1; j<=i; j++) printf("*");
    printf("\n");
}

e. Nhìn tổng thể xem thế nào...

Mọi thứ coi bộ đã tạm ổn. Bây giờ xem lại toàn bộ chương trình để vẽ tam giác ở vị trí 1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <conio.h>
int main()
{
    int h;  //khai báo biến h có kiểu int
    printf("Nhap h: "); //hiển thị ra màn hình yêu cầu nhập độ dài cạnh góc vuông
    scanf("%d", &h); //đọc độ dài cạnh góc vuông và lưu vào biến h
     
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
    getch(); //dừng màn hình
}

Khoan hãy nhấn F5 để chạy chương trình mà hãy biên dịch (build) chương trình trước xem có trục trặc gì không!

Hừ, lỗi.

f. Sửa lỗi khai báo

Hãy mở cửa sổ lỗi để xem cụ thể lỗi gì bằng cách:

  • Nhấn vào menu View → chọn ErrorList (nếu sử dụng Visual Studio phiên bản Professional hay Ultimate), hoặc
  • Nhấn vào menu View → chọn Other windows → chọn ErrorList (nếu sử dụng Visual Studio phiên bản Express).

Nhìn vào cửa sổ, dòng đầu tiên ta sẽ thấy:

error C2065: "i" : undeclared identifier ...

Vì nó không báo bằng tiếng Việt nên phải tra từ điển thôi. Coi nào...undeclare nghĩa là không khai báo, công bố, tuyên bố. À, té ra là biến i chưa được khai báo :-)

Mà hình như biến j cũng vậy. Vậy thì khai báo hai biến i và j có kiểu int. Thấy cùng chung kiểu với biến h nên có thể khai báo chung trong một lệnh:

1
int h, i, j;

g. Chạy thử xem thế nào!

Chương trình lúc này sẽ là:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <conio.h>
int main()
{
    int h, i, j;
    printf("Nhap h: "); //hiển thị ra màn hình yêu cầu nhập độ dài cạnh góc vuông
    scanf("%d", &h); //đọc độ dài cạnh góc vuông và lưu vào biến h
     
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
    getch(); //dừng màn hình
}

Biên dịch chương trình. Lúc này thì đã hết lỗi. Nhấn F5 để chạy nào...

Nhap h: 5
*
**
***
****
*****

Yeah!

Tốt nhất bây giờ bạn hãy nhìn lại từ đầu để thực sự hiểu những gì đang xảy ra rồi hãy đọc tiếp.

h. Đưa vào hàm

Để chương trình được gọn gàng, đỡ rối mắt, chắc ta nên đưa các lệnh để vẽ tam giác ở vị trí 1 này vào một hàm (đặt tên là Ve1 cho đơn giản) và ở hàm main sẽ có lời gọi đến hàm này.

Để coi, hàm này sẽ có nhiệm vụ là nhận chiều dài cạnh góc vuông sau đó vẽ tam giác ở vị trí 1 ra màn hình. Như vậy, hàm nhận 1 tham số ở đầu vào, đó là chiều cao h. Hàm không có giá trị trả về (nên sẽ là void). Cấu trúc chương trình lúc này sẽ là:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include ...
void <strong>Ve1</strong>(int h)
{
    [Vẽ_tam_giác_vị_trí_1]
}
int <strong>main</strong>()
{
    int h;
    printf("Nhap h: ");
    scanf("%d", &h);
     
    Ve1(h);
    getch(); //dừng màn hình
}

Chú ý, do lúc này ở hàm main không sử dụng hai biến i và j nữa nên không cần khai báo. Bây giờ chỉ đơn giản đưa đoạn mã vẽ tam giác vào hàm Ve1. Lúc này, hàm Ve1 lại cần 2 biến i, j nên ta phải khai báo trước khi sử dụng. Chương trình lúc này sẽ là:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <conio.h>
void <strong>Ve1</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
}
int <strong>main</strong>()
{
    int h, i, j;
    printf("Nhap h: "); //hiển thị ra màn hình yêu cầu nhập độ dài cạnh góc vuông
    scanf("%d", &h); //đọc độ dài cạnh góc vuông và lưu vào biến h
     
    Ve1(h);
    getch(); //dừng màn hình
}

Biên dịch chương trình sau đó nhấn F5 để chạy. Kết quả sẽ vẫn như ở trên, nhưng lúc này cấu trúc chương trình đã sẵn sàng để vẽ các vị trí tiếp theo.

3. VẼ TAM GIÁC VỊ TRÍ 2

a. Nhận xét

Để vẽ tiện trong việc suy nghĩ ý tưởng, có lẽ nên thống nhất cách đánh số thứ tự các hàng, cột như hình dưới đây (đương nhiên bạn có thể có cách đánh số cho riêng mình, ví dụ: từ 0, thay vì 1):

  1 2 3 4 5
1 * * * * *
2 * * * *  
3 * * *    
4 * *      
5 *        

Ta thấy rõ ràng là phải vẽ từng hàng, từ trên xuống dưới. Với mỗi hàng, vẽ từ trái sang phải. Để coi:

  • Hàng 1 vẽ h dấu *
  • Hàng 2 vẽ h-1 dấu *
  • ...
  • Hàng h-1 vẽ 2 dấu *
  • Hàng h vẽ 1 dấu *

Trong mỗi hàng ở trên, chỉ số đầu (số hàng) cộng với chỉ số sau (số dấu *) luôn bằng h+1. Như vậy trong trường hợp tổng quát:

  • Hàng i vẽ h-i+1 dấu *

Đây là một kết luận gần như quan trọng nhất cho vị trí 2 này.

b. Viết mã

Quy trình lý luận và viết mã hoàn toàn tương tự như trường hợp trên (vị trí 1) chỉ khác ở chỗ: tại dòng thứ i, thay vì vẽ i dấu * (vị trí 1) thì bây giờ sẽ vẽ (n-i+1) dấu *. Như vậy, đoạn mã để vẽ tam giác lúc này sẽ là:

1
2
3
4
5
for (i=1; i<=h; i++) //duyệt từng hàng
{ //với mỗi hàng i
    for (j=1; j<=h-i+1; j++) printf("*"); //hiển thị (<strong>h-i+1</strong>) dấu *
    printf("\n"); //xuống hàng
}

Viết một hàm mới có tên Ve2 để đảm trách việc vẽ này. Chương trình đầy đủ lúc này sẽ là:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <conio.h>
void <strong>Ve1</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
}
void <strong>Ve2</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=h-i+1; j++) printf("*"); //hiển thị (h-i+1) dấu *
        printf("\n"); //xuống hàng
    }
}
int <strong>main</strong>()
{
    int h, i, j;
    printf("Nhap h: "); //hiển thị ra màn hình yêu cầu nhập độ dài cạnh góc vuông
    scanf("%d", &h); //đọc độ dài cạnh góc vuông và lưu vào biến h
     
    Ve1(h);
    Ve2(h);
    getch(); //dừng màn hình
}

Biên dịch chương trình sau đó nhấn F5 để chạy. Hy vọng mọi việc suông sẻ :)

4. VẼ TAM GIÁC VỊ TRÍ 3

a. Nhận xét

Thoạt nhìn thì trông có vẻ cũng giống như 2 vị trí vừa rồi, tuy nhiên, nhìn kỹ thì thấy có chút vấn đề.

  1 2 3 4 5
1 * * * * *
2   * * * *
3     * * *
4       * *
5         *

Không như 2 trường hợp trên, trong trường hợp này trước mỗi hàng có các khoảng trắng. Cũng nên bắt đầu bằng việc ĐẾM:

  • Hàng 1 vẽ 0 dấu cách và h dấu *
  • Hàng 2 vẽ 1 dấu cách và h-1 dấu *
  • ...
  • Hàng h-1 vẽ h-2 dấu cách và 2 dấu *
  • Hàng h vẽ h-1 dấu cách và 1 dấu *

Có lẽ lúc này bạn nên dành vài phút để tự mình tìm ra quy luật.. Nếu được thì tuyệt vời, nếu cũng được cũng rất có giá trị đó bạn ạ :)

Nó đơn giản đến bất ngờ: quy luật giống hệt vị trí 2, chỉ thêm vào phần dấu cách:

  • Hàng i vẽ i-1 dấu cách và h-i+1 dấu *

b. Viết mã

Đoạn mã để vẽ tam giác vị trí 3sẽ là:

1
2
3
4
5
6
for (i=1; i<=h; i++) //duyệt từng hàng
{ //với mỗi hàng i
    for (j=1; j<=i-1; j++)   printf(" "); //hiển thị (<strong>i-1</strong>) dấu cách
    for (j=1; j<=n-i+1; j++) printf("*"); //hiển thị (<strong>n-i+1</strong>) dấu *
    printf("\n"); //xuống hàng
}

Viết một hàm mới có tên Ve2 để đảm trách việc vẽ này. Chương trình đầy đủ lúc này sẽ là:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <conio.h>
void <strong>Ve1</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
}
void <strong>Ve2</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=n-i+1; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
}
void <strong>Ve3</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i-1; j++)   printf(" "); //hiển thị (<strong>i-1</strong>) dấu cách
        for (j=1; j<=n-i+1; j++) printf("*"); //hiển thị (<strong>n-i+1</strong>) dấu *
        printf("\n"); //xuống hàng
    }
}
int <strong>main</strong>()
{
    int h, i, j;
    printf("Nhap h: "); //hiển thị ra màn hình yêu cầu nhập độ dài cạnh góc vuông
    scanf("%d", &h); //đọc độ dài cạnh góc vuông và lưu vào biến h
     
    Ve1(h);
    Ve2(h);
    Ve3(h);
    getch(); //dừng màn hình
}

Biên dịch chương trình sau đó nhấn F5 để chạy. Nếu ngon lành, có lẽ bạn nên đứng dậy, ra ngoài đi dạo & hít thở 1 lát :)

5. VẼ TAM GIÁC VỊ TRÍ 4

a. Nhận xét

Nếu đã hiểu cách vẽ vị trí 3 thì vị trí 4 này không thành vấn đề.

  1 2 3 4 5
1         *
2       * *
3     * * *
4   * * * *
5 * * * * *

ĐẾM nào:

  • Hàng 1 vẽ h-1 dấu cách và 1 dấu *
  • Hàng 2 vẽ h-2 dấu cách và 2 dấu *
  • ...
  • Hàng n-1 vẽ 1 dấu cách và n-1 dấu *
  • Hàng h vẽ 0 dấu cách và h dấu *

Bạn khoan hãy đọc tiếp. thử nhìn coi có quy luật gì!? Thứ nhất:

  • Hàng i vẽ h-i dấu cách và i dấu *

b. Viết mã

Chương trình đầy đủ lúc này sẽ là:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <conio.h>
void <strong>Ve1</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
}
void <strong>Ve2</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=n-i+1; j++) printf("*"); //hiển thị i dấu *
        printf("\n"); //xuống hàng
    }
}
void <strong>Ve3</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=i-1; j++)   printf(" "); //hiển thị (<strong>i-1</strong>) dấu cách
        for (j=1; j<=n-i+1; j++) printf("*"); //hiển thị (<strong>n-i+1</strong>) dấu *
        printf("\n"); //xuống hàng
    }
}
void <strong>Ve4</strong>(int h)
{
    int i,j;
    for (i=1; i<=h; i++) //duyệt từng hàng
    { //với mỗi hàng i
        for (j=1; j<=h-i; j++) printf(" "); //hiển thị (<strong>h-i</strong>) dấu cách
        for (j=1; j<=i; j++)   printf("*"); //hiển thị (<strong>i</strong>) dấu *
        printf("\n"); //xuống hàng
    }
}
int <strong>main</strong>()
{
    int h, i, j;
    printf("Nhap h: "); //hiển thị ra màn hình yêu cầu nhập độ dài cạnh góc vuông
    scanf("%d", &h); //đọc độ dài cạnh góc vuông và lưu vào biến h
     
    Ve1(h);
    Ve2(h);
    Ve3(h);
    Ve4(h);
    getch(); //dừng màn hình
}

Biên dịch chương trình sau đó nhấn F5 để chạy. Nếu ngon lành, có lẽ bạn nên đứng dậy, ra ngoài đi dạo & hít thở 1 lát :)

6. XOAY

a. Chọn cấu trúc lặp

Việc này có vẻ không đơn giản đây...

Cứ lý luận từ từ thôi, từ những gì đơn giản :)

Chắc chắn sẽ phải LẶP, lặp lại việc vẽ tam giác. Có 3 cấu trúc để lặp: for, while và do..while. Chọn cái nào?

Mỗi lúc gặp vấn đề này thì cần phải trả lời cho câu hỏi: Số lần lặp có biết trước? Dễ òm, không, vì người ta thích thì có thể nhấn 20 cái enter để nó xoay, không thích thì chỉ một hai cái. Như vậy loại bỏ for. Còn lại 2 sự lựa chọn.

Mỗi lúc cân nhắc giữa while và do..while, cần phải trả lời cho câu hỏi: Số lần vẽ tối thiểu là 0 hay 1? Rõ ràng là 1, vì dù thích hay không thích, chương trình vẫn sẽ vẽ ít nhất tam giác ở vị trí 1 sau khi người sử dụng nhập h và nhấn enter. Như vậy sẽ chọn do..while. Nghĩa là lúc này cấu trúc sẽ là:

1
2
3
4
do
{
    Vẽ; //vẽ tam giác ở vị trí nào đó
}while(vẫn_nhấn_enter);

b. Đọc dữ liệu bàn phím

Làm sao cài đặt phần: cứ lặp việc vẽ trong khi người ta cứ nhấn enter?
Trước mắt phải cần một biến kiểu char. Đặt tên là c cho nó đơn giản:

1
char c; //khai báo biến c có kiểu char

Để đọc ký tự người ta gõ từ phím, ta sử dụng hàm getch mà từ trước đến giờ chỉ quen sử dụng để "dừng màn hình":

1
c = getch();

Làm sao để biết người ta nhấn phím nào? À ha, người ta nhấn phím gì thì được lưu trong biến c vừa đọc mà. Ví dụ: nhấn phím a thì biến c sẽ lưu giá trị nguyên là 97 (mã ASCII của ký tự a). Như vậy vấn đề lúc này chỉ là: mã ASCII của enter là bao nhiêu? Bạn chỉ cần Google với từ khóa: mã ascii phím enter, trong link đầu tiên hoặc thứ 2 sẽ trả lời. Nhưng bây giờ tôi trả lời luôn đó là 13. Đến đây ta có thể kết hợp chúng lại với nhau:

1
2
3
4
5
6
char c;
do //lặp
{
    Vẽ; //vẽ tam giác ở vị trí nào đó
    c = getch(); //đợi người ta gõ 1 phím nào đó và lưu mã ASCII phím này vào c
}while(c==13); //trong khi người ta nhấn enter

c. Luân phiên 4 vị trí

Làm sao để cứ lần lượt vẽ từng vị trí? Nghĩa là ta làm công việc đếm luân phiêm: 1 → 2 → 3 → 4 → 1 → 2 → 3 → 4 → 1 → 2 → ...

Rõ ràng cần 1 biến kiểu nguyên để lưu số cần đếm, cụ thể là vị trí. Chọn kiểu int cho ngắn gọn, đặt tên là vitri.

1
int vitri;

Vị trí ban đầu là 1, do vậy ta khởi tạo giá trị trong lúc khai báo luôn:

1
int vitri = 1;

Cứ mỗi lần lặp thì sẽ vẽ tam giác ứng với vị trí hiện tại sau đó chuyển vị trí. Cấu trúc sẽ là:

1
2
3
4
5
6
7
8
char c;
int vitri = 1;
do //lặp
{
    Vẽ; //vẽ tam giác ở vị trí nào đó
    Chuyển_vị_trí;
    c = getch(); //đợi người ta gõ 1 phím nào đó và lưu mã ASCII phím này vào c
}while(c==13); //trong khi người ta nhấn enter

Mỗi lần chuyển, tăng vị trí lên 1 đơn vị, nhưng khi đã là 4 (không thể tăng lên 5) thì phải về lại 1. Một cách làm cho việc chuyển_vị_trínhư sau:

1
2
vitri++;
if (vitri==5) vitri=1;

Một cách khác, đơn giản nhưng có thể khó hiểu hơn một tí là chia 4 lấy dư (%) trước khi tăng 1. Bước chia lấy dư này chỉ đơn giản nếu vitri hiện tại là 4 thì sẽ quay trở lại 0. Vì bạn thấy đó nếu vitri nhỏ hơn 4 thì khi chia 4 lấy dư vẫn giữ nguyên (vd: 1 % 1 = 1):

1
vitri = (vitri % 4) + 1;

Coi lại cấu trúc lúc này:

1
2
3
4
5
6
7
8
char c;
int vitri = 1;
do //lặp
{
    Vẽ; //vẽ tam giác ở vị trí nào đó
    vitri = (vitri % 4) + 1;
    c = getch(); //đợi người ta gõ 1 phím nào đó và lưu mã ASCII phím này vào c
}while(c==13); //trong khi người ta cứ nhấn enter

d. Vẽ tam giác ứng với từng vị trí

Khi vitri=1 thì sẽ vẽ tam giác ở vị trí 1, khi vitri=2 thì sẽ vẽ tam giác ở vị trí 2,... Rõ ràng cần sử dụng cấu rẽ nhánh (if hoặc switch). Trường hợp này có 4 nhánh nên sử dụng switch sẽ hợp hơn.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char c;
int vitri = 1;
do //lặp
{
    switch (vitri)
    {
        case 1: Ve1(h); break;
        case 2: Ve2(h); break;
        case 3: Ve3(h); break;
        case 4: Ve4(h); break;
    }
    vitri = (vitri % 4) + 1;
    c = getch(); //đợi người ta gõ 1 phím nào đó và lưu mã ASCII phím này vào c
}while(c==13); //trong khi người ta cứ nhấn enter

e. Xóa hàm hình

Công việc cuối cùng là trong mỗi lần lặp, trước khi vẽ tam giác ta cần xóa sạch màn hình. Trong Visual C++, ta sử dụng hàm system với tham số là chuỗi "cls" (viết tắt của clear screen). Hàm này nằm trong thư viện stdlib.

7. KẾT HỢP TẤT CẢ

Đến đây ta có thể kết hợp mọi thứ lại với nhau. Sản phẩm đã hoàn thiện :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
void Ve1(int n)
{
    int i,j;
    for (i=1; i<=h; i++)
    {
        for (j=1; j<=i; j++) printf("*");
        printf("\h");
    }
}
void Ve2(int h)
{
    int i,j;
    for (i=1; i<=h; i++)
    {
        for (j=1; j<=h-i+1; j++) printf("*");
        printf("\h");
    }
}
void Ve3(int h)
{
    int i,j;
    for (i=1; i<=h; i++)
    {
        for (j=1; j<=i-1; j++) printf(" ");
        for (j=1; j<=h-i+1; j++) printf("*");
        printf("\h");
    }
}
void Ve4(int h)
{
    int i,j;
    for (i=1; i<=h; i++)
    {
        for (j=1; j<=h-i; j++) printf(" ");
        for (j=1; j<=i; j++) printf("*");
        printf("\h");
    }
}
int main()
{
    char c;
    int h,vitri,j;
    printf("Nhap do dai canh goc vuong: ");
    scanf("%d", &h);
    vitri = 1;
    do
    {
        system("cls"); //xóa màn hình
        switch (vitri)
        {
            case 1: ve1(h); break;
            case 2: ve2(h); break;
            case 3: ve3(h); break;
            case 4: ve4(h); break;
        }
        vitri = vitri % 4 + 1;
        c = getch();
    }while (c==13);
}

Bình luận (1)

Viết Bình luận
  • damvantai
    em cảm ơn thầy

    thầy giảng rất cụ thể và dễ hiểu

     

Viết Bình luận

Họ tên Bắt buộc
Email Bắt buộc
Tiêu đề Bắt buộc
Kiểu bình luận
Nội dung
Nhập mã được hiển thị: