Bài tập về vòng lặp (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

ndu96081631

Huyền thoại GPE
Thành viên BQT
Super Moderator
Tham gia
5/6/08
Bài viết
30,703
Được thích
53,974
Những ai đã từng xem qua bài viết này: Giới thiệu Cơ bản về vòng lặp For . . . next của sư phụ ptm0412 giờ hãy cùng làm 1 vài bài tập từ đơn giản đến nâng cao nhé
Xin mở màn bằng 1 bài tập sau:

Bài tập 01:

Hãy tính xem từ năm 1900 đến nay có bao nhiêu ngày thuộc dạng THỨ SÁU NGÀY 13
------------------------
Các bạn ai có bài tập gì hay xin post lên đây nhé! Cảm ơn
 
Chỉnh sửa lần cuối bởi điều hành viên:
Không biết như thế này có đúng không, Anh xem giúp nhé!
Mã:
Sub tinhngay()
Dim i As Date: Dim tong As Long
tong = 0
  For i = DateSerial(1900, 1, 1) To DateSerial(2010, 8, 17)
    If Weekday(i) = 6 And Day(i) = 13 Then tong = tong + 1
  Next
 MsgBox "So ngay la: " & tong
End Sub
 
Upvote 0
Cám ơn ndu đã nhắc tới và tiếp tục topic cũ. Quả thực lúc viết topic đó, mình nhớ gì viết nấy, và cũng muốn có nhiều bài tập hay hay từ thấp đến cao, nhưng nhất thời không nghĩ ra.

Nhân đây, mình rất mong mỏi những thành viên đang tập tành học VBA , nên tham gia topic này. Kể cả một vài thành viên đang viết code ầm ầm, nhưng theo nhận xét riêng thì đang rất mất căn bản trong tư duy logic.

Tư duy logic là cái cần thiết nhất, căn bản nhất mà người lập trình cần phải có. Các câu lệnh, cú pháp, hàm có sẵn, từ khoá, ... có thể mở Help lên xem, hoặc vào GPE hỏi, chứ tư duy logic thì không ai giúp được. Chỉ có thể rèn luyện bằng những bài tập nhỏ, những ứng dụng nhỏ, vận động trí óc tìm ra thuật toán để giải, ..

Rèn luyện tư duy, thì đây là 1 topic rất hay để các bạn tham gia và rèn luyện.

Đừng nghĩ rằng khi Excel đã có hàm giai thừa mà bắt các bạn tính giai thừa 1 số n bằng VBA là vô bổ, đó là rèn luyện suy luận đấy.


Hãy bắt đầu từ cái đơn giản nhất.


Gởi ndu:
Hãy từ từ nhé, hãy để vài người tham gia giải quyết cho rốt ráo 1 bài tập, rồi hãy đưa bài tập kế.
 
Upvote 0
Đúng, chắc vậy, nhưng bạn còn lãng fí kkhoảng 30 llần tthời gian cơ dđấy!

Thêm 1 vòng lặp nữa xem sao!
1 vòng lặp theo tháng, 1 vòng lặp theo năm . . . .
 
Upvote 0
Thêm 1 vòng lặp nữa xem sao!
1 vòng lặp theo tháng, 1 vòng lặp theo năm . . . .
Tôi nghĩ cũng chỉ cần 1 vòng lặp thôi.
PHP:
Sub Test()
Dim SoNgay As Long
    For i = 1 To (Year(Date) - 1900) * 12 + Month(Date) + (Day(Date) < 13)
        If Weekday(DateSerial(1900, i, 13)) = 6 Then SoNgay = SoNgay + 1
    Next
MsgBox SoNgay
End Sub
Trường hợp này dùng Do Until... Loop có lẽ là hay hơn
PHP:
Sub Test()
Dim SoNgay As Long, i As Long
Do Until DateSerial(1900, i, 13) > Date
    i = i + 1
    If Weekday(DateSerial(1900, i, 13)) = 6 Then SoNgay = SoNgay + 1
Loop
MsgBox SoNgay
End Sub
 
Upvote 0
Thêm 1 vòng lặp nữa xem sao!
1 vòng lặp theo tháng, 1 vòng lặp theo năm . . . .
Đúng là cần gì phải lặp theo ngày, vì ngày có sẵn là 13 rồi. Em sửa code lại như sau:
Mã:
Sub tinhngay1()
Dim i, j As Date: Dim tong As Long
tong = 0
 For j = 1900 To 2010
   For i = 1 To 12
    If Weekday(DateSerial(j, i, 13)) = 6 Then tong = tong + 1
   Next i
  Next j
 MsgBox "So ngay la: " & tong
End Sub
Tuy nhiên cái hàm Weekday(DateSerial(j, i, 13)) Em không biết thay hàm nào khác cả?
 
Upvote 0
MinhCong đã viết:
Mã:
Sub tinhngay1()
Dim i, j As Date: Dim tong As Long

- Vì thay thuật toán, nên i, j không phải là Date nữa, mà là Long
- Sự thực là i chưa khai báo kiểu, chỉ mới khai báo kiểu cho j và tong.
- Tính dư cho tháng 9 đến tháng 12 của năm 2010.
- Dùng Weekday đâu có vấn đề gì đâu?
 
Upvote 0
- Vì thay thuật toán, nên i, j không phải là Date nữa, mà là Long
- Sự thực là i chưa khai báo kiểu, chỉ mới khai báo kiểu cho j và tong.
Anh giải thích giúp Em sao biến i chưa được khai báo với, vì Em nghĩ đặt i và j cách nhau dấu "," thì nó hiểu hết chứ nhỉ?
Mã:
Sub tinhngay()
Dim i As Integer
Dim j As Long: Dim tong As Long
tong = 0
 For j = 1900 To 2010
   For i = 1 To 12
    If Weekday(DateSerial(j, i, 13)) = 6 And DateSerial(j, i, 13) <= Date Then tong = tong + 1
   Next i
  Next j
 MsgBox "So ngay la: " & tong
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Anh Bill quy định thế mà, biết làm sao được.
Phải khai báo đầy đủ:

Dim i As Long, j As Long, tong As Long.

Thử như vầy sẽ biết: Dùng 1 dòng lệnh kiểm tra:

i = "GPE"

Nếu khai báo đủ như dòng trên, thì dòng lệnh này sẽ báo lỗi Type Mismatch. Điều này có lợi khi muốn loại giá trị không thích hợp.
Nếu khai báo thiếu, anh Bill thấy text cũng mặc kệ.
 
Lần chỉnh sửa cuối:
Upvote 0
Những ai đã từng xem qua bài viết này: Giới thiệu Cơ bản về vòng lặp For . . . next của sư phụ ptm0412 giờ hãy cùng làm 1 vài bài tập từ đơn giản đến nâng cao nhé
Xin mở màn bằng 1 bài tập sau:

Bài tập 01:

Hãy tính xem từ năm 1900 đến nay có bao nhiêu ngày thuộc dạng THỨ SÁU NGÀY 13
------------------------
Các bạn ai có bài tập gì hay xin post lên đây nhé! Cảm ơn
Theo tôi với vòng lặp thì bài này có thể finish được rồi, 1 vòng lặp hay 2 vòng lặp thì số lượng phép toán là như nhau, các bạn có thể tìm hiểu thêm phương pháp không dùng vòng lặp(đệ quy) xem sao.
Liên quan đến vòng lặp thì thường là các bài liên quan đến xử lý mảng, sắp xếp, ma trận, xử lý chuỗi ... Tôi xin góp vui 1 bài như sau
Bài tập 02:
Nhập vào 1 số N nguyên dương, in ra sheet hiện hành trên 1 vùng N cột, N dòng bắt đầu từ ô A1 với vùng đó chứa các số tự nhiên từ 1 đến N*N theo vòng xoáy ốc. Ví dụ N=5 ta sẽ phải in ra sheet hiện hành là
|A|B|C|D|E
1|1|2|3|4|5
2|16|17|18|19|6
3|15|24|25|20|7
4|14|23|22|21|8
5|13|12|11|10|9
 
Upvote 0
Theo tôi với vòng lặp thì bài này có thể finish được rồi, 1 vòng lặp hay 2 vòng lặp thì số lượng phép toán là như nhau, các bạn có thể tìm hiểu thêm phương pháp không dùng vòng lặp(đệ quy) xem sao.
Liên quan đến vòng lặp thì thường là các bài liên quan đến xử lý mảng, sắp xếp, ma trận, xử lý chuỗi ... Tôi xin góp vui 1 bài như sau
Bài tập 02:
Nhập vào 1 số N nguyên dương, in ra sheet hiện hành trên 1 vùng N cột, N dòng bắt đầu từ ô A1 với vùng đó chứa các số tự nhiên từ 1 đến N*N theo vòng xoáy ốc. Ví dụ N=5 ta sẽ phải in ra sheet hiện hành là
|A|B|C|D|E
1|1|2|3|4|5
2|16|17|18|19|6
3|15|24|25|20|7
4|14|23|22|21|8
5|13|12|11|10|9
Bạn ơi! Bài tập này rất hay nhưng tôi e rằng quá khó so với trình độ của những bạn mới vào nghề (cả tôi cũng chưa nghĩ ra hướng giải quyết nữa đây)
Vậy... cứ từ từ nha bạn!
Nếu sư phụ ptm0412 hoặc các bạn khác nghĩ ra được bài nào đó ở tầm trung trở xuống, xin vui lòng gữi lên đây nhé
(Bài của rollover79, ai nghĩ ra thì cứ đưa code lên, không nghĩ được cũng không sao ---> Chúng ta cùng tiếp tục để nâng cao tay nghề thôi)
 
Upvote 0
Bài tập 03:
Chuẩn hoá 1 chuỗi đầu vào theo nguyên tắc: Không tồn tại 2 ký tự liền kề giống nhau, các ký tự không liền kề vẫn có thể giống nhau. Ví dụ với chuỗi đầu vào là "AABBBBCCCCDDAAAAAA" thì chuỗi sau khi chuẩn hoá là "ABCDA"
 
Upvote 0
Xin đóng góp một câu trả lời với 2 vòng lặp theo cách tiếp cận vừa xử lý nén vừa duyệt qua chuỗi
PHP:
Private Function Normalize(Optional InputString As String = "") As String
    ' Normalize all
    'AABBBBCCCCDDAAAAAA
    Dim xStr As String, Tmp As String, i As Long
    ' Get first occurent
    If InputString = "" Then
        xStr = "AABBBBCCCCDDAAAAAA"
    Else
        xStr = InputString
    End If
    While i < Len(xStr)
        Tmp = Mid(xStr, i + 1, 1)
        While InStr(xStr, Tmp & Tmp) > 0
            xStr = Replace(xStr, Tmp & Tmp, Tmp)
        Wend
        i = i + 1
        Debug.Print xStr
    Wend
    Normalize = xStr
End Function
Cách tiếp theo có thể dùng đệ quy hoặc duyệt qua chuỗi. Nhìn chung bài này có nhiều cách giải quyết.
Cách giải trên đây vẫn chưa phải là tối ưu do vẫn có một số vòng lặp bị thửa (giả định như chuỗi không còn phần tử lặp thì nó vẫn cứ phải duyệt qua cả chuỗi).
 
Lần chỉnh sửa cuối:
Upvote 0
Bài tập 03:
Chuẩn hoá 1 chuỗi đầu vào theo nguyên tắc: Không tồn tại 2 ký tự liền kề giống nhau, các ký tự không liền kề vẫn có thể giống nhau. Ví dụ với chuỗi đầu vào là "AABBBBCCCCDDAAAAAA" thì chuỗi sau khi chuẩn hoá là "ABCDA"
Bạn cho hỏi: Có phân biệt HOA - thường không? Hay người dùng tự định nghĩa lấy?
 
Upvote 0
Bài tập 03:
Chuẩn hoá 1 chuỗi đầu vào theo nguyên tắc: Không tồn tại 2 ký tự liền kề giống nhau, các ký tự không liền kề vẫn có thể giống nhau. Ví dụ với chuỗi đầu vào là "AABBBBCCCCDDAAAAAA" thì chuỗi sau khi chuẩn hoá là "ABCDA"
Tôi cũng góp vui bằng cách sử dụng hàm Trim()
PHP:
Function ConverStr(Str As String) As String
    Dim C As String
    Str = Application.WorksheetFunction.Trim(vbBack & Str & vbBack)
    Str = Replace(Str, " ", vbBack)
    i = 2
    Do Until i = Len(Str)
        C = Mid(Str, i, 1)
        If C <> vbBack Then Str = Replace(Application.WorksheetFunction.Trim(Replace(Str, C, " ")), " ", C)
        i = i + 1
    Loop
    ConverStr = Replace(Mid(Str, 2, Len(Str) - 2), vbBack, " ")
End Function
Nếu không phân biệt chữ hoa, chữ thường thì thêm một dòng lệnh Convert cả chuỗi sang chữ hoa hoặc chữ thường.
 
Upvote 0
Nếu không phân biệt chữ hoa, chữ thường thì thêm một dòng lệnh Convert cả chuỗi sang chữ hoa hoặc chữ thường.
Không phân biệt chữ hoa chữ thường nhưng kết quả trả về vẫn có chữ hoa và chữ thường tùy thuộc vào ký tự đầu tiên bị trùng lặp mà ta xét, ví dụ "aAABbbCCCdDdAa" thì kết quả là "aBCdA". Với yêu cầu đó thì có lẽ không dùng phương pháp này được.
 
Upvote 0
Không phân biệt chữ hoa chữ thường nhưng kết quả trả về vẫn có chữ hoa và chữ thường tùy thuộc vào ký tự đầu tiên bị trùng lặp mà ta xét, ví dụ "aAABbbCCCdDdAa" thì kết quả là "aBCdA". Với yêu cầu đó thì có lẽ không dùng phương pháp này được.
Cứ For Next bình thường là được rồi
- Đặt 1 biến tạm
- Quét chuổi từ 1 đến Len(Chuổi)
- Nếu biến tạm <> ký tư thứ i thi
a> Lấy ký tự thứ i này ráp vào 1 chuổi tạm khác
b) Cho biến tạm = Ký tự thứ i
- Tiếp tục vòng lập
- Cuối cùng lấy kết quả chính là chuổi tạm khác
----------
Phân biệt HOA thường hay không, cùng lắm chỉ xét thêm UCase nữa là xong!
Các bạn làm trước theo hướng dễ: Có phân biệt HOA - thường rồi sau đó hẳn tính tiếp
 
Upvote 0
Bài giải bài tập 02

Bài tập 02:
Nhập vào 1 số N nguyên dương, in ra sheet hiện hành trên 1 vùng N cột, N dòng bắt đầu từ ô A1 với vùng đó chứa các số tự nhiên từ 1 đến N*N theo vòng xoáy ốc. Ví dụ N=5 ta sẽ phải in ra sheet hiện hành là
|A|B|C|D|E
1|1|2|3|4|5
2|16|17|18|19|6
3|15|24|25|20|7
4|14|23|22|21|8
5|13|12|11|10|9
Tôi có một phương án cho bài tập này. Mời mọi người tham khảo.
PHP:
Sub Test()
Application.ScreenUpdating = False
Dim Rng As Range, Way As Boolean, Number As Long
ActiveSheet.UsedRange.Clear
Number = InputBox("Please enter your number:")
[A1].Value = 1
Set Rng = [B1]
Way = True
For i = 2 To Number * Number
    Rng.Value = i
    If Way Then
        If Rng.Column = 1 Or Rng.Column = Number Then
            Way = False
            Set Rng = Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1))
        ElseIf Rng.Offset(, IIf(Rng.Row < (Number / 2 + 0.5), 1, -1)).Value <> "" Then
            Way = False
            Set Rng = Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1))
        Else
            Set Rng = Rng.Offset(, IIf(Rng.Row > (Number / 2 + 0.5), -1, 1))
        End If
    Else
        If Rng.Row = 1 Or Rng.Row = Number Then
            Way = True
            Set Rng = Rng.Offset(, IIf(Rng.Row > (Number / 2 + 0.5), -1, 1))
        ElseIf Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1)).Value <> "" Then
            Way = True
            Set Rng = Rng.Offset(, IIf(Rng.Row > (Number / 2 + 0.5), -1, 1))
        Else
            Set Rng = Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1))
        End If
    End If
Next
Application.ScreenUpdating = True
End Sub
 
Upvote 0
Bài tập 03:
Chuẩn hoá 1 chuỗi đầu vào theo nguyên tắc: Không tồn tại 2 ký tự liền kề giống nhau, các ký tự không liền kề vẫn có thể giống nhau. Ví dụ với chuỗi đầu vào là "AABBBBCCCCDDAAAAAA" thì chuỗi sau khi chuẩn hoá là "ABCDA"
Xin góp một cách:
Mã:
Public Function cat(Vung As Range) As String
    Dim i As Integer, Tam As String, j As String
    'Vung = UCase(Vung)'
        For i = 2 To Len(Vung)
            j = Mid(Vung, i, 1)
            If Mid(Vung, i - 1, 1) = j Then j = ""
            Tam = Tam & j
        Next
  cat = Left(Vung, 1) & Tam
End Function
 
Upvote 0
Theo tôi với vòng lặp thì bài này có thể finish được rồi, 1 vòng lặp hay 2 vòng lặp thì số lượng phép toán là như nhau, các bạn có thể tìm hiểu thêm phương pháp không dùng vòng lặp(đệ quy) xem sao.
Liên quan đến vòng lặp thì thường là các bài liên quan đến xử lý mảng, sắp xếp, ma trận, xử lý chuỗi ... Tôi xin góp vui 1 bài như sau
Bài tập 02:
Nhập vào 1 số N nguyên dương, in ra sheet hiện hành trên 1 vùng N cột, N dòng bắt đầu từ ô A1 với vùng đó chứa các số tự nhiên từ 1 đến N*N theo vòng xoáy ốc. Ví dụ N=5 ta sẽ phải in ra sheet hiện hành là
|A|B|C|D|E
1|1|2|3|4|5
2|16|17|18|19|6
3|15|24|25|20|7
4|14|23|22|21|8
5|13|12|11|10|9
Về bài toán này, tôi nghĩ các bạn có thể tham khảo topic này:
http://www.giaiphapexcel.com/forum/showthread.php?34009-Lập-trình-để-tỏ-tình-bằng-excel/page2
Tìm code kẽ khung (Sub Enframe) và sửa lại đôi chút là được
 
Upvote 0
Bài tập 02:

Với các bạn mới học, hãy xé nhỏ ra từng đoạn:
Đoạn 1: fill ngang lần 1 (gặp cột thứ n thì ngừng)
Đoạn 2: fill xuống lần 1 (gặp dòng thứ n thì ngừng)
Đoạn 3: fill qua trái lần 1 (gặp cột 1 thì ngừng)
Đoạn 4: các số còn lại. Các số này có tính chất giống nhau là gặp ô có số thì đổi hướng.

Do dùng để hướng dẫn các bạn mới, nên không dùng mảng, không dùng thuật toán cao siêu, đơn giản select rồi gán số. Tô màu gì đó cho mỗi ô tạo chút hiệu ứng chạy.

Đoạn 1:

PHP:
For i = 1 To Num
    With Cells(1, i)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
    End With
Next

Quá dễ, đúng không?

Đoạn 2:


PHP:
For i = Num + 1 To Num * 2 - 1
    With Cells(i - Num + 1, Num)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
    End With
Next

Cũng còn dễ, chỉ cần suy luận 1 tí ti là chỉ có n - 1 số, từ n +1 đến 2n -1, số dòng dùng 1 phép cộng trừ đơn giản, cột là n.

Đoạn 3: suy luận tương tự, chỉ có n - 1 số, từ 2n đến 3n-2, dòng là n, cột thì cộng trừ tí ti.

PHP:
For i = Num * 2 To Num * 3 - 2
    With Cells(Num, Num * 3 - i - 1)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
    End With
Next

Đoạn 4:

Bắt đầu khó khăn. Trước khi select ô kế, phải dò trước xem ô đó có số chưa, nếu chưa thì chạy tới, nếu rồi thì đổi hướng.

PHP:
For i = Num * 3 - 1 To Num ^ 2

Hướng bắt đầu là hướng chạy lên, ô kế là Selection.Offset(-1, 0). Đặt 2 biến j và k và gán j = -1, k = 0
Điều kiện để đổi hướng chạy ngang qua phải:
PHP:
With Selection
        If .Offset(j, k).Value > 0 And j = -1 Then j = 0: k = 1
Tiếp theo là chạy ngang qua phải, ô kế là Selection.Offset(0, 1). Điều kiện đổi hướng chạy xuống:
PHP:
If .Offset(j, k).Value > 0 And j = 0 Then j = 1: k = 0
Tương tự điều kiện đổi hướng chạy ngang qua trái:
PHP:
 If .Offset(j, k).Value > 0 And j = 1 Then j = 0: k = -1
Cuối cùng là điều kiện đổi hướng chạy lên:
PHP:
If .Offset(j, k).Value > 0 And j = 0 Then j = -1: k = 0
    End With

Bắt đầu select và gán số:

PHP:
    With Selection.Offset(j, k)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
        .Interior.ColorIndex = 4
    End With
Next

Ráp lại, thêm 1 miếng Delay cho chạy từ từ thôi:

PHP:
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
PHP:
Sub quay1(ByVal Num As Long, Delay As Long)
Dim i As Long, j As Long, k As Long
ActiveSheet.Cells.Clear
For i = 1 To Num
    With Cells(1, i)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
    End With
    Sleep Delay
Next

For i = Num + 1 To Num * 2 - 1
    With Cells(i - Num + 1, Num)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
    End With
    Sleep Delay
Next

For i = Num * 2 To Num * 3 - 2
    With Cells(Num, Num * 3 - i - 1)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
    End With
    Sleep Delay
Next
   
j = -1: k = 0
For i = Num * 3 - 1 To Num ^ 2
    With Selection
        If .Offset(j, k).Value > 0 And j = -1 Then j = 0: k = 1
        If .Offset(j, k).Value > 0 And j = 0 Then j = 1: k = 0
        If .Offset(j, k).Value > 0 And j = 1 Then j = 0: k = -1
        If .Offset(j, k).Value > 0 And j = 0 Then j = -1: k = 0
    End With
    With Selection.Offset(j, k)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
        .Interior.ColorIndex = 4
    End With
    Sleep Delay
Next

End Sub

Dùng 1 Command button để lấy số tuỳ ý và chạy code:

PHP:
Private Sub Cmb1_Click()
Num = InputBox("So may?")
On Error GoTo exit1
quay1 Num, 20
exit1:
Exit Sub
End Sub
 
Upvote 0
Bài tập 02
Nâng cao 1 tí chút:

Vẫn dùng select tới đâu, gán số tới đó. nhưng không chia đoạn nữa, như vậy điều kiện chuyển hướng nhiều hơn: Không phải chỉ thấy số thì đổi hướng, mà 3 đoạn đầu bài trên, cần điều kiện khác. Cộng là 7 điều kiện:

PHP:
Sub quay2(ByVal Num As Long, Delay As Long)
Dim i As Long, j As Long, k As Long
ActiveSheet.Cells.Clear
    With ActiveSheet.[a1]
        .Select
        .Value = 1
        .Interior.ColorIndex = 4
    End With
 
j = 0: k = 1
For i = 2 To Num ^ 2
    With Selection
        If .Column = Num And j = 0 And k = 1 Then j = 1: k = 0
        If .Row = Num And j = 1 And k = 0 Then j = 0: k = -1
        If .Column = 1 And j = 0 And k = -1 Then j = -1: k = 0
        If .Offset(j, k).Value > 0 And j = 0 And k = 1 Then j = 1: k = 0
        If .Offset(j, k).Value > 0 And j = 1 And k = 0 Then j = 0: k = -1
        If .Offset(j, k).Value > 0 And j = 0 And k = -1 Then j = -1: k = 0
        If .Offset(j, k).Value > 0 And j = -1 And k = 0 Then j = 0: k = 1
    End With

    With Selection.Offset(j, k)
        .Select
        .Value = i
        .Interior.ColorIndex = 4
    End With

    Sleep Delay
Next

End Sub

Và vì thuật toán là dò ô kế, đạt điều kiện là nhảy qua rồi gán số, nên sót ô đầu tiên chưa có số, phải gán ngay từ đầu code.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Xin cảm ơn tất cả các bạn đã tham gia ToPic này !
Tôi đang thử sức với các bài tập trên nhưng chỉ hiểu và làm được khoảng 30%. Là người thành tâm muốn theo học, tôi xin có một số ý kiến như sau:
Với chủ đề của Topic này là bài tập về vòng lặp và tập đi từ dễ đến khó thì:
1- Chỉ giải quyết bài tập bằng vòng lặp (các kiểu vòng lặp), nhằm tập trung cho mục tiêu không bàn đến các giải pháp không dùng vòng lặp.
2- Bài tập càng đơn giản càng tốt (vì mọi cái chưa biết đều là khó). Không nên đưa ra quá nhiều bài tập theo tôi mỗi tuần khoảng 2 đến 3 bài là vừa. Giai đoạn đầu (giai đoạn dễ) nên kéo dài ít nhất 4 tuần để người học còn có thời gian nghiên cứu, đúc rút kinh nghiệm và tự thực hành.
3- Nên có hướng dẫn chi tiết từng bước cho người học ví dụ như bài #26 của ptm0412.
4- Các bạn tham hướng dẫn giải bài tập, trong giai đoạn đầu cần chú ý viết sao cho bình dân (dễ hiểu nhất) các vấn đề về vòng lặp, chưa vội bàn đến giải pháp ngắn hay dài, tối ưu hay chưa tối ưu (vì là bài tập nên hiệu ích của bài viết chính là số lượng người hiểu bài).

Đúng là "được voi lại đòi cả người cưỡi voi" nhưng với những người như tôi nếu không được cả hai thì mọi cố gắng của các bạn đều như nước đổ lá khoai mà thôi.

Nếu có gì không phải mong các bạn bỏ qua và đề nghị Mod xóa giúp bài này nếu xét thấy là không cần thiết.
Thanks !
 
Lần chỉnh sửa cuối:
Upvote 0
2- Bài tập càng đơn giản càng tốt (vì mọi cái chưa biết đều là khó). Không nên đưa ra quá nhiều bài tập theo tôi mỗi tuần khoảng 2 đến 3 bài là vừa. Giai đoạn đầu (giai đoạn dễ) nên kéo dài ít nhất 4 tuần để người học còn có thời gian nghiên cứu, đúc rút kinh nghiệm và tự thực hành.
Đồng ý với anh Trung Chinh!
Vậy xin mời các bạn làm lại bài 1bài 3, theo tôi 2 bài này cũng khá đơn giản!
Lưu ý: Khi làm xong code, nếu có thể được, các bạn hãy đính kèm luôn file nhé (cho tiện việc kiểm tra)
(xin đừng vì ngại người ta cười code của mình mà không tham gia nhé)
 
Upvote 0
Bài 3 giải theo concogia có lẽ là ổn rồi, xin góp bài tập kế:
Bài tập 04
Căn cứ vào câu lệnh tô màu và sleep trong bài 26, thử 3 câu như sau:

Chọn 1 vùng chữ nhật trong sheet, dài rộng không bằng nhau:
a. Tô màu từng ô, từng dòng từ trái qua phải, từ trên xuống dưới.
b. Tô màu từng dòng từ trái qua phải, rồi dòng kế ngược lại từ phải qua trái đến hết.
c. Tô màu caro kiểu bi da: Tô màu từng ô theo đường chéo 45 độ, gặp đường biên thì dội ra 45 độ hướng khác. Kết quả được 1 hình tô carô.

caro.jpg
 
Lần chỉnh sửa cuối:
Upvote 0
1- Chỉ giải quyết bài tập bằng vòng lặp (các kiểu vòng lặp), nhằm tập trung cho mục tiêu không bàn đến các giải pháp không dùng vòng lặp.
Tôi nghĩ nếu ai có giải pháp hay thì cứ post lên cho mọi người tham khảo kiểu như một cách giải khác thôi. Vì với một bài toán thì cách giải không dùng vòng lặp thường hay hơn cách giải dùng vòng lặp. Theo tôi đã học thì cái gì hay thì học, nhất là những bài giải mang tính sáng tạo.
 
Upvote 0
Tôi nghĩ nếu ai có giải pháp hay thì cứ post lên cho mọi người tham khảo kiểu như một cách giải khác thôi. Vì với một bài toán thì cách giải không dùng vòng lặp thường hay hơn cách giải dùng vòng lặp. Theo tôi đã học thì cái gì hay thì học, nhất là những bài giải mang tính sáng tạo.
Bạn ơi! Đây là topic BÀI HỌC chứ không phải TÌM GIẢI PHÁP hay!
Đã gọi là HỌC thì mục đích làm sao cho mọi người HIỂU được mới xem là thành công!
Giống như bài toán của sư phụ pmt0412 đưa ra đấy thôi: Dùng vòng lập để tính giai thừa ---> Ai chả biết bài nào khỏi vòng lập cũng làm được! Vấn đề là THÔNG QUA BÀI TẬP ĐỂ HIỂU VÒNG LẬP bạn à!
Ý kiến của bạn cũng tốt, nhưng e rằng ta phải tìm hiểu trong 1 topic khác thôi!
 
Upvote 0
Tôi xin bàn 1 chút về Bài tập 02, bài này mới đọc lên thì thấy rất khó, nhưng nếu hiểu rõ 1 chút về ma trận vuông thì bài này cũng không hẳn khó. Với 1 ma trận vuông cấp N sẽ có N dòng và N cột, giả sử các dòng và cột được đánh số từ 1 -> N, ta kẻ 2 đường chéo cho ma trận thì sẽ chia ma trận thành 4 vùng tương ứng là Trên, Dưới, Trái, Phải, tương ứng với mỗi vùng ta sẽ thấy, tại vùng Trên khi điền số theo thứ tự thì Cột tăng, tương tự vùng Dưới Cột giảm, vùng Phải Dòng tăng, vùng Trái Dòng giảm.Giờ ta xét 1 vài tính chất của ma trận này.
1. Đường chéo 1(màu tím): Tập hợp của các ô có Dòng=Cột
2. Đường chéo 2(màu xanh): Tập hợ của các ô có Dòng+Cột=N+1
3. Vùng nằm phía trên đường chéo 1: Tập hợp các ô có Cột > Dòng
4. Vùng nằm phía dưới đường chéo 1: Tập hợp các ô có Cột < Dòng
5. Vùng nằm phía trên đường chéo 2: Tập hợp các ô có Dòng+Cột < N+1
6. Vùng nằm phía dưới đường chéo 2: Tập hợp các ô có Dòng+Cột >N+1
Tập hợp các dữ kiện trên sẽ đưa ra được quy luật tương đối đơn giản, các bạn tham khảo đoạn code dưới đây nhé:
Mã:
Sub MaTran()
    Dim n As Long
    n = InputBox("Nhap cap ma tran: ")
    
    Dim iRow As Long
    Dim iCol As Long
    Dim iValue As Long
    Dim arr() As Long
    ReDim arr(1 To n, 1 To n)
    iCol = 1: iRow = 1
    For iValue = 1 To n ^ 2
        arr(iRow, iCol) = iValue
        If (iCol >= iRow And iCol + iRow < n + 1) Or (iCol = iRow - 1 And iCol + iRow <= n + 1) Then
            iCol = iCol + 1
        ElseIf iCol > iRow And iCol + iRow >= n + 1 Then
            iRow = iRow + 1
        ElseIf iCol <= iRow And iCol + iRow > n + 1 Then
            iCol = iCol - 1
        ElseIf iCol < iRow - 1 And iCol + iRow <= n + 1 Then
            iRow = iRow - 1
        End If
    Next
    Range(Cells(1, 1), Cells(n, n)) = arr
End Sub
attachment.php
 

File đính kèm

  • MaTran.GIF
    MaTran.GIF
    3.9 KB · Đọc: 208
Upvote 0
Bài 3 giải theo concogia có lẽ là ổn rồi, xin góp bài tập kế:
Bài tập 04
Căn cứ vào câu lệnh tô màu và sleep trong bài 26, thử 3 câu như sau:

Chọn 1 vùng chữ nhật trong sheet, dài rộng không bằng nhau:
a. Tô màu từng ô, từng dòng từ trái qua phải, từ trên xuống dưới.
b. Tô màu từng dòng từ trái qua phải, rồi dòng kế ngược lại từ phải qua trái đến hết.
c. Tô màu caro kiểu bi da: Tô màu từng ô theo đường chéo 45 độ, gặp đường biên thì dội ra 45 độ hướng khác. Kết quả được 1 hình tô carô.

View attachment 50774
Lưu ý câu c: Không phải hình chữ nhật nào cũng có đáp án. Ví dụ một hình chữ nhật có dạng d-1=n(r-1) (với d là chiều dài, r là chiều rộng) chẳng hạn như: 5x9, 5x13, 6x11,... Khi test code các bạn nên bẫy lỗi cẩn thận để tránh rơi vào vòng lặp vô tận.
untitled.GIF
 
Lần chỉnh sửa cuối:
Upvote 0
Lưu ý câu c: Không phải hình chữ nhật nào cũng có đáp án. Ví dụ một hình chữ nhật có dạng d-1=n(r-1) (với d là chiều dài, r là chiều rộng) chẳng hạn như: 5x9, 5x13, 6x11,... Khi test code các bạn nên bẫy lỗi cẩn thận để tránh rơi vào vòng lặp vô tận.
Câu c thấy hao hao giống bài này ghê:
http://www.giaiphapexcel.com/forum/showthread.php?18834-Hãy-xem-sự-di-chuyển-của-trái-Bi-a-trên-bàn!
 
Upvote 0
Tôi cũng Spam tí
3/ Toàn là cao thủ như RollOver, Ndu,HuuThang, và cả PTM nữa trả lời thì còn cửa nào cho anh anh em học hỏi.
.
Tôi chưa đưa lên topic này bất cứ code nào à nha!
Nên chăng có những BT thực tế hơn, ví dụ như là, tính những ngày nghĩ từ nay đến -> 31/12/2012 bao gồm những ngày nghỉ bù, (nếu ngày lễ là CN, áp dụng cho tuần là 48h) chưa kể mấy ngày lễ tết. Tính trước để mình còn dự trù những ngày ăn chơi.
Giả sử ngày nghỉ là: 30/04, 01/05, 02/09, 01/01. Chưa kể mấy ngày nghỉ tết và 10/3 AL.
Nhờ BQT xóa bài hộ.
Ái chà! Bài này cũng đâu có dễ ăn! Nhất là đối với bạn mới học
Thà là vầy đi: Tính từ đầu năm đến cuối năm tôi đã đi làm được bao nhiều ngày (nghỉ CN và lễ, không tính nghỉ đột xuất)
Dễ hơn rất nhiều
Ẹc... Ẹc...
 
Upvote 0
Thà là vầy đi: Tính từ đầu năm đến cuối năm tôi đã đi làm được bao nhiều ngày (nghỉ CN và lễ, không tính nghỉ đột xuất)
Dễ hơn rất nhiều
Ẹc... Ẹc...
Vậy cứ thống nhất vậy nhé.
Từ 19/08/2010 - 31/12/2010 mình sẽ làm việc bao nhiêu ngày. Ngày lễ gồm có: 2/9 và ngày nghỉ là CN. Và liệt kê những ngày thứ hai gán vào A1->An của 1 sheet. Dòng vòng lặp thông thường.
 
Upvote 0
Bài 3 giải theo concogia có lẽ là ổn rồi, xin góp bài tập kế:
Bài tập 04
Căn cứ vào câu lệnh tô màu và sleep trong bài 26, thử 3 câu như sau:

Chọn 1 vùng chữ nhật trong sheet, dài rộng không bằng nhau:
a. Tô màu từng ô, từng dòng từ trái qua phải, từ trên xuống dưới.
b. Tô màu từng dòng từ trái qua phải, rồi dòng kế ngược lại từ phải qua trái đến hết.
c. Tô màu caro kiểu bi da: Tô màu từng ô theo đường chéo 45 độ, gặp đường biên thì dội ra 45 độ hướng khác. Kết quả được 1 hình tô carô.

View attachment 50774
Em xin làm câu a và b trước.
Mã:
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
Câu a:
Mã:
Sub tomau1()
Dim i As Long, j As Long
  For i = 1 To 5
     For j = 1 To 7
        Cells(i, j).Interior.ColorIndex = 4
        Sleep 100
     Next j
  Next i
End Sub
Câu b:
Mã:
Sub tomau2()
Dim i As Long, j As Long
 For i = 9 To 14
   If i Mod 2 <> 0 Then
      For j = 1 To 7
        Cells(i, j).Interior.ColorIndex = 4
        Sleep 100
      Next j
   ElseIf i Mod 2 = 0 Then
      For j = 7 To 1 Step -1
      Cells(i, j).Interior.ColorIndex = 3
        Sleep 100
      Next j
   End If
 Next i
End Sub
 

File đính kèm

Upvote 0
Cái câu a) này sao bạn không dùng code theo kiểu
For Each Clls in Selection
Sẽ gọn hơn... mặc khác, chọn vùng nào ta "làm" vùng nấy!
Cảm ơn anh đã gợi ý. Em làm lại câu a theo For each...next như sau.
Mã:
Sub tomau3()
Dim clls As Range
  For Each clls In Selection
     clls.Interior.ColorIndex = 4
     Sleep 50
  Next
End Sub
 
Upvote 0
Em xin làm câu a và b trước.

Câu b:
Mã:
Sub tomau2()
Dim i As Long, j As Long
 For i = 9 To 14
   If i Mod 2 <> 0 Then
      For j = 1 To 7
        Cells(i, j).Interior.ColorIndex = 4
        Sleep 100
      Next j
   ElseIf i Mod 2 = 0 Then
      For j = 7 To 1 Step -1
      Cells(i, j).Interior.ColorIndex = 3
        Sleep 100
      Next j
   End If
 Next i
End Sub
Với câu b) tôi xin gợi ý thế này
- Dùng 2 vòng lập, 1 cái quét theo dòng và 1 cái quét theo cột... Đại khái thế này:
PHP:
Dim SrcRng as Range, iR as Long, iC as Long
Set SrcRng = Selection
For iR = 1 To SrcRng.Rows.Count
    For iC = 1 to SrcRng.Columns.Count Step 1
Trong code này, phần quét theo cột đang theo chiều thuận (từ trái sang phải)... Nếu muốn theo chiều ngược lại thì
PHP:
Dim SrcRng as Range, iR as Long, iC as Long
Set SrcRng = Selection
For iR = 1 To SrcRng.Rows.Count
    For SrcRng.Columns.Count to 1 Step -1
- Để ý thấy 2 code trên chỉ khác nhau 1 tí (đảo 1 SrcRng.Columns.Count với nhau và khác Step)
- Sự thay đổi này hoàn toàn tùy thuộc và vị trí của dòng (iR)
- Vậy ta có thể đặt thêm vài biến nữa để nhận biết được sự thay đổi này
PHP:
  Dim iR As Long, iC As Long, SrcRng As Range, Chk As Boolean, Col As Long, Stp As Long, Color As Long
  Set SrcRng = Selection
  Col = SrcRng.Columns.Count
  For iR = 1 To SrcRng.Rows.Count
    Chk = iR Mod 2
    Stp = IIf(Chk, 1, -1)
    Color = IIf(Chk, 4, 3)
    For iC = IIf(Chk, 1, Col) To IIf(Chk, Col, 1) Step Stp
      With SrcRng.Cells(iR, iC)
        .Select
        .Interior.ColorIndex = Color
      End With
      Sleep 100
    Next
  Next
Việc thể hiện code là tùy theo ý của mỗi người, miễn sao dễ nhìn là được!
Sau này, nếu trình độ khá hơn 1 chút, bạn có thể viết code theo kiểu có tham số truyền như thế này
PHP:
Private Sub RangeColor(SrcRng As Range, Color1 As Long, Color2 As Long, Delay As Long)
  Dim iR As Long, iC As Long, Chk As Boolean, Col As Long, Stp As Long
  Col = SrcRng.Columns.Count
  For iR = 1 To SrcRng.Rows.Count
    Chk = iR Mod 2
    Stp = IIf(Chk, 1, -1)
    For iC = IIf(Chk, 1, Col) To IIf(Chk, Col, 1) Step Stp
      With SrcRng.Cells(iR, iC)
        .Select
        .Interior.ColorIndex = IIf(Chk, Color1, Color2)
      End With
      Sleep Delay
    Next
  Next
End Sub
Rồi khi cần chạy ứng dụng, ta viết 1 đoạn khác ngắn gọn hơn:
PHP:
Sub Test()
  RangeColor Selection, 3, 4, 100
End Sub
Một vài gợi ý nhỏ, hy vọng có thể giúp ích cho các bạn
 
Upvote 0
Câu b Em làm theo cách hướng dẫn của Anh và cách hiểu của mình thay cho cách chọn số dòng số cột ở trước.
Mã:
    [COLOR=#0000bb]Private Declare Sub Sleep Lib "[/COLOR][COLOR=red]kernel32[/COLOR][COLOR=#0000bb]" (ByVal ms As Long)[/COLOR]
  [COLOR=#0000bb]Sub Test()[/COLOR]
  [COLOR=#0000bb]Dim iR As Long, iC As Long, SrcRng As Range[/COLOR]
  [COLOR=#0000bb]Set SrcRng = Selection[/COLOR]
  [COLOR=#0000bb] For iR = 1 To SrcRng.Rows.Count[/COLOR]
  [COLOR=#0000bb]     If iR Mod 2 <> 0 Then[/COLOR]
  [COLOR=#0000bb]        For iC = 1 To SrcRng.Columns.Count[/COLOR]
  [COLOR=#0000bb]           SrcRng.Cells(iR, iC).Interior.ColorIndex = 4[/COLOR]
  [COLOR=#0000bb]           Sleep 50[/COLOR]
  [COLOR=#0000bb]        Next[/COLOR]
  [COLOR=#0000bb]     ElseIf iR Mod 2 = 0 Then[/COLOR]
  [COLOR=#0000bb]        For iC = SrcRng.Columns.Count To 1 Step -1[/COLOR]
  [COLOR=#0000bb]           SrcRng.Cells(iR, iC).Interior.ColorIndex = 3[/COLOR]
  [COLOR=#0000bb]           Sleep 50[/COLOR]
  [COLOR=#0000bb]        Next[/COLOR]
  [COLOR=#0000bb]     End If[/COLOR]
  [COLOR=#0000bb]  Next[/COLOR]
  [COLOR=#0000bb]End Sub[/COLOR]
Câu c khó quá Anh hướng dẫn sơ sơ đi.
 
Lần chỉnh sửa cuối:
Upvote 0
Câu b Em làm theo cách hướng dẫn của Anh và cách hiểu của mình thay cho cách chọn số dòng số cột ở trước.
Mã:
    [COLOR=#0000bb]Private Declare Sub Sleep Lib "[/COLOR][COLOR=red]kernel32[/COLOR][COLOR=#0000bb]" (ByVal ms As Long)[/COLOR]
  [COLOR=#0000bb]Sub Test()[/COLOR]
  [COLOR=#0000bb]Dim iR As Long, iC As Long, SrcRng As Range[/COLOR]
  [COLOR=#0000bb]Set SrcRng = Selection[/COLOR]
  [COLOR=#0000bb] For iR = 1 To SrcRng.Rows.Count[/COLOR]
  [COLOR=#0000bb]     If iR Mod 2 <> 0 Then[/COLOR]
  [COLOR=#0000bb]        For iC = 1 To SrcRng.Columns.Count[/COLOR]
  [COLOR=#0000bb]           SrcRng.Cells(iR, iC).Interior.ColorIndex = 4[/COLOR]
  [COLOR=#0000bb]           Sleep 50[/COLOR]
  [COLOR=#0000bb]        Next[/COLOR]
  [COLOR=#0000bb]     ElseIf iR Mod 2 = 0 Then[/COLOR]
  [COLOR=#0000bb]        For iC = SrcRng.Columns.Count To 1 Step -1[/COLOR]
  [COLOR=#0000bb]           SrcRng.Cells(iR, iC).Interior.ColorIndex = 3[/COLOR]
  [COLOR=#0000bb]           Sleep 50[/COLOR]
  [COLOR=#0000bb]        Next[/COLOR]
  [COLOR=#0000bb]     End If[/COLOR]
  [COLOR=#0000bb]  Next[/COLOR]
  [COLOR=#0000bb]End Sub[/COLOR]
Câu c khó quá Anh hướng dẫn sơ sơ đi.
Câu b) này dù đã sửa lại nhưng đếm trong code sẽ thấy có 3 vòng lập ---> Vì thế mà tôi mới hướng dẩn bạn rút gọn lại chỉ còn 2 vòng lập thôi
Thử để ý xem code này:
PHP:
For iC = 1 To SrcRng.Columns.Count
   SrcRng.Cells(iR, iC).Interior.ColorIndex = 4
   Sleep 50
Next
Và đoạn này:
PHP:
For iC = SrcRng.Columns.Count To 1 Step -1
  SrcRng.Cells(iR, iC).Interior.ColorIndex = 3
  Sleep 50
Next
Có khác nhau gì mấy đâu ---> Sao không gộp làm 1?
-----------------------------------------------------------
Câu c) khó quá thì... cứ từ từ... Xem bài Trái Bi-a này cũng giống đấy!
 
Lần chỉnh sửa cuối:
Upvote 0
Vậy cứ thống nhất vậy nhé.
Từ 19/08/2010 - 31/12/2010 mình sẽ làm việc bao nhiêu ngày. Ngày lễ gồm có: 2/9 và ngày nghỉ là CN. Và liệt kê những ngày thứ hai gán vào A1->An của 1 sheet. Dòng vòng lặp thông thường.
Các anh xem góp ý cho Em nhé!
Mã:
Sub lamviec()
Dim i As Integer, j As Integer, k As Integer, dk As Boolean
  Dim ngayle As Integer, ngaynghi As Integer, ngaylam As Long
  ngayle = 1: ngaynghi = 0
   For i = 8 To 12
       dk = i Mod 8
       k = IIf(dk, 1, 19)
       For j = k To 31
           With [COLOR=Red]ActiveCell[/COLOR]
               If Weekday(DateSerial(2010, i, j)) = 1 Then
                  ngaynghi = ngaynghi + 1
                  .Value = DateSerial(2010, i, j)
                  .Offset(1, 0).Select
               End If
           End With
       Next j
   Next i
       ngaylam = DateSerial(2010, 12, 31) - DateSerial(2010, 8, 19) - ngayle - ngaynghi
       MsgBox "Tong ngay lam viec la: " & ngaylam
End Sub
Điều kiện đưa vào bắt đầu cells(1,1) Em chưa biết, nên dùng Activecell thì nó mới chạy, mong các Anh giúp.
 

File đính kèm

Upvote 0
Bài 4 câu b có thể giải bằng 1 vòng lặp duy nhất:

Bằng cách dùng cells(i , j) với gia số dòng K và gia số cột L với điều kiện:

Nếu j = tổng số cột hoặc j=1, i tăng lên 1, ta cho gia số dòng k = 0 sau đó tăng k = k + 1

khi tô màu từ trái qua phải, j tăng 1 đến khi bằng tổng số cột thì ngưng, xuống dòng.
khi tô từ phải qua trái, j giảm 1 đến khi bằng 1 thì ngưng, xuống dòng.
Vậy ta cho gia số cột L = 1 và khi thoả điều kiện, L = - L (đổi dấu)

Vòng lặp chạy từ 1 đến tích số dòng và cột. Lưu ý rằng j có những mốc không tăng, không giảm, đó là khi vừa xuống dòng.

Để tô 2 màu xen kẽ, ta đặt điều kiện cho gia số k, nếu k Mod 2 = 0 thì tô màu này, ngược lại thì tô màu kia.

PHP:
Sub tomau2()
Dim i As Long, j As Long, k As Long, L As Long, t As Long
Dim CRows As Long, CCols As Long
    Cells.Clear
    k = 0: L = 1
    i = 1: j = 0: t = 0
    On Error GoTo exit1
    CRows = InputBox("So dong?")
    CCols = InputBox("So cot?")
    For t = 1 To CRows * CCols
        Cells(i + k, j + L).Interior.ColorIndex = IIf(k Mod 2 = 0, 28, 3)
        j = j + L
        If t Mod CCols = 0 And t < CRows * CCols Then
            k = k + 1
            Cells(i + k, j).Interior.ColorIndex = IIf(k Mod 2 = 0, 28, 3)
            t = t + 1
            L = -L
        End If

        Sleep 20
    Next
exit1:
    Exit Sub
End Sub

Hai vòng lặp không phải là dở, nhưng bằng biện pháp dùng gia số dòng cột này, hãy nghĩ đến câu c.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Bài tập 04 này thực chất là loạt bài thao tác với ma trận tương tự như sau
a)Nhập vào dòng, cột in ra ma trậ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
b)Nhập vào dòng, cột, in ra ma trận:
1|2|3|4
8|7|6|5
9|10|11|12
16|15|14|13
17|18|19|20
24|23|22|21
Nếu hiểu rõ về ma trận thì cả 2 câu này không khó, chỉ cần duy nhất 1 vòng lặp từ 1 đến Dòng*Cột là xong. Tôi gợi ý 1 chút như sau, với cả 2 câu đều thực hiện giống nhau, với mỗi bước của vòng lặp, xác định biến Dòng và Cột từ biến chạy, xử lý cho cell tương ứng với Dòng và Cột vừa tính được.
 
Upvote 0
Theo gợi ý của RollOver (chuyên gia mảng), câu a làm lại như sau: (thủ thuật tương tự bài ma phương)

PHP:
Sub tomau1()
Dim i As Long, j As Long
Dim CRows As Long, CCols As Long
    Cells.Clear

    CRows = InputBox("So dong?")
    CCols = InputBox("So cot?")
    For t = 1 To CRows * CCols
        i = Int((t - 1) / CCols) + 1
        j = IIf(t Mod CCols = 0, CCols, t Mod CCols)
        Cells(i, j).Interior.ColorIndex = IIf(i Mod 2 = 0, 3, 4)
        Sleep 50
   Next
End Sub

Đây là thủ thuật biến mảng 1 chiều thành mảng 2 chiều. Nếu là gán số xuống vùng vừa tô thì như sau:
Thêm câu lệnh gọi vào sub tomau1:
PHP:
Ganso CRows, CCols

PHP:
Sub Ganso(CRows As Long, CCols As Long)
Dim Arr()
ReDim Arr(1 To CRows, 1 To CCols)
    For t = 1 To CRows * CCols
        i = Int((t - 1) / CCols) + 1
        j = IIf(t Mod CCols = 0, CCols, t Mod CCols)
        Arr(i, j) = t
    Next
    Range(Cells(1, 1), Cells(CRows, CCols)) = Arr
End Sub
 
Upvote 0
Ghi chú:

câu c bài 04, để tránh trường hợp tô hoài không hết như huuthang_bd cảnh báo, xin giới hạn đề bài thành 1 hình chữ nhật cụ thể 15 dòng, 24 cột cho các bạn mới học dễ làm.
 
Upvote 0
Ghi chú:

câu c bài 04, để tránh trường hợp tô hoài không hết như huuthang_bd cảnh báo, xin giới hạn đề bài thành 1 hình chữ nhật cụ thể 15 dòng, 24 cột cho các bạn mới học dễ làm.
Không cần đâu sư phụ à! Chỉ cần trong quá trình tô màu mà có lập lại ít nhất 1 cell đã tô thì ... THOÁT ---> Đơn giản mà!
Tóm lại: Vùng cần tô màu = Selection (với Selection là 1 vùng liên tục)
 
Upvote 0
Không cần đâu sư phụ à! Chỉ cần trong quá trình tô màu mà có lập lại ít nhất 1 cell đã tô thì ... THOÁT ---> Đơn giản mà!

Không đâu ndu à, khi trái bi da lăn, ai cấm nó lăn cắt ngang đường cũ chứ? Mà không cho nó lăn cắt ngang (vừa đụng vào đướng cũ là thoát) làm sao nó chạy qua hết tất cả các ô cần thiết?
 
Upvote 0
Không đâu ndu à, khi trái bi da lăn, ai cấm nó lăn cắt ngang đường cũ chứ? Mà không cho nó lăn cắt ngang (vừa đụng vào đướng cũ là thoát) làm sao nó chạy qua hết tất cả các ô cần thiết?
Sư phụ chỉ cần xét 4 đường biên là được rồi ---> Bên trong không cần!
Nếu rơi vào vòng lập vô hạn thì chắc chắn nó phải "đạp" vào 1 cell nào đó (tại đường biên) mà nó đã từng đi qua
 
Lần chỉnh sửa cuối:
Upvote 0
Nói cũng phải, nhưng để anh em người ta làm dzới chứ. Từ dễ đến khó mà.
 
Upvote 0
Ghi chú:

câu c bài 04, để tránh trường hợp tô hoài không hết như huuthang_bd cảnh báo, xin giới hạn đề bài thành 1 hình chữ nhật cụ thể 15 dòng, 24 cột cho các bạn mới học dễ làm.
Nếu xuất phát từ 1 góc của hình chữ nhật thì khi lăn đến một trong 3 góc còn lại của hình chữ nhật thì coi như trái banh đã lăn qua tất cả các điểm có thể đi qua. Dù có tô hết hay chưa, nếu có lăn tiếp thì cũng lặp lại quỹ đạo cũ. Vì vậy có thể dựa vào đặc điểm này để làm điều kiện thoát vòng lặp.
 
Upvote 0
Vậy cứ thống nhất vậy nhé.
Từ 19/08/2010 - 31/12/2010 mình sẽ làm việc bao nhiêu ngày. Ngày lễ gồm có: 2/9 và ngày nghỉ là CN. Và liệt kê những ngày thứ hai gán vào A1->An của 1 sheet. Dòng vòng lặp thông thường.
Với yêu cầu dạng này dùng vòng lặp là làm chơi thôi, có thể không cần dùng vòng lặp cũng ra được kết quả vì nó có quy luật rõ ràng. Ngày làm=Tổng số ngày-Ngày nghỉ. Tính ngày nghỉ thì xác định ngày nghỉ cuối cùng, ngày nghỉ đầu tiên kết hợp thêm con số 7 nữa là ra. Các ngày nghỉ đặc biệt thì chỉ cần kiểm tra có thuộc khoảng xét hay không nữa là xong.
 
Upvote 0
Với yêu cầu dạng này dùng vòng lặp là làm chơi thôi, có thể không cần dùng vòng lặp cũng ra được kết quả vì nó có quy luật rõ ràng. Ngày làm=Tổng số ngày-Ngày nghỉ. Tính ngày nghỉ thì xác định ngày nghỉ cuối cùng, ngày nghỉ đầu tiên kết hợp thêm con số 7 nữa là ra. Các ngày nghỉ đặc biệt thì chỉ cần kiểm tra có thuộc khoảng xét hay không nữa là xong.
Vâng! Nhưng cũng như tôi đã nói ở lần trước: Chúng ta đang tập tành với vòng lập ---> Vậy thì cứ quét từ ngày đầu đến ngày cuối và xét điều kiện đi ---> Đâu có vấn đề gì chứ
(Chứ để làm bài này thì công thức cũng xong)
 
Upvote 0
Mình xin xúi 1 cách làm tầm bậy, như sau

(*) Tính tổng số ngày;

(*) Tạo 1 vòng lặp từ ngày đầu tiên đến 7 ngày sau đó để tìm ra ngày CN đầu tiên

(*) Tạo vòng lặp từ ngày CN đầu tiên cho đến ngày cuối bước nhảy là 7 để đếm hết các ngày CN

(*) Kiểm thêm ngày Quốc khánh là thứ máy trong tuần

(*) Đáp án là tổng đại số các ngày trên;

Khà, khà,. . . .
 
Upvote 0
(*) Tính tổng số ngày;

(*) Tạo 1 vòng lặp từ ngày đầu tiên đến 7 ngày sau đó để tìm ra ngày CN đầu tiên

(*) Tạo vòng lặp từ ngày CN đầu tiên cho đến ngày cuối bước nhảy là 7 để đếm hết các ngày CN

(*) Kiểm thêm ngày Quốc khánh là thứ máy trong tuần

(*) Đáp án là tổng đại số các ngày trên;

Khà, khà,. . . .
Bác này chỉ xúi không à. Bài tập về vòng lặp thì cũng nên đi tư cơ bản đã, dạng như quy nạp, vậy cứ xét từ ngày đầu đền ngày cuối. Sau khi làm xong thấy cũng hay, ngồi nghĩ lại sao mà vòng này chạy nhiều quá tốn xăng, => mới nghiệm lại có thể nào bớt vòng đi. Chưa gì Bác đã gợi ý, có khi các bạn lại thích vòng lặp kiểu khác sao. Và nhất là phải liệt kê những ngày nghỉ nữa.
Em xin có ngu ý như vậy. Các bạn nếu muốn học VBA sao không xem đây là cơ hội. Thử viết xem 1 code như trên hoàn chỉnh, mình tin chắc sẽ có những cao nhân như Bac SA_DQ, Ndu, RollOver, HuuThang, PTM sẽ hướng dẫn và trau chuốt thêm. Chắc chắn sẽ có ích.
 
Upvote 0
Về bài 4 câu C, tôi xin đưa lên 1 file ví dụ tạo khí thế cho các bạn nghiên cứu, xin được đưa code lên sau, do đó tạm thời tôi protect code(dĩ nhiên là protect VBA không ý nghĩa gì với các cao thủ cả :)).
Chạy macro test trong file này sẽ cho phép nhập vào số Dòng, số Cột(kích thước nào cũng thực hiện tô hết), thực hiện bắt đầu tô từ 1 ô ngẫu nhiên trong vùng và tiến về hướng ngẫu nhiên trong 4 hướng. Nếu kích thước phù hợp sẽ thực hiện tô 1 lần đến hết, nếu kích thước thuộc trường hợp bị lặp lại thì khi nào phát hiện lặp lại thì sẽ thực hiện tô từ 1 ô ngẫu nhiên trong số ô chưa tô theo hướng ngẫu nhiên.
 

File đính kèm

Upvote 0
Về bài 4 câu C, tôi xin đưa lên 1 file ví dụ tạo khí thế cho các bạn nghiên cứu, xin được đưa code lên sau, do đó tạm thời tôi protect code(dĩ nhiên là protect VBA không ý nghĩa gì với các cao thủ cả :)).
Chạy macro test trong file này sẽ cho phép nhập vào số Dòng, số Cột(kích thước nào cũng thực hiện tô hết), thực hiện bắt đầu tô từ 1 ô ngẫu nhiên trong vùng và tiến về hướng ngẫu nhiên trong 4 hướng. Nếu kích thước phù hợp sẽ thực hiện tô 1 lần đến hết, nếu kích thước thuộc trường hợp bị lặp lại thì khi nào phát hiện lặp lại thì sẽ thực hiện tô từ 1 ô ngẫu nhiên trong số ô chưa tô theo hướng ngẫu nhiên.
Thêm 1 tí khí thế nữa --> Tuy không hay bằng của rollover79 nhưng nhìn cũng.. sướng mắt lắm nha!
Cách dùng: Chọn vùng tùy ý rồi nhấn nút
 

File đính kèm

Upvote 0
Về bài 4 câu C, tôi xin đưa lên 1 file ví dụ tạo khí thế cho các bạn nghiên cứu, xin được đưa code lên sau, do đó tạm thời tôi protect code(dĩ nhiên là protect VBA không ý nghĩa gì với các cao thủ cả :)).
Chạy macro test trong file này sẽ cho phép nhập vào số Dòng, số Cột(kích thước nào cũng thực hiện tô hết), thực hiện bắt đầu tô từ 1 ô ngẫu nhiên trong vùng và tiến về hướng ngẫu nhiên trong 4 hướng. Nếu kích thước phù hợp sẽ thực hiện tô 1 lần đến hết, nếu kích thước thuộc trường hợp bị lặp lại thì khi nào phát hiện lặp lại thì sẽ thực hiện tô từ 1 ô ngẫu nhiên trong số ô chưa tô theo hướng ngẫu nhiên.
Xem kỹ lại code của rollover79 mới thấy để giải quyết bài này cho chuẩn thật chẳng đơn giản tí nào
- Chuẩn có nghĩa là tô ca rô toàn bộ vùng chọn, bất kể vùng ấy thế nào
- Dùng phép di chuyển như trái bi-a thì đương nhiên sẽ có trường hợp nào đó rơi vào vòng lập vô hạn dù ca rô chưa được tô hết
- Vậy, đối với trường hợp này ta phải thay đổi vị trí của ActiveCell thế nào đó sao cho bảo đảm tô màu ca rô toàn bộ
--------------------
Hay! nhưng mà với các bạn mới học vòng lập e rằng hơi quá sức chăng?
 
Upvote 0
Xem kỹ lại code của rollover79
Hay! nhưng mà với các bạn mới học vòng lập e rằng hơi quá sức chăng?

Vậy mới phải đề nghị 1 trường hợp cố định 15 dòng x 24 cột trước, cho người ta làm với. Mấy cao thủ cứ ngứa ngáy chân tay hoài.

http://s248.photobucket.com/albums/gg173/ptm0412/GPE/?action=view&current=to2mau.mp4



Code có tí tẹo à, chỉ vài dòng chính thôi.
 
Lần chỉnh sửa cuối:
Upvote 0
Xem kỹ lại code của rollover79 mới thấy để giải quyết bài này cho chuẩn thật chẳng đơn giản tí nào
- Chuẩn có nghĩa là tô ca rô toàn bộ vùng chọn, bất kể vùng ấy thế nào
- Dùng phép di chuyển như trái bi-a thì đương nhiên sẽ có trường hợp nào đó rơi vào vòng lập vô hạn dù ca rô chưa được tô hết
- Vậy, đối với trường hợp này ta phải thay đổi vị trí của ActiveCell thế nào đó sao cho bảo đảm tô màu ca rô toàn bộ
--------------------
Hay! nhưng mà với các bạn mới học vòng lập e rằng hơi quá sức chăng?
Vậy tôi mới phải protect code lại, chỉ là tạo thêm hứng thú cho các bạn khác nghiên cứu thêm thôi mà. Còn bình thường thì đúng như bác ptm nói, không hề phức tạp, thậm chí rất đơn giản chỉ vài dòng code là xong. Còn code của tôi thì nó không đơn giản chỉ là về vấn đề vòng lặp, còn có khá nhiều vấn đề trong đó nữa mà có thể ta sẽ gặp trong các bài toán khác.
 
Upvote 0
(*) Tính tổng số ngày;

(*) Tạo 1 vòng lặp từ ngày đầu tiên đến 7 ngày sau đó để tìm ra ngày CN đầu tiên

(*) Tạo vòng lặp từ ngày CN đầu tiên cho đến ngày cuối bước nhảy là 7 để đếm hết các ngày CN

(*) Kiểm thêm ngày Quốc khánh là thứ máy trong tuần

(*) Đáp án là tổng đại số các ngày trên;

Khà, khà,. . . .
Em sửa lại đoạn code theo hướng dẫn của Bác HYen17 như sau:
Mã:
Sub Tinhngay()
Dim tongngay As Long, nghi As Integer, le As Integer
Dim i As Long, j As Date
Cells.Clear
tongngay = DateSerial(2010, 12, 31) - DateSerial(2010, 8, 19)
le = 1: nghi = 0
For i = 19 To 26
    If Weekday(DateSerial(2010, 8, i)) = 1 Then
       For j = DateSerial(2010, 8, i) To DateSerial(2010, 12, 31) Step 7
        With ActiveCell
             .Value = j
             nghi = nghi + ActiveCell.Count
             .Offset(1, 0).Select
        End With
        Next
    End If
Next
If Weekday(DateSerial(2010, 9, 2)) <> 1 Then ActiveCell = DateSerial(2010, 9, 2)
MsgBox "Tong ngay lam viec la: " & tongngay - le - nghi
End Sub
Các Anh xem và góp ý cho Em nhé!
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Muốn nhận được góp í thì đây, xin mời

đoạn code theo hướng dẫn của Bác HYen17 như sau: . . .
Các Anh xem và góp ý cho Em nhé!

(*) Sau lại nhốt chung vòng lặp sau vô trong vòng lặp trước vậy?

Nếu gặp ngay ngày CN từ đầu, có fải bạn fí fạm 6 lần lặp không cần thiết không nào?
Nên thoát khỏi nó ngay khi gặp ngày CN chứ; Tuy thêm 1 dòng lệnh, nhưng thưởng giảm đi được khoảng gần nữa đọan đường trong vòng lặp thứ nhật đó bạn.
 
Upvote 0
Em sửa lại đoạn code theo hướng dẫn của Bác HYen17 như sau:
Mã:
Sub Tinhngay()
Dim tongngay As Long, nghi As Integer, le As Integer
Dim i As Long, j As Date
Cells.Clear
tongngay = DateSerial(2010, 12, 31) - DateSerial(2010, 8, 19)
le = 1: nghi = 0
For i = 19 To 26
    If Weekday(DateSerial(2010, 8, i)) = 1 Then
       For j = DateSerial(2010, 8, i) To DateSerial(2010, 12, 31) Step 7
        With ActiveCell
             .Value = j
             nghi = nghi + ActiveCell.Count
             .Offset(1, 0).Select
        End With
        Next
    End If
Next
If Weekday(DateSerial(2010, 9, 2)) <> 1 Then ActiveCell = DateSerial(2010, 9, 2)
MsgBox "Tong ngay lam viec la: " & tongngay - le - nghi
End Sub
Các Anh xem và góp ý cho Em nhé!
Đây là code liệt kê tất cả những ngày đi làm ra cột A, từ đầu năm 2010 đến cuối năm 2010 (không tính chủ nhât)
PHP:
Sub Tinhngay()
  Dim i As Long, j As Long
  With Range("A:A")
    .ClearContents
    .NumberFormat = "dd/mm/yyyy"
    For i = DateSerial(2010, 1, 1) To DateSerial(2010, 12, 31)
      If Weekday(i, 1) > 1 Then
        j = j + 1
        .Cells(j, 1) = i
      End If
    Next
  End With
End Sub
Code này chưa tính đến nghỉ lễ ---> Bạn cứ cải tiến nhé
(Nhìn qua nhìn lại chỉ thấy có mỗi bạn MinhCong ---> cái vụ VBA này xem ra ít người khoái nhỉ?)
 
Lần chỉnh sửa cuối:
Upvote 0
Buồn quá, và ngứa ngáy nữa, nên đành post câu c bài 04 lên để tham khảo.

Như đã gợi ý ở câu b, ta dùng 1 gia số dòng và 1 gia số cột.

Xin giải thích 1 tẹo về chạy ca rô: Chạy ca rô là chạy ô vừa lên hoặc xuống, vừa chạy qua phải (hoặc trái), mỗi lần dịch chuyển 1 vị trí dòng và 1 vị trí cột. Xuống thì chỉ số dòng tăng và ngược lại. Qua phải thì chỉ số cột tăng và ngược lại.

Vậy gia số thêm vào cho dòng và cột là các số 1 và -1.

Trước tiên tô màu ô trên cùng bên trái vị trí là dòng i = 1 cột j = 1, hướng đi xuống về bên phải, gia số dòng K = 1 và gia số cột L = 1:

PHP:
i = 1: j = 1
K = 1, L = 1
Cells (i, j).Interior.ColorIndex = 15

Ô kế tiếp có vị trí dòng và cột là i = i + K, j = j + L

Nếu sau khi tô, vị trí ô vừa tô là cạnh rìa của hình chữ nhật, thì đổi chiều:

- Đụng cạnh rìa bên phải: L đổi từ 1 thành -1 để chạy qua trái
- Đụng cạnh rìa bên trái: L đổi từ -1 thành 1 để chạy qua phải
- Đụng cạnh dưới: K đổi từ 1 thành -1 để chạy lên
- Đụng cạnh trên: K đổi từ -1 thành 1 để chạy xuống.

Chưa cần tính tối ưu code làm gì, và cũng chưa cần bẫy lỗi làm gì, bạn đã có 1 đoạn code hoàn chỉnh và ngắn gọn. Với hình chữ nhật không đặc biệt (nghĩa là không bị trả về quỹ đạo cũ), bảo đảm sẽ tô toàn bộ khung chữ nhật thành carô.

Vậy tô bao nhiêu ô? Theo lý thuyết thì tô 1/2 tổng số ô, nhưng do chạy kiểu này, mỗi ô là 1 giao điểm của 2 đường chéo nên sẽ bị chạy qua 2 lần. Vậy Chọn số vòng lặp là tổng số ô và = dòng x cột. Có thể dư, có thể thiếu, nhưng tạm xài.

Code sau đây tô hình chữ nhật không đặc biệt 15 x 24:

PHP:
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
______________________________________

Sub colorRun()
i = 1: j = 1
K = 1: L = 1
For d = 1 To 15 * 24
Sleep (15)
Cells(i, j).Interior.ColorIndex = 15
i = i + K
j = j + L
If i = 15 Or i = 1 Then K = -K
If j = 24 Or j = 1 Then L = -L
Next
End Sub

Code chính có 1 tí tẹo, đúng không?
 
Lần chỉnh sửa cuối:
Upvote 0
Buồn quá, và ngứa ngáy nữa, nên đành post câu c bài 04 lên để tham khảo.
Code chính có 1 tí tẹo, đúng không?
1. Xin hỏi trường hợp code của anh số hàng bằng số cột thì tô màu chỉ có 1 đường chéo
2. Xin anh giải thích giúp đoạn code: Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Camr ơn anh
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
(Nhìn qua nhìn lại chỉ thấy có mỗi bạn MinhCong ---> cái vụ VBA này xem ra ít người khoái nhỉ?)

Không phải đâu anh, chẳng qua chưa làm được thì chưa post lên thôi, nhưng theo dõi và học tập thường xuyên, kính mong mấy anh giúp đỡ, đây là lớp học thuận tiên nhất
Cảm ơn các anh rất nhiều, chúc các anh luôn khỏe.
 
Upvote 0
2. Mở rộng tô hình chữ nhật lấy kích thước từ bàn phím: (Hình đặc biệt vẫn chưa bẫy lỗi, lỗi gì thì thử nhiều kích thước khác nhau sẽ thấy)

PHP:
Sub colorRun1()
CRows = InputBox("So dong?")
CCols = InputBox("So cot?")
If CRows = 1 Or CCols = 1 Then Exit Sub
i = 1: j = 1
K = 1: L = 1
For d = 1 To CRows * CCols
    Sleep (15)
    Cells(i, j).Interior.ColorIndex = 15
    i = i + K
    j = j + L
    If i = CRows Or i = 1 Then K = -K
    If j = CCols Or j = 1 Then L = -L
Next
End Sub

3. Mở rộng tô vùng chọn bất kỳ không phải bắt đầu từ A1: (vẫn chưa sửa gì cho hình chữ nhật đặc biệt)

PHP:
 Sub colorRun2()
CRows = Selection.Rows.Count
CCols = Selection.Columns.Count
If CRows = 1 Or CCols = 1 Then Exit Sub
i = 1: j = 1
K = 1: L = 1
For d = 1 To CRows * CCols
    Sleep (15)
    With Selection
        .Cells(i, j).Interior.ColorIndex = 15
        i = i + K
        j = j + L
        If i = CRows Or i = 1 Then K = -K
        If j = CCols Or j = 1 Then L = -L
    End With
Next
End Sub

Mọi người thử so sánh với code của mình làm xem? (Code của ndu và huuthang cũng chưa tô hết cho hình đặc biệt)
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
1. Xin hỏi trường hợp code của anh số hàng bằng số cột thì tô màu chỉ có 1 đường chéo
2. Em chạy thấy báo lỗi dòng Sleep(15): Xin anh giải thích giúp
Camr ơn anh

Như đã nói từ đầu topic, làm từ dễ đến khó, bẫy lỗi cho mọi hình chữ nhật không phải đơn giản, mới chỉ có mình RollOver đưa file lên tô hình chữ nhật bất kỳ, ndu và Huuthang cũng chưa. Trước mắt suy luận chuyện dễ trước.
Lỗi dòng Sleep do có lẽ viehoai không copy dòng khai báo trên cùng. Tải file bài trên nhé.
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
CRows * CCols
hay 24*15
Con số này bạn lây ở đâu ra vậy, hình như vừa thừa vừa thiếu? đây là số hay, tôi mới tiếp xúc VBA , không biết nên hỏi, nếu không đúng, thì bỏ qua
tôi cũng bị lỗi giống thế, vậy hàm Sleep này mình nghĩ ra, hãy viết ở đâu?

Bạn đọc kỹ bài của tôi sẽ thấy câu này:

Chưa cần tính tối ưu code làm gì, và cũng chưa cần bẫy lỗi làm gì, bạn đã có 1 đoạn code hoàn chỉnh và ngắn gọn. Với hình chữ nhật không đặc biệt (nghĩa là không bị trả về quỹ đạo cũ), bảo đảm sẽ tô toàn bộ khung chữ nhật thành carô.

Vậy tô bao nhiêu ô? Theo lý thuyết thì tô 1/2 tổng số ô, nhưng do chạy kiểu này, mỗi ô là 1 giao điểm của 2 đường chéo nên sẽ bị chạy qua 2 lần. Vậy Chọn số vòng lặp là tổng số ô và = dòng x cột. Có thể dư, có thể thiếu, nhưng tạm xài.

Vậy nên tôi lấy tổng số ô = dài x rộng dùng làm số lần lặp.
Vì vẫn có 1 số ô nằm trên rìa hình chữ nhật không được tô 2 lần, nên hơi dư. Nếu không tô hết thì dư khá nhiều. Tuy vậy, không đến nỗi phải ngồi chờ suông lâu quá.

Hàm sleep là lấy trong thư viện Office ra, nó không có sẵn trong VBA nên phải khai báo đến thư viện (Lib) Kernel32.dll
mục đích dùng hàm này là để Pause code 1 khoảng thời gian tính bằng milisecond.
 
Lần chỉnh sửa cuối:
Upvote 0
Em xin mạnh dạng đưa code, xin các anh chị giúp đỡ:
1. Chọn cell để xác định hàng và cột cuối cùng của vùng cần tô màu nền caro --> chạy code
2. (phần hỏi) Để tô nền caro cho một range bất kỳ (không xuất phát A1) bằng cách quét chọn range bất kỳ nào đó. Muốn vậy cần xác định hàng và cột đầu tiên của Range đó bằng cách nào? (cell đầu tiên của Range đang chọn). Xin các anh chị giúp đỡ
Cảm ơn các anh chị.
 

File đính kèm

Upvote 0
Em xin mạnh dạng đưa code, xin các anh chị giúp đỡ:
1. Chọn cell để xác định hàng và cột cuối cùng của vùng cần tô màu nền caro --> chạy code
2. (phần hỏi) Để tô nền caro cho một range bất kỳ (không xuất phát A1) bằng cách quét chọn range bất kỳ nào đó. Muốn vậy cần xác định hàng và cột đầu tiên của Range đó bằng cách nào? (cell đầu tiên của Range đang chọn). Xin các anh chị giúp đỡ
Cảm ơn các anh chị.

1. Để xác định dòng cột đầu của vùng chọn:

dongdau = Selection.Resize(1, 1).Row
cotdau = Selection.Resize(1, 1).Column

hoặc

dongdau = Selection.Row
cotdau = Selection.Column

2. Để xác định dòng cuối và cột cuối:

dongcuoi = dongdau + Selection.Rows.Count - 1
cotcuoi = cotdau + Selection.Columns.Count - 1

Viehoai có thể thử sửa code cho vùng chọn bất kỳ. Dù không phải tô kiểu bida, nhưng kết quả cũng là tô carô. Coi như bài tập phụ vậy.

Tuy nhiên, không cần thiết phải làm như vậy cho cực.

Đối với 1 vùng chọn hình chữ nhật đơn (nghĩa là không tô chọn nhiều vùng 1 lúc), VBA có thể dùng câu lệnh như sau để đối xử như cả sheet:

Selection.Cells(1, 1) tương đương với ô đầu tiên của vùng chọn. Viết đầy đủ là Sheet1.Selection.Cells(1, 1). Có thể dùng biến i, j bắt đầu từ 1 như cũ.

Đối với sheet thì là Sheet1.Cells(1, 1) nghĩa là ô A1, viết tắt là Cells(1, 1) vì mặc định selection đang là cả sheet.

Trong bài trên tôi đã áp dụng thủ pháp này.
 
Upvote 0
1. Để xác định dòng cột đầu của vùng chọn:

dongdau = Selection.Resize(1, 1).Row
cotdau = Selection.Resize(1, 1).Column

hoặc

dongdau = Selection.Row
cotdau = Selection.Column

2. Để xác định dòng cuối và cột cuối:

dongcuoi = dongdau + Selection.Rows.Count - 1
cotcuoi = cotdau + Selection.Columns.Count - 1

Viehoai có thể thử sửa code cho vùng chọn bất kỳ. Dù không phải tô kiểu bida, nhưng kết quả cũng là tô carô. Coi như bài tập phụ vậy.

Tuy nhiên, không cần thiết phải làm như vậy cho cực.

Đối với 1 vùng chọn hình chữ nhật đơn (nghĩa là không tô chọn nhiều vùng 1 lúc), VBA có thể dùng câu lệnh như sau để đối xử như cả sheet:

Selection.Cells(1, 1) tương đương với ô đầu tiên của vùng chọn. Viết đầy đủ là Sheet1.Selection.Cells(1, 1). Có thể dùng biến i, j bắt đầu từ 1 như cũ.

Đối với sheet thì là Sheet1.Cells(1, 1) nghĩa là ô A1, viết tắt là Cells(1, 1) vì mặc định selection đang là cả sheet.

Trong bài trên tôi đã áp dụng thủ pháp này.

Cảm ơn anh rất nhiều em hiểu sâu hơn về vấn đề này. Tuy nhiên Anh Mỹ giải thích giúp em cách 1 sao có thêm Resize(1,1)?
Em xin sửa lại code theo cách quét vùng chọn bất kỳ ---> chạy code
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Resize(1, 1) nhằm giảm kích thước vùng chọn xuống còn 1 dòng và 1 cột, tương đương 1 ô.
 
Upvote 0
(*) Sau lại nhốt chung vòng lặp sau vô trong vòng lặp trước vậy?

Nếu gặp ngay ngày CN từ đầu, có fải bạn fí fạm 6 lần lặp không cần thiết không nào?
Nên thoát khỏi nó ngay khi gặp ngày CN chứ; Tuy thêm 1 dòng lệnh, nhưng thưởng giảm đi được khoảng gần nữa đọan đường trong vòng lặp thứ nhật đó bạn.
Em sửa lại đoạn code theo góp ý của Bác ChanhTQ@ như sau:
Mã:
Sub Tinhngay()
Dim tongngay As Long, nghi As Integer, le As Integer
Dim i As Long, j As Date
Cells.ClearContents
tongngay = DateSerial(2010, 12, 31) - DateSerial(2010, 8, 19): le = 1
  For i = 19 To 25
    If Weekday(DateSerial(2010, 8, i)) = 1 Then Exit For
  Next
  For j = DateSerial(2010, 8, i) To DateSerial(2010, 12, 31) Step 7
    With [COLOR=Red]ActiveCell[/COLOR]
        .NumberFormat = "dd/mm/yyyy"
        .Value = j
        nghi = nghi + ActiveCell.Count
        .Offset(1, 0).Select
    End With
  Next
If Weekday(DateSerial(2010, 9, 2)) <> 1 Then ActiveCell = DateSerial(2010, 9, 2)
MsgBox "Tong ngay lam viec la: " & tongngay - le - nghi
End Sub
Tuy nhiên chỗ ActiveCell muốn nó nằm ở cột A thì làm sao nhỉ? Không lẽ phải thêm 1 vòng lặp nữa?
 
Lần chỉnh sửa cuối:
Upvote 0
VBA có thể tác động đến ô, dòng, cột bất kỳ, không cần select, chỉ cần dùng lệnh gán.
Thí dụ: 3 câu lệnh sau có kết quả như nhau:
PHP:
Sheet1.Range("A1") = i
Cells(1, 1) = i
[A1] = i

Nếu muốn gán kết quả xuống các ô kế tiếp nhau trên cùng cột, cũng có nhiều cách:

PHP:
[A1000]. End(xlUp).Offset(1,0) = i
[A1].End(xlDown).Offset(1,0) = i

Nếu có 1 biến khác chạy step 1, (thí dụ biến j), có thể dùng:

PHP:
Cells(j, 1) = i

Nếu j chạy step 2, thì j chia 2. Nếu không có biến nào phù hợp, tạo 1 biến đếm tăng 1 khi thoả điều kiện.

Cụ thể trong code trên, có thể dùng End cách 1 hoặc 2.

MinhCong xem thêm code tô màu, đâu có phải select từng cell để gán màu nữa đâu?
 
Lần chỉnh sửa cuối:
Upvote 0
Em sửa lại đoạn code theo góp ý của Bác ChanhTQ@ như sau:
Mã:
Sub Tinhngay()
Dim tongngay As Long, nghi As Integer, le As Integer
Dim i As Long, j As Date
Cells.ClearContents
tongngay = DateSerial(2010, 12, 31) - DateSerial(2010, 8, 19): le = 1
For i = 19 To 25
If Weekday(DateSerial(2010, 8, i)) = 1 Then Exit For
Next
For j = DateSerial(2010, 8, i) To DateSerial(2010, 12, 31) Step 7
With [COLOR=red]ActiveCell[/COLOR]
.NumberFormat = "dd/mm/yyyy"
.Value = j
nghi = nghi + ActiveCell.Count
.Offset(1, 0).Select
End With
Next
If Weekday(DateSerial(2010, 9, 2)) <> 1 Then ActiveCell = DateSerial(2010, 9, 2)
MsgBox "Tong ngay lam viec la: " & tongngay - le - nghi
End Sub
Tuy nhiên chỗ ActiveCell muốn nó nằm ở cột A thì làm sao nhỉ? Không lẽ phải thêm 1 vòng lặp nữa?
Một cách để cho kết quả từ A1:
_ Tạo một biến, thí dụ : Dim K as Integer
_ With ActiveCell thay bằng With [A1].Offset(K) hoặc With Cells(K + 1, 1)
_ Thay .Offset(1, 0).Select bằng K= K + 1
 
Upvote 0
Câu C bài số 4 trong trường hợp tổng quát, giả sử tô 1 vùng bất kỳ bởi 2 màu, khi đó ta sẽ thấy tập các ô có tính chất (Cột+Dòng) là 1 số chẵn sẽ được tô 1 màu, tập các ô có tính chất (Cột+Dòng) là 1 số lẻ được tô 1 màu. Như vậy nếu để tô mà không cần theo quy luật về đường đi thì các bạn chỉ cần duyệt và tô theo tính chất trên sẽ rất đơn giản. Còn về quy luật đường đi thì theo cách của bác ptm theo tôi là chuẩn nhất rồi. Vậy để giải quyết bài này theo hướng tổng quát nhất ta có thể đi theo mấy bước như sau:
1. Duyệt tất cả các ô, đẩy tất cả các ô cần tô(có cùng tính chất Dòng+Cột chẵn hoặc lẻ) vào 1 danh sách
2. Chọn ngẫu nhiên 1 ô trong danh sách, thực hiện tô màu cho ô này, sau khi tô thì loại ô đó ra khỏi danh sách, sau khi loại khỏi danh sách mà hết danh sách thì dừng.
3. Thực hiện di chuyển từ ô vừa tô theo nguyên tắc di chuyển(di chuyển đến ô nào thì kiểm tra nếu ô đó có trong danh sách thì loại ô đó ra khỏi danh sách), gặp dấu hiệu bị lặp thì dừng di chuyển và quay lại bước 2.
Tôi xin gửi các bạn code của cả 3 câu của bài 4 như sau:
Câu a
Mã:
Sub Row1()
    Dim iValue As Long, iCol As Long, iRow As Long, iRows As Long, iCols As Long
    iCols = InputBox("Nhap so cot:")
    iRows = InputBox("Nhap so dong:")
    For iValue = 1 To iRows * iCols
        iRow = (iValue - 1) \ iCols + 1
        iCol = (iValue - 1) Mod iCols + 1
        Cells(iRow, iCol).Interior.ColorIndex = 4
        Sleep 100
    Next
End Sub
Câu b
Mã:
Sub Row2()
    Dim iValue As Long, iCol As Long, iRow As Long, iRows As Long, iCols As Long
    iCols = InputBox("Nhap so cot:")
    iRows = InputBox("Nhap so dong:")
    For iValue = 1 To iRows * iCols
        iRow = (iValue - 1) \ iCols + 1
        iCol = IIf(iRow Mod 2 = 1, (iValue - 1) Mod iCols + 1, iCols - ((iValue - 1) Mod iCols))
        Cells(iRow, iCol).Interior.ColorIndex = 4
        Sleep 100
    Next
End Sub
Câu c
Mã:
Sub Caro1()
    Dim iValue As Long, iCol As Long, iRow As Long, iRows As Long, iCols As Long, objDic As New 

Dictionary, EpRow As Long, EpCol As Long
    iCols = InputBox("Nhap so cot:")
    iRows = InputBox("Nhap so dong:")
    For iValue = 1 To iCols * iRows
        iRow = (iValue - 1) \ iCols + 1
        iCol = (iValue - 1) Mod iCols + 1
        If ((iRow + iCol) Mod 2 = 0) Then objDic.Add iValue, iValue
    Next
    Randomize
    Do While objDic.Count > 0
        EpRow = IIf(Rnd() > 0.5, 1, -1)
        EpCol = IIf(Rnd() > 0.5, 1, -1)
        iValue = Int(Rnd() * objDic.Count)
        iRow = (objDic.Keys(iValue) - 1) \ iCols + 1
        iCol = (objDic.Keys(iValue) - 1) Mod iCols + 1
        Cells(iRow, iCol).Interior.ColorIndex = 4
        Sleep 200
        objDic.Remove objDic.Keys(iValue)
        Do While objDic.Count > 0
            If iRow + EpRow < 1 Or iRow + EpRow > iRows Then EpRow = EpRow * (-1)
            If iCol + EpCol < 1 Or iCol + EpCol > iCols Then EpCol = EpCol * (-1)
            iRow = iRow + EpRow
            iCol = iCol + EpCol
            iValue = (iRow - 1) * iCols + iCol
            Cells(iRow, iCol).Interior.ColorIndex = 4
            Sleep 100
            If objDic.Exists(iValue) Then
                objDic.Remove iValue
            Else
                If iRow = 1 Or iRow = iRows Or iCol = 1 Or iCol = iCols Then Exit Do
            End If
        Loop
    Loop
    MsgBox "OK!"
End Sub
Các bạn thử cải tiến thành 3 câu như sau:
Câu a thành tô theo từng cột từ trên xuống dưới
Câu b thành tô theo từng cột từ trên xuống dưới rồi lại từ dưới lên trên
Câu c thành tô với 2 màu, khi nào tô hết màu thứ nhất thì tô tiếp màu thứ 2 để thành 1 bàn cờ với 2 màu.
 
Upvote 0
Câu a và b chr cần thay đổi vị trí của cells(iRow,iCol) thành cells(iCol,iRow) là được.
Mã:
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Câu a:
Mã:
Sub Row1()
    Dim iValue As Long, iCol As Long, iRow As Long, iRows As Long, iCols As Long
    Cells.Clear
    iCols = InputBox("Nhap so cot:")
    iRows = InputBox("Nhap so dong:")
    For iValue = 1 To iRows * iCols
        iRow = (iValue - 1) Mod iCols + 1
        iCol = (iValue - 1) \ iCols + 1
        Cells(iRow, iCol).Interior.ColorIndex = 4
        Sleep 50
    Next
End Sub
Câu b:
Mã:
Sub Row2()
    Dim iValue As Long, iCol As Long, iRow As Long, iRows As Long, iCols As Long
    Cells.Clear
    iCols = InputBox("Nhap so cot:")
    iRows = InputBox("Nhap so dong:")
    For iValue = 1 To iRows * iCols
        iCol = (iValue - 1) \ iCols + 1
        iRow = IIf(iCol Mod 2 = 1, (iValue - 1) Mod iCols + 1, iCols - ((iValue - 1) Mod iCols))
        Cells(iRow, iCol).Interior.ColorIndex = 4
        Sleep 100
    Next
End Sub
Đoạn code tô caro sao Em chạy nó bị báo lỗi ở khai báo objDic As New Dictionary nhỉ?
 

File đính kèm

Upvote 0
Đoạn code tô caro sao Em chạy nó bị báo lỗi ở khai báo objDic As New Dictionary nhỉ?
Vào menu Tools\References và check vào mục Microsoft scripting runtime là hết lỗi ngay

untitled.JPG


Ngoài ra ra còn cách khác:
PHP:
Sub Caro1()
  Dim objDic
  Set objDic = CreateObject("Scripting.Dictionary")
  .....
  ....
End Sub
 
Upvote 0
Câu c, nếu tô 1 màu, thì căn cứ vào diễn giải của RollOver, và đoạn code sau:

PHP:
    For iValue = 1 To iCols * iRows
        iRow = (iValue - 1) \ iCols + 1
        iCol = (iValue - 1) Mod iCols + 1
        If ((iRow + iCol) Mod 2 = 0) Then objDic.Add iValue, iValue
    Next

Nếu thay điều kiện If (iRow + iCol) Mod 2 = 0 thành
If (iRow + iCol) Mod 2 = 1
sẽ tô các ô còn lại.

Vậy cho code chạy 2 lần với 2 tham số sẽ tô bàn cờ 2 màu:

Mã:
Private Sub CommandButton1_Click()
    Cells.Clear
    iCols = InputBox("Nhap so cot:")
    iRows = InputBox("Nhap so dong:")

Caro1 iCols, iRows, 1, 15
Caro1 iCols, iRows, 0, 16
End Sub

Mã:
Sub Caro1(ByVal iCols As Long, ByVal iRows As Long, le As Long, clor As Long)
    Dim iValue As Long, iCol As Long, iRow As Long
    Dim objDic As New Dictionary, EpRow As Long, EpCol As Long
    For iValue = 1 To iCols * iRows
        iRow = (iValue - 1) \ iCols + 1
        iCol = (iValue - 1) Mod iCols + 1
        If ((iRow + iCol) Mod 2 = [COLOR="Red"][B]le[/B][/COLOR]) Then objDic.Add iValue, iValue
    Next

Đoạn dưới giữ nguyên chỉ sửa 2 dòng sau:
Mã:
....
        Cells(iRow, iCol).Interior.ColorIndex = [B][COLOR="Red"]clor[/COLOR][/B]
...
 
Lần chỉnh sửa cuối:
Upvote 0
Tiếp tục đi các Anh. Cho Em út có cơ hội học hỏi với. Các Bạn nào trên diễn đàn đang tham gia học hỏi topic này thì cố viết code đưa lên để các Anh giúp cho, đừng sợ sai gì cả đâu có ai mới học lại giỏi liền đâu? Riêng Em cái vụ VBA này rất khoái (mặc dù ít áp dụng cho công việc của mình).
 
Upvote 0
Tiếp tục đi các Anh. Cho Em út có cơ hội học hỏi với. Các Bạn nào trên diễn đàn đang tham gia học hỏi topic này thì cố viết code đưa lên để các Anh giúp cho, đừng sợ sai gì cả đâu có ai mới học lại giỏi liền đâu? Riêng Em cái vụ VBA này rất khoái (mặc dù ít áp dụng cho công việc của mình).

Ngoài việc "chờ" người ta đưa bài tập mẫu, các bạn có thể tự mình nghĩ ra 1 tình huống gì đó phải dùng đến vòng lập rồi đưa lên đây để chúng ta cùng "mổ xẻ"
Nhớ lại ngày trước, khi mới chập chững vấn thân vào VBA, tay cơ còn quá non mà tôi còn dám "gan cùng mình", mở nguyên 1 topic ĐỐ VUI VỀ VBA đấy thôi
Ngán gì chứ? Hi... hi...
 
Upvote 0
Tiếp tục đi các Anh. Cho Em út có cơ hội học hỏi với. Các Bạn nào trên diễn đàn đang tham gia học hỏi topic này thì cố viết code đưa lên để các Anh giúp cho, đừng sợ sai gì cả đâu có ai mới học lại giỏi liền đâu? Riêng Em cái vụ VBA này rất khoái (mặc dù ít áp dụng cho công việc của mình).
Thêm bài số 05 tương tự loạt bài 04 như sau:
Câu a: Tô màu với N bất kỳ theo nguyên tắc như sau:
attachment.php

Câu b: Tương tự câu a nhưng theo nguyên tắc:
attachment.php

Chú ý là tô theo thứ tự các con số của mỗi ô.
 

File đính kèm

  • 123.GIF
    123.GIF
    5.3 KB · Đọc: 106
  • 456.GIF
    456.GIF
    5.6 KB · Đọc: 106
Upvote 0
Gợi ý sơ qua!
Với câu 5a) của rollover79, các bạn dùng 2 vòng lập là dễ nhất:
PHP:
For iR = 1 To n
    For iC = n - iR + 1 To n + iR - 1
Với
- n là số các bạn nhập vào InputBox
- iRiC là vị trí cell
- Cells(iR, iC) chính là cell mà các bạn cần tô màu
Gợi ý gần như... toàn bộ rồi đấy!
-----------
Cũng có thể dùng 1 vòng lập For i = 1 to n^2 ---> Tùy ý
Thử xem! Câu 5b) gần như tương tự (về cách suy luận)
 
Lần chỉnh sửa cuối:
Upvote 0
Em xin đáp án 2 câu trên bằng 2 vòng lặp For như anh NDU gợi ý như sau:
Mã:
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
Câu a:
Mã:
Sub Tomau1()
Dim iR As Long, iC As Long, N As Long
  Cells.Clear
  N = InputBox("Hay nhap N?")
 For iR = 1 To N
   For iC = N - iR + 1 To N + iR - 1
      With Cells(iR, iC)
        .Interior.ColorIndex = 5
        Sleep 50
      End With
    Next iC
 Next iR
End Sub
Câu b:
Mã:
Sub Tomau2()
Dim iR As Long, iC As Long, N As Long
  Cells.Clear
  N = InputBox("Hay nhap N?")
 For iR = 1 To N
   For iC = N - iR + 1 To N + iR
      With Cells(iR, iC)
        .Interior.ColorIndex = 5
        Sleep 50
      End With
    Next iC
 Next iR
End Sub
Dùng 1 vòng lặp thì Em chưa nghiên cứu tới. Cố gắng chiều nay có thể hoàn thành 1 vòng lặp. Hì hì
 

File đính kèm

Upvote 0
Dùng 1 vòng lặp thì Em chưa nghiên cứu tới. Cố gắng chiều nay có thể hoàn thành 1 vòng lặp. Hì hì
MinhCong khá lắm, nhất là đã tự mình suy luận được câu 5b) ---> Cố gắng lên, chẳng bao lâu bạn sẽ thành cao thủ như ai!
Sư phụ ptm0412 đã từng cho tôi 1 bài học: Cái khó nằm ở tư duy logic chứ còn code kiết gì đó chỉ là công cụ hổ trợ, làm vài lần tự nhiên quen tay thôi
Về vụ 1 vòng lập, nghiên cứu thì cứ việc nhưng xin lưu ý với bạn rằng với bài này, dù là 1 vòng lập hay 2 vòng lập thì tốc độ vẫn như nhau
(có chăng là nghiên cứu thuật toán chơi, biết đâu dùng trong dịp khác)
 
Lần chỉnh sửa cuối:
Upvote 0
MinhCong khá lắm, nhất là đã tự mình suy luận được câu 5b) ---> Cố gắng lên, chẳng bao lâu bạn sẽ thành cao thủ như ai!
Sư phụ ptm0412 đã từng cho tôi 1 bài học: Cái khó nằm ở tư duy logic chứ còn code kiết gì đó chỉ là công cụ hổ trợ, làm vài lần tự nhiên quen tay thôi
Về vụ 1 vòng lập, nghiên cứu thì cứ việc nhưng xin lưu ý với bạn rằng với bài này, dù là 1 vòng lập hay 2 vòng lập thì tốc độ vẫn như nhau
(có chăng là nghiên cứu thuật toán chơi, biết đâu dùng trong dịp khác)
1 vòng lặp Em làm có lẽ được 1/2 vì Em nghĩ đặt được điều kiện cho iRow rồi, còn cái ICol thì đang nghiên cứu, thấy khó tư duy quá. Biết cách nó chạy nhưng cái thuật toán thì chưa tìm ra được mới tức chứ.
Mã:
For i = 1 To N ^ 2
        iRow = IIf(i <= N, i, N)
iRow Em dò lại thì có lẽ là đúng (chưa chắc lắm).
 
Upvote 0
1 vòng lặp Em làm có lẽ được 1/2 vì Em nghĩ đặt được điều kiện cho iRow rồi, còn cái ICol thì đang nghiên cứu, thấy khó tư duy quá. Biết cách nó chạy nhưng cái thuật toán thì chưa tìm ra được mới tức chứ.
Mã:
For i = 1 To N ^ 2
        iRow = IIf(i <= N, i, N)
iRow Em dò lại thì có lẽ là đúng (chưa chắc lắm).
Hình như iRow bằng vầy thì phải
iRow = Int(Sqr(i - 1)) + 1
Kiểm tra lại xem ---> Khỏi IF
Khó ở chổ tìm iCol đấy ---> Bùn lắm thì IF... IF gì đó đi!
Ẹc... Ẹc...
 
Upvote 0
Vụ dùng 1 vòng lặp thì tốt nhất hãy nghĩ đến dùng gia số dòng cột có điều kiện. If iếc đâu có mất mát gì đâu.

Note: irow tính theo ndu mới đúng, MinhCong tính sai rồi.
 
Upvote 0
1 vòng lặp Em làm có lẽ được 1/2 vì Em nghĩ đặt được điều kiện cho iRow rồi, còn cái ICol thì đang nghiên cứu, thấy khó tư duy quá. Biết cách nó chạy nhưng cái thuật toán thì chưa tìm ra được mới tức chứ.
Mã:
For i = 1 To N ^ 2
        iRow = IIf(i <= N, i, N)
iRow Em dò lại thì có lẽ là đúng (chưa chắc lắm).
iRow thì như bác cách của bác ndu. iCol thì tôi gợi ý chút thế này.
Với mỗi 1 giá trị i ta đã biết iRow, với mỗi iRow ta đã biết cột xuất phát của dòng rồi, lấy cột xuất phát + thứ tự của ô tương ứng với giá trị i trong dòng đó là xong. Để tính thứ tự của ô tương ứng với giá trị i thì hãy thử vận dụng các dữ kiện bao gồm i và tổng số ô của các dòng phía trên xem sao.
Ví dụ:
Với N=4, khi i=8 ta có iRow=3, Cột xuất phát là cột 2(N-iRow+1), giờ ta tính tổng các ô của các dòng phía trên(dòng 1 và dòng 2), ở đây là 4=(iRow-1)^2. Giờ từ i=8, cột xuất phát là 2, và tổng các ô các dòng phía trên là 4, hãy tính thử xem sao.
 
Upvote 0
iRow thì như bác cách của bác ndu. iCol thì tôi gợi ý chút thế này.
Với mỗi 1 giá trị i ta đã biết iRow, với mỗi iRow ta đã biết cột xuất phát của dòng rồi, lấy cột xuất phát + thứ tự của ô tương ứng với giá trị i trong dòng đó là xong. Để tính thứ tự của ô tương ứng với giá trị i thì hãy thử vận dụng các dữ kiện bao gồm i và tổng số ô của các dòng phía trên xem sao.
Ví dụ:
Với N=4, khi i=8 ta có iRow=3, Cột xuất phát là cột 2(N-iRow+1), giờ ta tính tổng các ô của các dòng phía trên(dòng 1 và dòng 2), ở đây là 4=(iRow-1)^2. Giờ từ i=8, cột xuất phát là 2, và tổng các ô các dòng phía trên là 4, hãy tính thử xem sao.
Viết thế này người đọc dễ hiểu cột xuất phát được tính bằng công thức 2*(N-iRow+1). Chỗ này, phần trong ngoặc là chú thích cho số 2.
 
Upvote 0
Mọi người tính cột xuất phát thế nào ấy nhỉ? Tôi tính chỉ bằng 1/2 của Roll và Huuthang thôi: N - iRow + 1
Còn jCol, theo tôi cứ tính jCol xuất phát, sau đó cho jCol tăng 1 dần dần. Khi nào xuống dòng (iRow tăng), tính lại jCol xuất phát mới. Cách tư duy này đơn giản hơn.
Kể cả iRow, nếu tư duy đơn giản thì cho iRow xuất phát = 1, khi thoả điều kiện, iRow = iRow +1

Kết hợp cả 2, iRow tăng, tính lại jCol, cùng 1 điều kiện, chỉ cần 1 If.
 
Lần chỉnh sửa cuối:
Upvote 0
Mọi người tính cột xuất phát thế nào ấy nhỉ? Tôi tính chỉ bằng 1/2 của Roll và Huuthang thôi: N - iRow + 1
Còn jCol, theo tôi cứ tính jCol xuất phát, sau đó cho jCol tăng 1 dần dần. Khi nào xuống dòng (iRow tăng), tính lại jCol xuất phát mới. Cách tư duy này đơn giản hơn.
Kể cả iRow, nếu tư duy đơn giản thì cho iRow xuất phát = 1, khi thoả điều kiện, iRow = iRow +1

Kết hợp cả 2, iRow tăng, tính lại jCol, cùng 1 điều kiện, chỉ cần 1 If.
Cột xuất phát là cột xuất phát của 1 dòng cụ thể nào đó mà, ví dụ tại dòng iRow thì cột xuất phát sẽ là N-iRow+1, còn việc tính iCol thì đúng là hơi khó tư duy, nhưng làm theo cách đó thì thuật toán đọc lên rõ ràng. Cứ với mỗi giá trị ta có Dòng và Cột rồi đem xử lý là xong. Còn phương pháp tăng Dòng và Cột thì có vẻ nó giống với 2 vòng lặp, còn khi thể hiện với 1 vòng lặp thì thuật toán hơi rối.
 
Upvote 0
Xin lỗi RollOver đã đọc nhầm chỗ này: 2(N-iRow+1), nếu viết cách ra và ghi chú 2 (tính bằng N-iRow+1) thì rõ nghĩa hơn. Xin lỗi HuuThang vì HT cũng giải thích chứ không phải tính.

Còn ý tôi khi cho tăng dòng cột là cho người mới học, nếu cách tính toán khó khăn thì nghĩ đến cách tư duy đơn giản trước. Vả lại, nếu ta phát triển tô như trên nhưng 2 lần, 1 lần là lần lượt tăng mổi dòng 1, 3, 5, .., N ô, sau đó giảm mỗi dòng N-2, ..., 5, 3 ,1 ô (dạng hình thoi bằng 2 hình tam giác bài 5, 1 úp 1 lật ngửa); cũng dễ phát triển hơn. Đơn giản vốn dễ phát triển hơn phức tạp mà.
 
Lần chỉnh sửa cuối:
Upvote 0
Gợi ý tiếp câu 5a) cho trường hợp 1 vòng lập
PHP:
iCol = n - iRow + j - (iRow - 1) ^ 2
Với j là biến chạy, n là số nhập trong InputBox
Thí nghiệm thử rồi làm luôn câu 5b) cho trường hợp 1 vòng lập
-------------------------------
Nếu đã hoàn tất, các bạn hãy thử nghĩ đến vấn đề bẫy lỗi xem:
- Với n như thế nào thì code sẽ lỗi?
- Giải pháp bẫy lỗi ra sao?
-------------------------------
(Lập trình viên thường ít khi sợ viết code mà chỉ ngán việc bẫy lỗi thôi!)
 
Upvote 0
Gợi ý tiếp câu 5a) cho trường hợp 1 vòng lập
PHP:
iCol = n - iRow + j - (iRow - 1) ^ 2
Với j là biến chạy, n là số nhập trong InputBox
Thí nghiệm thử rồi làm luôn câu 5b) cho trường hợp 1 vòng lập
-------------------------------
Nếu đã hoàn tất, các bạn hãy thử nghĩ đến vấn đề bẫy lỗi xem:
- Với n như thế nào thì code sẽ lỗi?
- Giải pháp bẫy lỗi ra sao?
-------------------------------
(Lập trình viên thường ít khi sợ viết code mà chỉ ngán việc bẫy lỗi thôi!)
Em xin đưa câu 5a lên theo hướng dẫn của anh NDU như sau:
Mã:
[COLOR=Blue]Sub Tomau3()
Dim iR As Long, iC As Long, N As Long
  Cells.Clear
  N = InputBox("Hay nhap N?")
If N > 128 Or N < 0 Then Exit Sub
 For i = 1 To N ^ 2
   iR = Int(Sqr(i - 1)) + 1
   iC = N - iR + i - (iR - 1) ^ 2
      With Cells(iR, iC)
        .Interior.ColorIndex = 5
        Sleep 50
      End With
 Next
End Sub[/COLOR]
Lỗi khi nhập n theo Em nghĩ như sau:
Lỗi nếu n để trống (tức không nhập số vào box), n<0 và n>128 (vì excel có tổng cộng là 256 cột => 256/2=128, mà ta tô màu đối xứng từ giữa ra 2 bên).
Bẫy lỗi như vậy không biết có đúng không? Các Anh xem và góp ý cho Em nhé!
 
Upvote 0
Em xin đưa câu 5a lên theo hướng dẫn của anh NDU như sau:
Mã:
[COLOR=Blue]Sub Tomau3()
Dim iR As Long, iC As Long, N As Long
  Cells.Clear
  N = InputBox("Hay nhap N?")
If N > 128 Or N < 0 Then Exit Sub
 For i = 1 To N ^ 2
   iR = Int(Sqr(i - 1)) + 1
   iC = N - iR + i - (iR - 1) ^ 2
      With Cells(iR, iC)
        .Interior.ColorIndex = 5
        Sleep 50
      End With
 Next
End Sub[/COLOR]
Lỗi khi nhập n theo Em nghĩ như sau:
Lỗi nếu n để trống (tức không nhập số vào box), n<0 và n>128 (vì excel có tổng cộng là 256 cột => 256/2=128, mà ta tô màu đối xứng từ giữa ra 2 bên).
Bẫy lỗi như vậy không biết có đúng không? Các Anh xem và góp ý cho Em nhé!
Gần được rồi đấy!
Thiếu 1 vài chổ:
- Biến i chưa khai báo
- Chưa bẫy lỗi nhập TEXT vào InputBox ---> Có thể cải tiến thành Application.InputBox("Hay nhap N?", Type:=1)
- Mặc dù nhập số thập phân vào nó vẫn chạy (vì khai báo n as Long) nhưng cũng nên để ý đến việc bẫy lỗi này
- Khó nhất là bẫy lỗi không nhập gì hoặc bấm Cancel trên InputBox
 
Upvote 0
Gần được rồi đấy!
- Mặc dù nhập số thập phân vào nó vẫn chạy (vì khai báo n as Long) nhưng cũng nên để ý đến việc bẫy lỗi này
- Khó nhất là bẫy lỗi không nhập gì hoặc bấm Cancel trên InputBox
Anh chỉ cho Em cách bẫy lỗi 2 thằng trên đi.
Về lỗi thập phân Em định dùng 1 biến tạm T cho nó T=INT(N) có được không nhỉ?
 
Upvote 0
Anh chỉ cho Em cách bẫy lỗi 2 thằng trên đi.
Về lỗi thập phân Em định dùng 1 biến tạm T cho nó T=INT(N) có được không nhỉ?
Về việc bẫy lỗi số thập phân, dùng thế là chính xác rồi
Còn vụ InputBox, đã từng được đề cập trong mục Đố vui về VBA! xem tại đây:
http://www.giaiphapexcel.com/forum/showthread.php?7146-%C4%90%E1%BB%91-vui-v%E1%BB%81-VBA%21&p=232566#post232566
Có thể làm sơ qua thế này:
Mã:
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub Tomau3()
  Dim iR As Long, iC As Long, [COLOR=Red][B]N[/B][/COLOR], i As Long
  Cells.Clear
  [COLOR=Black]N = [B][COLOR=Red]Val([/COLOR][/B]InputBox("Hay nhap N?"))[/COLOR]
  If N > 128 Or N < 0 Or [COLOR=Red]N <> Int(N)[/COLOR] Then Exit Sub
  For i = 1 To N ^ 2
   iR = Int(Sqr(i - 1)) + 1
   iC = N - iR + i - (iR - 1) ^ 2
   Cells(iR, iC).Interior.ColorIndex = 5
   Sleep 50
 Next
End Sub
Quan trọng nằm ở chổ màu đỏ ấy
- Khai báo N kiểu Variant
- N = Val(...) suy ra nếu InputBox là TEXT thì N = 0
- Chấp luôn bấm Cancel và OK khi chưa nhập gì
 
Lần chỉnh sửa cuối:
Upvote 0

Bài viết mới nhất

Back
Top Bottom