01/10/2018, 16:56

Vui học - Bài 1 - Vẽ vời bằng sao (1)

Giới thiệu series “Vui học”

Series Vui học được xây dựng từ những ý tưởng của tác giả mỗi khi nhìn vào một topic gì đó có vẻ vui vui trên diễn đàn và thấy mọi người viết bài share ngắn ngắn hay hay, mình cũng nổi hứng viết một vài bài đóng góp

Anh Đạt boss, hungsteve, nicklauri viết bài về ngôn ngữ lập trình, mình viết bài có pha chút algorithm vào cho độc


Dạo qua diễn đàn, không hiếm topic có dạng vẽ hình bằng * (sao) như thế này.

Mọi người có ai biết thuật toán về vẽ hình trái tim trong java hay c++ ko ạ? Chỉ cho e với! E cám ơn

https://daynhauhoc.com/t/xin-cach-ve-hinh-trong-c/71291

Em mới học C++,anh chị nào chỉ dùm em cách vẽ chữ O trong C++ bằng ký tự * với smiley
viết chương trình vẽ một tam giác cân bằng dấu "*".trong ngôn ngữ C nha Các bậc tiền bối giúp với ạ.Bài này trong bài 17 list youtube học lập trình C của anh đạt
in ra màn hình hình tam giác bằng kí tự * . bạn ạ chưa nghĩ được thuật toán :(( [image]

Ngoài ra còn có các kiểu vẽ hình thoi, hình dấu +, các chữ số 0-9 như trên bảng điện tử,…

Để khởi động, ta sẽ làm 1 bài đơn giản trước.

Đề

Vẽ

  * * * * * *
 * * * * * *
* * * * * *

và phải dùng for.

Cách vẽ

Niềm vui toé loe ra từ đây ^^

Ta đánh số các cách theo thứ tự tăng dần của mức độ học để thấy mức độ hay và kì cục của mỗi cách.

Cách không có học

Làm con ngoan trò giỏi, thầy bảo gì làm nấy.

printf("  * * * * * *
");
printf(" * * * * * *
");
printf("* * * * * *
");

Ơ kìa, thiếu for mất rồi. Nâng cấp lên một chút nào:

int i;
for (i = 0; i < 1; i++) {
    printf("  * * * * * *
");
    printf(" * * * * * *
");
    printf("* * * * * *
");
}

Một số kiểu for khác vui hơn:

for (;;) { 
    /* lắp 3 dòng printf vào */
    break;
}
#include <climits>

for (int i = 0; i < INT_MAX; i++); // nhìn cho thật kĩ vào ^^
// 3 cái printf vào đây
for (int i = 0; !i; i ^= 1) // bitwise cho máu

Cách ít học

Khi đã học hơn một chút, ta biết 3 cái dòng này cứ na ná giống nhau, lắp for vào cho khoẻ. Nhưng ta không biết lắp thế nào cho vừa.

Ta nhanh mắt thấy

  • Dòng 1 có 2 dấu cách, rồi có * * * * * *.
  • Dòng 2 có 1 dấu cách, rồi có * * * * * *.
  • Dòng 3 có 0 dấu cách, rồi có * * * * * *.

Ta code thật nhanh tay:

int i, j;
for (i = 2; i >= 0; i--) { // số dấu cách đầu dòng
    for (j = 0; j < i; j++) printf(" "); // in ra dấu cách đầu dòng
    printf("* * * * * *
");
}

Có vẻ ổn rồi chứ nhỉ?

Cách có học

Nếu như một ngày đẹp trời nào đó, thầy lỡ tay gõ nhầm, thay vì bắt bạn in ra 1 dòng 6 sao thì 1 dòng phải in ra hàng trăm sao, hàng nghìn sao,… thì ta gõ tay từng sao trong printf làm sao đây, gõ đến hết giờ cũng không xong

Bạn khóc đến sưng húp cả 2 mắt mà chả thấy Bụt nào hiện lên hỏi cả Rồi trong lúc chùi nước mắt, bạn lại thấy sao cái dãy sao này có vẻ như lặp lại như 3 cái dòng vừa nãy. Bạn lao ngay vào code:

int i, j;
for (i = 2; i >= 0; i--) { // vẫn là số dấu cách đầu dòng
    for (j = 0; j < i; j++)
        printf(" "); // vẫn in ra dấu cách đầu dòng

    // phép màu bắt đầu từ đây
    for (j = 0; j < 6; j++)
        printf("* ");

    printf("
"); // bình tĩnh kết thúc cái dòng sao của nợ này
}

Rồi bạn vô tình nhận ra trong lúc in sao có lỡ thừa ra dấu cách ở cuối dòng, bạn đành tặc lưỡi kệ. Sao bảo có học mà chả thấy hay ho hơn ít học gì sất

Cách bác học

Một cách super có học, gọi là bác học. Nó super có học hơn vì nó vứt đi được cái dấu cách thừa thãi ở cuối đáng ghét kia :x

Dấu cách đứng bên phải dấu sao mà thấy thừa dấu cách thì cho nó đứng bên trái cho đỡ thừa.

int i, j;
for (i = 2; i >= 0; i--) {
    for (j = 0; j < i; j++)
        printf(" ");

    for (j = 0; j < 6; j++)
        printf(" *");

    printf("
");
}

Output:

   * * * * * *
  * * * * * *
 * * * * * *

Vấn đề xảy ra, tự dưng lòi đâu cái dấu cách ở đầu mỗi dòng, trông đáng ghét quá Vậy vứt đi bằng cách nào?

Có sửa chỗ vòng for in dấu cách đầu dòng cũng không ổn. Vẫn thừa dấu cách ở dòng cuối :’(

  * * * * * *
 * * * * * *
 * * * * * * // cái dòng đáng ghét -_- 

Đến đây ta áp dụng chút kiến thức toán học cùi ta còn rớt lại.

Ném dòng sao kia lên trục toạ độ, mỗi kí tự là 1 điểm, có đánh số đàng hoàng.

| `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` |
|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
|  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  | 10  |

Coi dấu * đầu tiên là gốc toạ độ luôn cho dễ.

Còn những dấu cách đằng trước, ta coi nó đặt trên các điểm âm. Ta thích thì in nó ra, không thích thì thôi.

Lắp code vào:

int i, j;
for (i = -2; i <= 0; i++) { // i là điểm đầu
    for (j = i; j < 10; j++) {
        if (j >= 0 && j % 2 == 0)
            printf("*");
        else
            printf(" ");
    }
    printf("
");
}

Lạ nhỉ, sao code này đúng?

Ta thử vẽ lại trên hệ trục toạ độ như hình trên:

  • Dòng 1:
| ` ` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` |
|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
| -2  | -1  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  | 10  |
  • Dòng 2:
| ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` |
|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
| -1  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  | 10  |
  • Dòng 3:
| `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` | ` ` | `*` |
|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
|  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  | 10  |

Vì ta biết dòng cuối có dấu * ở đầu nên ta coi dấu * đầu tiên là gốc luôn. Trên mỗi dòng, vị trí các kí tự đều phụ thuộc vào dấu * đầu tiên của mỗi dòng hết.

Khó hiểu quá, đúng không? Code bác học mà

Tổng quát hoá

Thay vì chỉ có 3 dòng, mỗi dòng 6 sao thì ta upgrade lên m dòng, mỗi dòng n sao. Cách làm vẫn tương tự. Không khuyến khích 2 cách đầu tiên, quá khổ sở

Kết luận

Đề gốc:

https://daynhauhoc.com/t/xin-cach-ve-hinh-trong-c/71291

Vào xem cmt, có lẽ sẽ có cái cao học hơn cách mình nói nữa đó

viết 19:07 ngày 01/10/2018

Mình k rõ mọi người thế nào chứ bản thân mình vẫn thích cách người ta đưa ra hướng làm cho bài code, tức là cách tiếp cận bài toán. Như vậy sẽ giúp người đọc code hiểu được vì sao lại lặp chỗ này, tại sao lại bắt đầu từ j=2 mà k phải j=1…
Cái này chỉ là ý kiến cá nhân, mình biết nó sẽ tốn công cho người làm

Bài liên quan
0