Xây dựng một hình tam giác không có hình tam giác


44

Khi còn nhỏ, tôi rất thích chơi với những đồ chơi này:

nhập mô tả hình ảnh ở đây

Có lẽ họ dự định những thứ này sẽ được sử dụng cho nghệ thuật, nhưng tôi luôn sử dụng chúng cho toán học! Fractals, mẫu, v.v ... Một lần, tôi được đưa ra thử thách này:

Xây dựng một hình tam giác mà không sử dụng bất kỳ gạch tam giác màu xanh lá cây.

Thử thách này đã khiến tôi vấp ngã trong thời gian dài nhất, cho đến khi tôi tình cờ thấy một cách thực sự đẹp và đơn giản chỉ với 3 hình thang:

  /\  
 /_/\ 
/__\_\

Bây giờ, lấy hình tam giác này và xoay nó:

______         
\ \__/         
 \/ /          
  \/ 

Sử dụng hai hình tam giác này, chúng ta có thể tạo ra các hình tam giác lớn hơn trong số chúng. Đây là một tam giác có chiều cao 2:

     /\           
    /_/\          
   /__\_\         
  /\ \__/\        
 /_/\/ /_/\       
/__\_\/__\_\    

Và đây là những hình tam giác có chiều cao 3- 7:

#3
        /\
       /_/\
      /__\_\
     /\ \__/\
    /_/\/ /_/\
   /__\_\/__\_\
  /\ \__/\ \__/\
 /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\

#4
           /\
          /_/\
         /__\_\
        /\ \__/\
       /_/\/ /_/\
      /__\_\/__\_\
     /\ \__/\ \__/\
    /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\

#5
              /\
             /_/\
            /__\_\
           /\ \__/\
          /_/\/ /_/\
         /__\_\/__\_\
        /\ \__/\ \__/\
       /_/\/ /_/\/ /_/\
      /__\_\/__\_\/__\_\
     /\ \__/\ \__/\ \__/\
    /_/\/ /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\/__\_\

#6
                 /\
                /_/\
               /__\_\
              /\ \__/\
             /_/\/ /_/\
            /__\_\/__\_\
           /\ \__/\ \__/\
          /_/\/ /_/\/ /_/\
         /__\_\/__\_\/__\_\
        /\ \__/\ \__/\ \__/\
       /_/\/ /_/\/ /_/\/ /_/\
      /__\_\/__\_\/__\_\/__\_\
     /\ \__/\ \__/\ \__/\ \__/\
    /_/\/ /_/\/ /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\/__\_\/__\_\

#7
                    /\
                   /_/\
                  /__\_\
                 /\ \__/\
                /_/\/ /_/\
               /__\_\/__\_\
              /\ \__/\ \__/\
             /_/\/ /_/\/ /_/\
            /__\_\/__\_\/__\_\
           /\ \__/\ \__/\ \__/\
          /_/\/ /_/\/ /_/\/ /_/\
         /__\_\/__\_\/__\_\/__\_\
        /\ \__/\ \__/\ \__/\ \__/\
       /_/\/ /_/\/ /_/\/ /_/\/ /_/\
      /__\_\/__\_\/__\_\/__\_\/__\_\
     /\ \__/\ \__/\ \__/\ \__/\ \__/\
    /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\/__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\/__\_\/__\_\/__\_\

Các thách thức

Viết chương trình hoặc hàm lấy số n và in tam giác không có tam giác có chiều cao n . Không gian lưu trữ trên mỗi dòng là chấp nhận được, và tối đa một dấu vết hoặc dòng mới hàng đầu cũng được chấp nhận. IO có thể ở bất kỳ định dạng hợp lý. Đầu vào được đảm bảo là một số nguyên dương, vì vậy bạn không phải lo lắng về số âm, số thập phân, số không, v.v.

Câu trả lời ngắn nhất trong byte chiến thắng!


Hãy thử tạo thêm hình thang ra khỏi hình thang. Độ dài 2 và 3 chắc chắn là có thể (và bằng cách mở rộng, tất cả các số có dạng 2 ^ a * 3 ^ b) (Làm sao tôi biết? Chơi với cùng một loại khối khi tôi còn là một đứa trẻ.)
CalculatorFeline

1
@CatsAreFluffy Vâng, vì bạn có thể tạo hình thang ra khỏi hình tam giác, bạn có thể kết luận rằng bạn có thể tạo hình thang ra khỏi hình thang. Trong thực tế, nếu bạn nhìn vào các hình tam giác có chiều cao 3 và 7, bạn có thể thấy mô hình tương tự lặp lại với hình thang lớn.
DJMcMayhem

Thử thách này thực sự rất tuyệt. Tôi rất thích tìm ra cách để làm điều này trong Retina.
mbomb007

@ mbomb007 Rất vui khi biết bạn thích nó! = D Đó chính xác là lý do tại sao tôi viết thử thách.
DJMcMayhem

2
Thử thách này phù hợp hoàn hảo trên màn hình với ứng dụng di động. Đó có phải là cố ý? :)
Doddy

Câu trả lời:


15

CJam, 47

ri_"/__\_\/_/\/ /\ \__"6/f**eeW%{_S.*s\~,\-<N}/

Giải trình:

ri_       read the input, convert to integer and duplicate
"…"       push that string, containing the repeating pattern
           (3 lines in reverse order, concatenated)
6/        split into (3) lines of 6 characters
f*        multiply (repeat) each line n times
*         repeat the array of 3 lines n times
           at this point we have an array of 3*n strings with 6*n characters each
ee        enumerate the array (obtaining an array of [index string] pairs)
W%        reverse the array
           (so the lines are in correct order and indices in reverse order)
{…}/      for each [index string] pair
  _       duplicate the pair
  S.*     vectorized-multiply with " "
           this effectively replaces the index with a string of <index> spaces
  s       convert the pair to string, effectively concatenating the spaces
           with the string
  \       swap with the other copy of the [index string] pair
  ~,      dump the index and string on the stack and get the string length
  \-      subtract the index from it - this is the desired line length
  <       cut the concatenated string to that length
  N       add a newline

Dùng thử trực tuyến


17

Ruby, 79

->n{1.upto(n*=3){|i|puts (' '*(n-i)).ljust(n+i,'/__\_\/\ \__/_/\/ '[i%3*6,6])}}

A. (-4 byte, -1 +1) đã thay đổi từ 0-indexed ( .times) thành 1-indexed ( 1.upto)

B. (-5 byte) đã thay đổi từ mảng ba chuỗi 6 char thành lựa chọn chuỗi con 6 char của chuỗi 18 char.

C. (-1 byte) m=n*3->n*=3

D. (-5 byte) đã giảm tất cả năm dấu gạch chéo kép thành dấu gạch chéo ngược đơn (một phần có thể thực hiện được bằng cách sắp xếp lại chuỗi cần thiết cho điểm A)

Ruby, 94

->n{(m=n*3).times{|i|puts (' '*(m-i-1)).ljust(m+i+1,[ '/\\ \\__','/_/\\/ ','/__\\_\\'][i%3])}}

giải trình

Đơn vị cơ bản là một viên kim cương 3x6 như sau (ký tự cuối cùng trên mỗi hàng được nhân đôi cho rõ ràng :)

    /\ \__/
   /_/\/ / 
  /__\_\/

Tất cả chúng ta cần làm là hiển thị một cửa sổ phù hợp của mẫu này. Ruby's ljustcho phép bạn đệm với bất kỳ chuỗi nào, không chỉ là khoảng trắng. Thông thường ljustsẽ được sử dụng để đệm một chuỗi các ký tự có thể in bằng cách thêm khoảng trắng ở cuối, nhưng ở đây chúng tôi sử dụng ngược lại: để đệm một chuỗi khoảng trắng bằng cách thêm các ký tự có thể in ở cuối.

vô dụng trong chương trình thử nghiệm

f=->n{
  (m=n*3).times{|i|                  #for each line of the triangle
    puts (' '*(m-i-1)).              #print m-i-1 spaces, 
      ljust(m+i+1,[ '/\\ \\__',      #left justified and padded to total length m+i+1
                   '/_/\\/ ',        #by one of these three strings
                  '/__\\_\\'][i%3])
  }
}

f[gets.to_i]

@ mbomb007 Đây là lần đầu tiên tôi có khiếu nại đó. Là một kỹ sư, tôi đã quen với việc sửa đổi mọi thứ Đây là một thử thách khá đơn giản và những cải tiến khá tầm thường, vì vậy tôi đã đi trước và xóa các thư sửa đổi. Tôi nghĩ rằng để lại mã gốc là tốt hoặc ít nhất là không có hại, vì nó dễ theo dõi hơn phiên bản hiện tại.
Cấp sông St

3
Kích thước mã thường xác định duy nhất bất kỳ sửa đổi nào, nhưng lịch sử sửa đổi cũng có sẵn cho bất kỳ ai xem lịch sử chỉnh sửa.
mbomb007

9

Võng mạc , 150 122 118 byte

Nhân tiện, kết quả cho thử thách này trông thật tuyệt vời!

Đầu vào là đơn nhất. Đầu ra chứa một linefeed trailing. Mã sử ​​dụng mã hóa ISO 8859-1. Lưu ý không gian dấu trên dòng áp chót.

(?=_\\¶.*1)
_\/__\
(?=/_/\\¶.*1)
/_/\/ 
(^|__)(?=/\\¶.*1)
$1/\ \__
ms}`(.*1*)1
/\¶/_/\¶/__\_\¶$1
m`^(?=(.*¶)*.)
$#1$* 

Dùng thử trực tuyến

Giải trình

Nếu bạn muốn một lời giải thích sâu sắc hơn, hãy bình luận hoặc nhắn tin cho tôi trong cuộc trò chuyện.

(?=_\\¶.*1)                     # Matches the start of the 3rd line of every triangle
/__\_\                          #   and prepends another layer if needed
(?=/_/\\¶.*1)                   # 2nd line of each triangle
/_/\/ 
(^|__)(?=/\\¶.*1)               # 1st line of each triangle
$1/\ \__
ms}`(.*1*)1                 # This and above in a multi-single-line loop.
/\¶/_/\¶/__\_\¶$1               #   This stage adds a flattened triangle on top
m`^(?=(.*¶)*.)                  # Prepend a space for every line following -1
$#1$* 

Cảm ơn Martin đã chơi golf 32 byte.


6

Ngôn ngữ in ascii của Tarmo, 46 ​​byte. (không cạnh tranh)

1  /\| /_/\|/__\_\2 \__|/ 0n{n-a-1{~}1a{2#1}$}

Chỉ bằng cách tìm đến những ngôn ngữ lập trình kỳ quặc như CJam, nó khiến tôi choáng váng về việc ngôn ngữ phức tạp, không tự nhiên và khó hiểu đến mức nào, tôi muốn "mạnh dạn đi đến nơi không có người đàn ông nào đi trước" và phát minh ra ngôn ngữ của mình. Kết quả là tôi đã tạo ngôn ngữ của riêng mình để in các mẫu ascii.

Ý tưởng cơ bản là bạn có thể xác định patten đầu tiên và sau đó in - sử dụng cùng loại ký tự '1' hoặc '2' hoặc bất kỳ số nào - bạn có thể xác định mẫu in của riêng mình.

Khi mẫu được xác định (Bắt đầu từ số đến hết số) - các số tiếp theo sẽ thực hiện in mẫu.

Ví dụ

1  /\| /_/\|/__\_\01

Đầu ra như thế này:

  /\
 /_/\
/__\_\

Sẽ xác định mẫu 1 và sau đó in nó ngay lập tức. Mẫu được định nghĩa mọi thứ được phân tách bằng '|' tính cách. 0 ở cuối - hoạt động như chấm dứt mẫu.

Các ký tự đặc biệt như '$' được dành riêng dưới dạng nguồn cấp dữ liệu và '~' được dành riêng cho khoảng cách - một nửa - của mẫu cụ thể.

1  /\| /_/\|/__\_\01$~11$~1~11

Sẽ xuất văn bản như thế này:

  /\
 /_/\
/__\_\
     /\
    /_/\
   /__\_\
        /\
       /_/\
      /__\_\

Tiếp theo là vòng lặp for. Cái đó cần phải dễ dàng nhìn thấy - vì vậy tôi đã giữ lại {} dấu ngoặc cho vòng lặp, nhưng tên biến được đặt tên tự động - vì vậy dấu ngoặc đầu tiên sẽ sử dụng biến 'a', giây 'b', v.v. Lặp lại sẽ luôn đi từ 0 đến số cụ thể - và số đó được xác định trước dấu ngoặc {}.

'n' là biến dành riêng cho toàn bộ đầu vào hàm.

1  /\| /_/\|/__\_\0n{1$}

Sẽ xuất ra (Với n == 4):

  /\
 /_/\
/__\_\
  /\
 /_/\
/__\_\
  /\
 /_/\
/__\_\
  /\
 /_/\
/__\_\

Và '#' là công cụ sửa đổi đặc biệt để cắt khoảng trắng chì.

Và cuối cùng là toàn bộ giải pháp:

DrawPotypes.cs:

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CSharp;

class DrawPatterns
{
//Command line parameters - for example like this: "1  /\| /_/\|/__\_\2 \__|/ 0n{n-a-1{~}1a{2#1}$}" 3
    static Dictionary<char, String[]> patterns = new Dictionary<char,string[]>();

    static string Tabs(int n)
    {
        if( n < 0 ) n = 0;

        String r = "";

        for( int i = 0; i < n ; i++ )
            r += "    ";

        return r;
    }

    static int[] left = new int[10];
    static int top = Console.CursorTop;
    static int lastTop = Console.CursorTop;

    static public void DoPrint(char c, char modifier = ' ')
    {
        if (c == '$')
        {
            for (int i = 0; i < left.Length; i++)
                left[i] = 0;
            top = lastTop + 1;
            return;
        }

        if (!patterns.ContainsKey(c))
            return;

        if (modifier == '½' || modifier == '~')
        {
            int maxSize = patterns[c].Select(x => x.Length).Max();
            for( int i = 0; i < left.Length; i++ )
                left[i] += maxSize / 2;
            return;
        }

        int iLine = 0;
        foreach (var l in patterns[c])
        {
            Console.SetCursorPosition(left[iLine], top + iLine);
            if( top + iLine > lastTop ) 
                lastTop = top + iLine;

            String s = l;
            if (modifier == '#')
                s = s.TrimStart(' ');

            Console.WriteLine(s);
            left[iLine] += s.Length;
            iLine++;
        }
    }

    static void Main(string[] _args)
    {
        List<String> args = _args.ToList();
        String todo = "";
        String code = "";
        char nextVar = 'a';
        String lf = "\r\n";
        int align = 1;
        char lastModifier = ' ';
        int nextArg = 1;
        Dictionary<String, String> argValues = new Dictionary<string,string>();
        bool bDebug = false;

        if (args.Count != 0 && args[0].ToLower() == "-d")
        {
            bDebug = true;
            args.RemoveAt(0);
        }

        if (args.Count == 0)
        {
            Console.WriteLine("Usage: DrawPatterns.cs [options] \"script\" <arguments to script>");
            Console.WriteLine("[options] allowed:");
            Console.WriteLine("-d - debug");
            return;
        }

        String prog = args[0];

        for( int i = 0; i < prog.Length; i++ )
        {
            char c = prog[i];

            // Define pattern.
            if (c >= '0' && c <= '9' && !patterns.ContainsKey(c))
            {
                String p = Regex.Match(prog.Substring(i + 1), "[^0-9]*").Groups[0].Value;
                patterns[c] = p.Split('|');
                i += p.Length;
                if( prog[i + 1] == '0' ) i++;
                continue;
            }

            String procRemain = prog.Substring(i);
            // modifier specified, but pattern number is not provided - use first pattern.
            if( lastModifier != ' ' && ( c < '0' || c > '9' ) )
            {
                code += Tabs(align);
                code += "print('1' , '" + lastModifier + "');" + lf;
                lastModifier = ' ';
            }

            switch ( c )
            {
                case '{':
                    code += Tabs(align);
                    code += "for ( int " + nextVar + " = 0; " + nextVar + " < " + todo + " ; " + nextVar + "++ )" + lf;

                    //  Check for all variable names if they can be used in program.
                    foreach ( var m in Regex.Matches(todo, "[a-zA-Z_][a-zA-Z0-9_]*", RegexOptions.Singleline) )
                    {
                        String varName = m.ToString();

                        if( varName.Length == 1 && varName[0] <= nextVar )
                            // Already declared as a loop.
                            continue;

                        if( argValues.ContainsKey(varName ) )
                            continue;

                        if( nextArg >= args.Count )
                        {
                            Console.WriteLine("Insufficient parameters provided to script - argument '" + varName + "' value is needed");
                            return;
                        }

                        argValues[varName] = args[nextArg];
                        nextArg++;
                    }


                    code += Tabs(align);
                    code += "{" + lf;
                    nextVar++;
                    todo = "";
                    align++;
                    break;

                case '}':
                    align--;
                    code += Tabs(align);
                    code += "}" + lf;
                    break;

                default:
                    if (((c >= '0' && c <= '9') || c == '<' || c == '$') && todo == "")
                    {
                        code += Tabs(align);
                        code += "print('" + c + "' , '" + lastModifier + "');" + lf;
                        lastModifier = ' ';
                        continue;
                    }

                    if (c == '½' || c == '~' || c == '#')
                    {
                        lastModifier = c;
                        continue;
                    }

                    if( c == '\r' || c == '\n' )
                        continue;

                    todo += c;
                    break;
            }

        } //for

        String code2 = "";
        code2 += "using System;" + lf;
        code2 += "public class ExecClass { static void Exec( Action<char, char> print";

        object[] invokeArgs = new object[ argValues.Count+1];
        invokeArgs[0] = new Action<char, char>(DoPrint);
        int iValueIndex = 1;

        foreach ( var kv in argValues )
        {
            code2 += ",";
            code2 += "int " + kv.Key;
            invokeArgs[iValueIndex] = Int32.Parse(kv.Value);
            iValueIndex++;
        }

        code2 += ") {" + lf;
        code2 += code;
        code2 += "} };";

        if( bDebug )
        {
            int line = 1;
            String lineNumberedCode =Regex.Replace(code2, "^(.*)$", 
                delegate(Match m) { return (line++).ToString("d2") + ": " + m.Value; },
                RegexOptions.Multiline
            );
            Console.WriteLine(lineNumberedCode);
            Console.WriteLine();
            Console.WriteLine();
        }

        left[0] = Console.CursorLeft;
        for( int i = 1; i < left.Length; i++ )
            left[i] = left[0];
        top = Console.CursorTop;

        try
        {
            var compileResult = new CSharpCodeProvider().CompileAssemblyFromSource( new CompilerParameters() { GenerateExecutable = false, GenerateInMemory = true }, code2);
            if (compileResult.Errors.HasErrors)
            {
                foreach (CompilerError ce in compileResult.Errors)
                {
                    if (ce.IsWarning) continue;
                    Console.WriteLine("{0}({1},{2}: error {3}: {4}", ce.FileName, ce.Line, ce.Column, ce.ErrorNumber, ce.ErrorText);
                }
                return;
            }

            var method = compileResult.CompiledAssembly.GetType("ExecClass").GetMethod("Exec", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
            method.Invoke(null, invokeArgs);

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        Console.SetCursorPosition(1, lastTop);
        Console.WriteLine();
        Console.WriteLine();
    } //Main
}

Với các đối số dòng lệnh như thế này: -d "1 / \ | / _ / \ | / ___ \ 2 __ | / 0n {na-1 {½} 1a {2 # 1} $}" 3

Sẽ xuất kết quả này:

01: using System;
02: public class ExecClass { static void Exec( Action<char, char> print,int n) {
03:     for ( int a = 0; a < n ; a++ )
04:     {
05:         for ( int b = 0; b < n-a-1 ; b++ )
06:         {
07:             print('1' , '~');
08:         }
09:         print('1' , ' ');
10:         for ( int c = 0; c < a ; c++ )
11:         {
12:             print('2' , ' ');
13:             print('1' , '#');
14:         }
15:         print('$' , ' ');
16:     }
17: } };


        /\
       /_/\
      /__\_\
     /\ \__/\
    /_/\/ /_/\
   /__\_\/__\_\
  /\ \__/\ \__/\
 /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\

1
Điều đó thực sự tuyệt vời! Bạn nên đưa nó lên Github và khuyến khích mọi người sử dụng nó!
DJMcMayhem

3
Chào mừng bạn đến với Câu đố lập trình và Code Golf! Thật tuyệt khi bạn đã phát minh ra ngôn ngữ lập trình của riêng mình, nhưng phiên bản mới nhất có thể chạy trước thách thức không?
Ad Nam

Không hiểu bạn hoàn toàn, bạn đang nói gì?
TarmoPikaro

Chà, nếu bản thân ngôn ngữ mới hơn thách thức, người ta thường đánh dấu nó là không cạnh tranh (khá logic phải;)). Đây có thể là một bài viết có liên quan.
Ad Nam

Ngôn ngữ phụ thuộc vào miền vấn đề và tôi không biết vấn đề đó tồn tại trước khi tôi đọc nó từ đây. Tôi đoán tôi có thể mã ngôn ngữ sớm hơn nếu tôi gặp vấn đề tương tự. Dù sao đi nữa, bằng cách thu hoạch trang web này, tôi đã hiểu rằng CJam là ngôn ngữ khá "bình thường" ở đây. :)
TarmoPikaro

5

JavaScript (ES6), 119 byte

n=>`,/\\ \\__,/_/\\/ ,/__\\_\\`[r=`repeat`](n).split`,`.map((s,i)=>` `[r](n*3-i)+s[r](n).slice(0,i*2)).slice(1).join`\n`

Trường hợp \nđại diện cho nhân vật dòng chữ mới. Nếu một dòng hàng đầu có n*3khoảng trắng và một dòng mới được chấp nhận thì .slice(1)có thể loại bỏ dòng này để tiết kiệm 9 byte.



2

Python 2, 142 byte

def f(n,m):return f(n-1,m+3)+[' '*(m+x)+(y*n)[x*2:]for x,y in((2,' \\__/\\'),(1,'/ /_/\\'),(0,'/__\\_\\'))]if n else[]
print '\n'.join(f(n,0))

Nguyên tắc này rất giống với các câu trả lời khác: lấy ba chuỗi lặp lại và sau đó xếp chúng theo cách mà bạn chỉ cần cắt một số trong số chúng để có được hình tam giác, sau đó đệm chúng ở bên trái.


2

C ++, 395 byte

Golf mã lần đầu tiên với kích thước vinh quang 395 byte trong C ++. Trong trường hợp của tôi, nó cảm thấy giống như một cuộc thi dành cho obfuscation: D

#include <iostream>
#include <cstring>
#define A for (int k=0;k<((s-(i+1))*3+(2-j));k++) cout<<" ";
using namespace std; string t[3]={"/\\","/_/\\","/__\\_\\"};string r[2]={" \\__","/ "};int tr=3;int main(int,char**argv){int s=atoi(argv[1]);for(int i=0;i<s;i++){for(int j=0;j<tr;j++){A for(int l=1;l<=2*(i+1)-1;l++){if((l%2)==0&&(j<2)){cout<<r[j];}else if ((l%2)==1)cout<<t[j];}A cout<<endl;}}}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.