Tôi đang ở đâu?


21

Tôi đang ở đâu?

Đưa ra một chuỗi d, chỉ chứa các chữ cái NSWE, xác định tọa độ tôi đã đi (từ trái sang phải, tiêu thụ một cách tham lam) và tọa độ cuối cùng nơi tôi cư trú.

Các quy tắc đọc tọa độ từ trái sang phải:

  • Nếu ký tự tiếp theo là NhoặcS :
    • Nếu ký tự sau Nhoặc Slà khác NhoặcS :
      • Chỉ tiêu thụ đầu tiên Nhoặc S.
      • Đầu ra [0,1] choN
      • Đầu ra [0,-1]choS
    • Nếu ký tự sau Nhoặc SWhoặcE :
      • Tiêu thụ cả Nhay SWhay E.
      • Đầu ra [1,1]hoặc [-1,1]cho NENW, tương ứng.
      • Đầu ra [1,-1]hoặc [-1,-1]cho SESW, tương ứng.
  • Nếu ký tự là một Ehoặc Wkhông có trước ShoặcN :
    • Tiêu thụ Ehay W.
    • Đầu ra [1,0]cho E.
    • Đầu ra [-1,0]cho W.

Ví dụ làm việc

NSWE

[0,1]   (North      N)
[-1,-1] (South-west SW)
[1,0]   (East       E)
[0,0]   (N+SW+E = Didn't actually move)

Lưu ý điều này có thể ở bất kỳ định dạng nào, đây là các ví dụ khác về đầu ra hợp lệ:

[[0,1],[-1,-1],[1,0],[0,0]]


[[[0,1],[-1,-1],[1,0]],[0,0]]


"0,1\n0,-1\n-1,0\n1,0\n0,0"

V.v ...


Thêm ví dụ

SWSENNESWNE

[-1,-1]
[1,-1]
[0,1]
[1,1]
[-1,-1]
[1,1]
[1,0]

NNEESESSWWNW

[0,1]
[1,1]
[1,0]
[1,-1]
[0,-1]
[-1,-1]
[-1,0]
[-1,1]
[0,0]

NENENEE

[1,1]
[1,1]
[1,1]
[1,0]
[4,3]

KHÔNG

[1,1]
[0,1]
[1,2]

EEE

[1,0]
[1,0]
[1,0]
[3,0]

Quy tắc

  • Bạn có thể xuất ra ở bất kỳ định dạng thuận tiện nào không vi phạm sơ hở.
  • Bạn phải tiêu dùng một cách tham lam, NWEkhông bao giờ N,W,E, nó luôn luôn NW,E.
    • Này áp dụng cho: SW*, SE*, NW*, NE*.
    • Bạn đang tiêu thụ từ trái sang phải, tham lam.
  • Đây là , số byte thấp nhất sẽ thắng.

"Xác định tọa độ tôi đã đi" : Tôi không chắc liệu nó có thực sự khớp với những gì được mô tả sau đó không. Nó giống như "xác định các vectơ của tất cả các bước di chuyển của tôi" . Chỉ có đầu ra cuối cùng là tọa độ thực tế.
Arnauld

1
Một trường hợp thử nghiệm đi đến [4, 3]hoặc như vậy sẽ giúp dễ dàng hơn để xem những gì đang diễn ra trong đầu ra thử nghiệm.
Lynn

3
Được số phức được định dạng như 1, -1j, (-1+1j)vv một định dạng đầu ra hợp lệ?
Lynn

2
Dựa trên sự vắng mặt của trường hợp này trong cả các quy tắc và ví dụ được đưa ra, tôi cho rằng Chuỗi đầu vào sẽ không bao giờ kết thúc bằng 'N' hoặc 'S'?
Kevin Cruijssen

1
Là tiêu dùng tham lam thực sự khác nhau hơn không? Vì NEchỉ là N+Enó không quan trọng?
Thuật sĩ lúa mì

Câu trả lời:


7

Python 2 , 116 byte

import re
a=[(int(s,35)%5-3,('N'in s)-('S'in s))for s in re.findall('[NS][EW]?|.',input())]
print a,map(sum,zip(*a))

Hãy thử trực tuyến!

Với đầu ra là [(3+4j), 1, -1j, …], 91 byte

lambda x:[sum(1j**(ord(c)%8%5)for c in s)for s in[x]+re.findall('[NS][EW]?|.',x)]
import re

Hãy thử trực tuyến!

Lambda này trả về một danh sách các số nguyên Gaussian : đầu tiên là tọa độ cuối cùng và tất cả các bước khác là các bước cần thiết để đạt được điều đó.


5

Tùy viên , 80 byte

V#Sum##{Chop[1-ToBase[22260446188,3],2][Sum@Ords=>MatchAll[_,/"[NS][WE]|."]%11]}

Hãy thử trực tuyến!

Đây là một hàm ẩn danh có một đối số chuỗi.

Giải trình

Nhiệm vụ đầu tiên là thực hiện giai đoạn phân tích cú pháp của câu hỏi này. Tôi thấy nó ngắn nhất để sử dụng một Regex đơn giản để phân tích cú pháp đầu vào ( _):

MatchAll[_,/"[NS][WE]|."]

Điều này phù hợp với tất cả các lần xuất hiện của regex [NS][WE]|., như đã thấy trong nhiều câu trả lời khác. Điều này tham lam mang lại các hướng yêu cầu.

Bây giờ, chúng ta sẽ áp dụng hàm băm cho mỗi direciton. Chúng tôi lấy các mật mã của mỗi hướng và tổng hợp chúng. Điều này đưa ra ánh xạ sau:

Direction       Ord-sum
E               69
N               78
S               83
W               87
NE              147
SE              152
NW              165
SW              170

Chúng ta sẽ cố gắng ánh xạ các giá trị này sang một miền nhỏ hơn; modulo rất hữu ích cho việc này và chúng ta có thể chứng minh rằng modulo nhỏ nhất dẫn đến các giá trị duy nhất cho tất cả các đầu vào đã cho là 11. Sắp xếp theo số dư, điều này cho chúng ta bảng sau:

Direction       Ord-sum         % 11
NW              165             0
N               78              1
E               69              3
NE              147             4
SW              170             5
S               83              6
SE              152             9
W               87              10

Bây giờ, chúng ta có một sự tương ứng đầu vào, như mã hóa bởi Sum@Ords=>[...]%11. Tiếp theo, chúng ta phải biến những phần còn lại thành điểm. Chúng ta sẽ cố gắng rút ra một ánh xạ khác, có nghĩa là chèn "các giá trị lấp đầy thưa thớt" vào các giá trị băm không tương ứng với các hướng sẽ hữu ích:

Direction       Hash        Coordinates
NW              0           [-1, 1]
N               1           [0, 1]
--             (2)          [0, 0]
E               3           [1, 0]
NE              4           [1, 1]
SW              5           [-1, -1]
S               6           [0, -1]
--             (7)          [0, 0]
--             (8)          [0, 0]
SE              9           [1, -1]
W               10          [-1, 0]

Chúng tôi hiện có một loạt các điểm, có thể đưa ra một danh sách có thể lập chỉ mục bằng hàm băm:

[-1, 1] [0, 1] [0, 0] [1, 0] [1, 1] [-1, -1] [0, -1] [0, 0] [0, 0] [1, -1] [-1, 0]

Bây giờ, chúng ta sẽ nén cái này, xem như nó chỉ bao gồm -1s, 0s và 1s. Vì danh sách đại diện cho các cặp, chúng tôi có thể làm phẳng danh sách mà không mất dữ liệu. Sau đó, nếu chúng ta lấy từng số xvà tính toán 1-x, chúng ta sẽ nhận được danh sách sau:

2 0 1 0 1 1 0 1 0 0 2 2 1 2 1 1 1 1 0 2 2 1

Chúng ta có thể chuyển đổi số này thành số 3 cơ sở:

20101101002212111102213

Chuyển đổi sang cơ sở 10:

20101101002212111102213 ≡ 2226044618810

Để tóm tắt, chúng tôi đã lấy điểm của chúng tôi, bỏ ghép chúng, lấy từng phần tử được trừ 1và chuyển đổi từ cơ sở 3, cho chúng tôi 22260446188. Chúng ta có thể giải nén như vậy:

  1. Chuyển đổi sang cơ sở 3: ToBase[22260446188,3]
  2. Lấy mỗi số bị trừ từ một (tự đảo ngược): 1-ToBase[22260446188,3]
  3. Ghép nối lại danh sách: Chop[1-ToBase[22260446188,3],2]

Điều này cho chúng ta bộ cặp ban đầu của chúng tôi. Sau đó, chúng ta có thể thực hiện việc lập chỉ mục nói trên như sau:

(chopped value)[hashes]

Vì, trong Attache, lập chỉ mục theo một mảng trả về tất cả các phần tử tương ứng với các chỉ mục đó. (Vì vậy [1,2,3,4][ [0,0,-1,1] ] = [1,1,4,2],.) Bây giờ, chúng ta có hướng của con đường mà OP đã đi. Những gì còn lại là để tính tổng.

Vì vậy, chúng tôi nắm bắt kết quả này trong lambda {...}và đặt nó làm hàm đầu tiên trong thành phần hàm ( a##b), với hàm thứ hai V#Sum. Đây là một ngã ba, mà, đầu vào đã cho x, mở rộng thành:

V[x, Sum[x]]

Sum, khi được cung cấp một mảng 2D, sẽ xảy ra tính tổng mỗi cột trong mảng (là kết quả của tổng hợp véc tơ). Vì vậy, điều này ghép các hướng với đích đến cuối cùng và chúng ta có kết quả cuối cùng.


4

JavaScript (ES6), 102 byte

Trả về một chuỗi.

s=>s.replace(/[NS][EW]|./g,s=>(D=d=>!!s.match(d),x+=h=D`E`-D`W`,y+=v=D`N`-D`S`,[h,v]+`
`),x=y=0)+[x,y]

Hãy thử trực tuyến!


Tôi thích việc sử dụng các chức năng mẫu! : D
Conor O'Brien

@ ConorO'Brien Vâng, chúng khá tiện dụng ở đây. Tất cả các phép thuật băm băm mà tôi đã triệu tập cho đến nay ít nhất là lâu hơn một chút.
Arnauld

4

MATL , 45 byte

'NS' 'WE'Z*Z{2MhX{h'eklihfmj'X{YX9\3_2&YAqts

Hãy thử trực tuyến! Hoặc xác minh tất cả các trường hợp thử nghiệm .

Giải thích (ví dụ)

Hãy xem xét đầu vào 'NSWE'là một ví dụ.

'NS' 'WE'  % Push these two strings
           % STACK: 'NS', 'WE'
Z*         % Cartesian product. Gives a 4×2 char matrix
           % STACK: ['NW'; 'NE'; 'SW'; 'SE']
Z{         % Cell array of rows (strings)
           % STACK: {'NW', 'NE', 'SW', 'SE'}
2M         % Push again the inputs of the second-last function call
           % STACK: {'NW', 'NE', 'SW', 'SE'}, 'NS', 'WE'
h          % Concatenate horizontally
           % STACK: {'NW', 'NE', 'SW', 'SE'}, 'NSWE'
X{         % Cell array of individual elements (chars)
           % STACK: {'NW', 'NE', 'SW', 'SE'}, {'N', 'S', 'W', 'E'}
h          % Concatenate horizontally
           % STACK: {'NW', 'NE', 'SW', 'SE', 'N', 'S', 'W', 'E'}
'eklihfmj' % Push this string
           % STACK: {'NW', 'NE', 'SW', 'SE', 'N', 'S', 'W', 'E'}, 'eklihfmj'
X{         % Cell array of individual elements (chars)
           % STACK: {'NW','NE','SW','SE','N','S','W','E'},{'e','k','l','i','h','f','m','j'}
YX         % Implicit input. Regexp replace: replaces 'NW' by 'e', then 'NE' by 'k', etc.
           % Note that the two-letter combinations are replaced first, which implements
           % the greediness; and the target letters do not appear in the source, which
           % avoids unwanted interactions between replacements
           % STACK: 'hlj'
9\         % Modulo 9 (of codepoints), element-wise
           % STACK: [5, 0, 7]
3_2&YA     % Convert to base 3 with 2 digits. Gives a 2-column matrix
           % STACK: [1, 2; 0, 0; 2, 1]
q          % Subtract 1, element-wise
           % STACK: [0, -1; -1, -1; 1, 0]
tXs        % Duplicate. Sum of each column
           % STACK: [0, -1; -1, -1; 1, 0], [0, 0]
           % Implicit display

4

Java (JDK 10) , 171 byte

s->{var r="";int i=0,l=s.length,c,x=0,y=0,Y,X;for(;i<l;X=c>1||i<l&&(c=~-s[i]/6%4)>1&&++i>0?c*2-5:0,r+=X+","+Y+" ",x+=X,y+=Y)Y=(c=~-s[i++]/6%4)<2?1-c*2:0;return r+x+","+y;}

Hãy thử trực tuyến!

Giải thích

Nhờ c=~-s[i]/6%4, ánh xạ sau đây được thực hiện:

'N' -> ascii: 78 -> -1 = 77 -> /6 = 12 -> %4 = 0
'S' -> ascii: 83 -> -1 = 83 -> /6 = 13 -> %4 = 1
'W' -> ascii: 87 -> -1 = 86 -> /6 = 14 -> %4 = 2
'E' -> ascii: 69 -> -1 = 68 -> /6 = 11 -> %4 = 3
  • NSđược kiểm tra c<2và ánh xạ tới +1/ -1sử dụng 1-c*2;
  • EWđược kiểm tra c>1và ánh xạ tới +1/ -1sử dụng c*2-5.

Tín dụng


Ah, bạn đã đăng câu trả lời Java của bạn trong khi tôi đang gõ lời giải thích của tôi. :) Vì cả hai chúng tôi sử dụng một cách tiếp cận hoàn toàn khác nhau nên tôi sẽ rời khỏi bây giờ. Các biến quá xấu được sử dụng trong lambdas cần phải có hiệu quả cuối cùng, nếu không bạn có thể đã trả về một Chuỗi thay vì Danh sách để lưu byte.
Kevin Cruijssen

Cảm ơn, nó chỉ lưu một vài byte (4), nhưng tốt hơn là không có gì;)
Olivier Grégoire

@KevinCruijssen Cảm ơn, ban đầu có vẻ khá rõ ràng, nhưng tôi đã thực hiện một cách tiếp cận khác làm giảm số lượng byte của tôi hơn 30. Một cách "phân tích cú pháp", không phải là "khớp".
Olivier Grégoire

1
Thở dài .. 172 byte
Kevin Cruijssen

1
@KevinCruijssen Xin lỗi, đó là một mớ hỗn độn tích hợp các thay đổi của bạn ... Tôi đã làm việc và tôi quên làm mới trang này ... Cảm ơn vì tất cả mọi thứ ^^ 'Số tín dụng rất có thể thấp hơn tín dụng thực tế của bạn. Xin lỗi vì điều đó quá: s
Olivier Grégoire

3

Võng mạc 0.8.2 , 93 byte

.+
$&¶$&
\G[NS]?[EW]?
$&¶
G`.
W
J
%O`.
+`EJ|NS

m`^((J)?[EJ]*)((S)?[NS]*)
$#2$*-$.1,$#4$*-$.3

Hãy thử trực tuyến! Giải trình:

.+
$&¶$&

Nhân đôi đầu vào.

\G[NS]?[EW]?
$&¶

Chia bản sao đầu tiên thành các hướng.

G`.

Loại bỏ các dòng trống bên ngoài được tạo bởi quá trình trên.

W
J

Thay đổi Wthành Jsao cho nó sắp xếp giữa EN. (Di chuyển Eđến giữa SWcũng sẽ làm việc.)

%O`.

Sắp xếp từng dòng theo thứ tự.

+`EJ|NS

Xóa các cặp hướng ngược lại (điều này chỉ ảnh hưởng đến dòng cuối cùng của khóa học).

m`^((J)?[EJ]*)((S)?[NS]*)
$#2$*-$.1,$#4$*-$.3

Đếm số lượng chuyển động ngang và dọc, thêm các dấu hiệu khi cần thiết.

Những người bạn biết sự khác biệt giữa Retina 0.8.2 và Retina 1 sẽ muốn chỉ ra rằng tôi có thể lưu 2 byte trong Retina 1 vì nó sử dụng *thay vì $*. Trong khi tôi ở đó, tôi đã cố gắng đơn giản hóa quá trình phân tách nhưng tôi không thể giảm số byte hơn nữa, tôi chỉ có thể cân bằng với điều này:

L$`$(?<=(.*))|[NS]?[EW]?
$&$1

3

Java 10, 269 265 243 byte

s->{var r="";int x=0,y=0,t,X,Y,a;for(;!s.isEmpty();r+=X+"|"+Y+" ",s=s.substring(++t),x+=X,y+=Y){a=s.charAt(t=0);if(s.matches("[SN][WE].*")){X=s.charAt(1)<70?1:-1;Y=1-a%2*2;t++;}else{X=a<70?1:a>86?-1:0;Y=a>69&a<87?1-a%2*2:0;}}return r+x+"|"+y;}

Chắc chắn không phải là ngôn ngữ phù hợp cho thử thách này ..

Hãy thử trực tuyến.

Giải trình:

s->{                  // Method with String as both parameter and return-type
  var r="";           //  Result-String, starting empty
  int x=0,            //  Ending `x`-coordinate, starting at 0
      y=0,            //  Ending `y`-coordinate, starting at 0
      t,X,Y,a;        //  Temp-integers
  for(;!s.isEmpty()   //  Loop as long as the input-String is not empty yet
      ;               //    After every iteration:
       r+=X+"|"+Y+" ",//     Append the current steps to the result-String
       s=s.substring(t),
                      //     Remove the first `t` characters from the input-String
       x+=X,y+=Y){   //      Append the ending `x`,`y` coordinates with the steps
    a=s.charAt(0);   //    Set `a` to the first character of the input-String to save bytes
    t=1;             //    Set `t` to 1
    if(s.matches("[SN][WE].*")){
                     //   Else-if the input-String starts with N/S followed by E/W:
      X=s.charAt(1)<70?1:-1;
                     //    Set `X` to 1 if 'E', -1 if 'W'
      Y=1-a%2*2;     //    Set `Y` to 1 if 'N', -1 if 'S'
      t++;}          //    Increase `t` by 1
    else{            //   Else:
      X=a<70?1:a>86?-1:0;
                     //    Set `X` to 1 if 'E', -1 if 'W', 0 if 'N' or 'S'
      Y=a>69&a<87?1-a%2*2:0;}}
                     //    Set `Y` 1 if 'N', -1 if 'S', 0 if 'E' or 'W'
  return r+x+"|"+y;} //  Append the ending coordinates, and return the result-String

1
Các câu trả lời Java nhận được điểm mặc dù mọi người đều hiểu chúng :).
Bạch tuộc ma thuật Urn

@MagicOctopusUrn Đúng. :) Và tôi vẫn thích chơi golf trong Java, mặc dù bạn sẽ không bao giờ là người ngắn nhất .. Trừ khi bạn là người duy nhất trả lời (có hai câu trả lời Java được chấp nhận .. XD). Tuy nhiên, đối với thử thách này, câu trả lời Java của OlivierGrégoire ngắn hơn khoảng 70 byte, vì vậy hầu hết các upvote nên đến với anh ta.
Kevin Cruijssen


2

JavaScript (ES6), 102 byte

f=
s=>s.replace(/((N)|(S))?((E)|(W))?/g,(m,v,n,s,h,e,w)=>(x+=h=!w-!e,y+=v=!s-!n,m?[h,v]+`
`:[x,y]),x=y=0)
<input oninput=o.textContent=/[^NSEW]/.test(this.value)?``:f(this.value)><pre id=o>0,0

Trả về một chuỗi.


1

Ruby , 75 71 byte

->x{[*x.scan(/[NS][EW]?|./),x].map{|s|s.chars.sum{|c|1i**(c.ord%8%5)}}}

Hãy thử trực tuyến!

-4 byte nhờ benj2240.

Vì việc trả về các số phức có vẻ là một định dạng đầu ra có thể chấp nhận được, tôi đoán nó sẽ không trở nên golf hơn nhiều so với việc tạo ra một câu trả lời rất hay của Lynn .


Rất đẹp. bạn có thể lưu một vài byte bằng cách bỏ qua phần bên trong map, chuyển trực tiếp khối của nó tới sum: Dùng thử trực tuyến!
benj2240

1

F # (Mono) , 269 byte

let f s=
 let l,h=(string s).Replace("NW","A").Replace("NE","B").Replace("SW","C").Replace("SE","D")|>Seq.map(function 'N'->0,1|'S'->0,-1|'W'-> -1,0|'E'->1,0|'A'-> -1,1|'B'->1,1|'C'-> -1,-1|'D'->1,-1)|>Seq.mapFold(fun(x,y) (s,t)->(s,t),(x+s,y+t))(0,0)
 Seq.append l [h]

Hãy thử trực tuyến!


Xin chào, chào mừng đến với PPCG. Thật không may, bạn đang thiếu mục cuối cùng của đầu ra, đó là vị trí mà bạn đã kết thúc. Vì vậy, đối với NSWEhiện tại bạn đang xuất ra (0,1), (-1,-1), (1,0), nhưng một đầu ra thứ tư sẽ là tổng của những tọa độ, vì vậy (0,0)(vì 0+-1+1 = 01+-1+0 = 0).
Kevin Cruijssen

@KevinCruijssen OK, tôi đã không nắm bắt được điều đó. Thực hiện một bản cập nhật.
Henrik Hansen

1
Có vẻ như bây giờ làm việc tuyệt vời, vì vậy +1 từ tôi. Tận hưởng kì nghỉ của bạn! :) Và trong trường hợp bạn chưa nhìn thấy nó, Mẹo chơi golf trong F #Mẹo chơi gôn bằng <tất cả các ngôn ngữ> có thể rất thú vị để đọc qua.
Kevin Cruijssen

1

sed, 125

Các quyền tự do với phiên bản định dạng đầu ra :

Điểm bao gồm +1 cho -rtham số sed.

s/(N|S)(E|W)/\L\2,\1 /g
s/N|S/,& /g
s/E|W/&, /g
s/N|E/A/gi
s/S|W/a/gi
p
:
s/(\S*),(\S*) (\S*),(\S*)/\1\3,\2\4/
t
s/Aa|aA//
t

Hãy thử trực tuyến .

Đầu ra như sau:

  • các phần tử tọa độ được phân tách bằng dấu phẩy
  • mỗi bộ tọa độ được phân tách bằng TAB
  • tọa độ cuối cùng là trên một dòng mới
  • tất cả các số đều trong-unary:
    • một chuỗi Aký tự đại diện cho số nguyên + velen(string)
    • một chuỗi aký tự đại diện cho số nguyên -ve-len(string)
    • chuỗi rỗng đại diện 0

Ví dụ:

  • , là [0,0]
  • ,AA là [0,2]
  • aaa, là [-3,0]

sed 4.2.2 bao gồm phần mở rộng GNU exec , 147

Các hợp lý định dạng đầu ra phiên bản:

Điểm bao gồm +1 cho -rtham số sed.

s/(N|S)(E|W)/\L\2 \1\n/g
s/N|S/0 &\n/g
s/E|W/& 0\n/g
s/N|E/1/gi
s/S|W/-1/gi
p
:
s/(\S+) (\S+)\n(\S+) (\S+)/\1+\3 \2+\4/
t
s/\S+/$[&]/g
s/^/echo /e

Đầu ra được đưa ra dưới dạng tọa độ phân tách không gian, mỗi tọa độ trên một dòng. Có một dòng mới bổ sung giữa các tọa độ áp chót và cuối cùng - không chắc đó có phải là vấn đề hay không.

Hãy thử trực tuyến!


0

PHP, 153 byte

hãy để một regex thực hiện việc chia tách; lặp qua các trận đấu, in và tổng hợp các kết quả trung gian:

preg_match_all("/[NS][EW]?|E|W/",$argn,$m);foreach($m[0]as$s){$x+=$p=strtr($s[-1],NEWS,1201)-1;$y+=$q=strtr($s[0],NEWS,2110)-1;echo"$p,$q
";}echo"$x,$y";

Chạy như ống với -nRhoặc thử trực tuyến .


0

C (gcc) , 173 byte

Thật thú vị khi thực hiện điều này bằng một ngôn ngữ không có hỗ trợ regex!

f(char*s){char*t="[%d,%d]\n";int x[4]={0},i;for(;*s;*x=x[1]=!printf(t,x[1],*x))for(i=-1;i<5;)if(*s=="S NW E"[++i]){x[i/3+2]+=x[i/3]=i%3-1;i+=2-i%3;s++;}printf(t,x[3],x[2]);}

Hãy thử trực tuyến!


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.