Hai Nama saya Dmitry Andriyanov, saya bekerja sebagai pengembang antarmuka di Yandex. Tahun lalu saya berpartisipasi dalam persiapan kompetisi front end online kami.

Beberapa hari yang lalu saya menerima surat dari panitia yang menanyakan apakah saya ingin berpartisipasi lagi - untuk membuat tugas-tugas frontend untuk kejuaraan pemrograman kedua . Saya setuju - dan berpikir itu adalah topik yang menarik untuk artikel ini. Tuang kopi, duduk. Saya akan memberi tahu Anda bagaimana kami menyiapkan tugas setahun yang lalu.
Ada sekitar sepuluh dari kita, hampir semuanya adalah pengembang front-end dari berbagai layanan Yandex. Kami harus memilih tugas yang akan diperiksa oleh autotests.
Untuk kompetisi pemrograman, ada layanan khusus - Yandex.Contest . Di sana Anda dapat mempublikasikan tugas, dan peserta mendaftar dan menyelesaikannya. Pengujian tugas berlangsung secara otomatis, hasil peserta diterbitkan dalam tabel khusus. Dengan demikian, infrastruktur sudah siap. Yang dibutuhkan hanyalah membuat tugas. Tetapi ternyata ada satu peringatan. Sebelumnya, Yandex mengadakan kompetisi dalam algoritma, pembelajaran mesin, dan topik lainnya, tetapi tidak pernah di kompetisi front-end. Tidak ada yang memiliki pemahaman tentang apa yang harus terdiri dari kompetisi dan bagaimana mengotomatiskan verifikasi.

Kami memutuskan bahwa untuk pengembang front-end, tugas yang memerlukan tata letak, JavaScript, dan pengetahuan tentang API browser cocok. Layout dapat diperiksa dengan membandingkan tangkapan layar. Tugas algoritma dapat dijalankan di Node.js dan diverifikasi dengan membandingkan hasilnya dengan jawaban yang benar. Program yang berfungsi dengan API browser dapat diluncurkan melalui Puppeteer dan skrip dapat memeriksa status halaman setelah eksekusi.
Kompetisi terdiri dari dua putaran - kualifikasi dan final, dengan 6 tugas di setiap babak. Tugas kualifikasi harus bervariasi sehingga peserta yang berbeda mendapatkan opsi yang berbeda. Kami memilih jumlah dan jenis tugas untuk setiap putaran, dibagi menjadi tim yang terdiri dari dua orang dan membagikan tugas antar tim. Setiap kelompok harus datang dengan dua masalah variatif untuk kualifikasi dan dua tugas non-variasional untuk final.

Mari klik pada elemen DOM ...
Idenya muncul - untuk memberikan permainan browser, di mana Anda perlu mengklik elemen DOM, sebagai salah satu tugas variabel. Tugas peserta adalah menulis program yang memainkan permainan ini dan menang. Diciptakan 4 opsi:
Jika mau, Anda bisa mengikuti tautan dan bermain. Jika Anda memainkan "telepon" atau "piano", jangan lupa nyalakan suaranya.
Tulis bagian umum untuk semua opsi. Isinya logika untuk menampilkan elemen yang dapat diklik, serta elemen dengan informasi tentang di mana untuk mengklik (catatan, angka tulisan tangan, kartu dengan gambar dan warna). Kumpulan informasi dan elemen yang dapat diklik ditetapkan melalui parameter.
Penampilannya dikendalikan melalui CSS. Ternyata sangat mirip dengan csszengarden.com - satu tata letak dengan gaya berbeda terlihat berbeda.




Hasil dari program peserta adalah log klik pada elemen. Menambahkan pawang yang menulis informasi tentang item yang diklik ke variabel global. Sehingga peserta, bukannya klik jujur, tidak bisa langsung menulis hasilnya ke variabel ini, kami memberikan namanya di luar.
function initGame(targetClasses, keyClasses, resultName) {
Skrip untuk menjalankan program peserta adalah seperti ini:
Tambahkan suara
Kami memutuskan bahwa kami perlu menghidupkan kembali permainan dengan telepon sedikit dan menambahkan suara penekanan tombol. Suara seperti itu disebut nada DTMF . Menemukan artikel tentang cara menghasilkannya. Singkatnya, perlu memainkan dua suara secara bersamaan dengan frekuensi yang berbeda. Suara frekuensi tertentu dapat diputar menggunakan API Audio Web . Hasilnya adalah sesuatu seperti kode ini:
function playSound(num) {
Suara juga telah ditambahkan untuk memainkan piano. Jika ada peserta mencoba memainkan catatan yang tertulis di halaman, dia akan mendengar pawai kekaisaran dari Star Wars.

Mari menyulitkan tugas
Kami bersukacita atas tugas keren yang kami lakukan, tetapi sukacita itu tidak berlangsung lama. Selama pengujian game, ternyata program mengklik tombol sangat cepat dan semua suara keren kami bergabung menjadi kekacauan umum. Kami memutuskan untuk menambahkan penundaan 50 ms antara penekanan tombol, sehingga suara diputar secara bergantian. Pada saat yang sama, tugas ini sedikit rumit.
function initGame(targetClasses, keyClasses, resultName) {
Tapi itu belum semuanya. Kami berpikir bahwa peserta dapat dengan mudah melihat kode sumber dan segera melihat penundaan. Untuk mempersulit tugas mereka, kami mengecilkan semua kode JS pada halaman menggunakan UglifyJS . Tetapi perpustakaan ini tidak mengubah API kelas publik. Oleh karena itu, bagian-bagian yang UglifyJS meninggalkan sama (yaitu, nama-nama metode dan bidang kelas), kami diganti melalui replace
.
Script untuk kebingungan permainan terlihat seperti ini:
const minified = uglifyjs.minify(lines.join('\n')); const replaced = minified.code .replaceAll('this.window', 'this.') .replaceAll('this.document', 'this.') .replaceAll('this.log', 'this.') .replaceAll('this.lastClick', 'this.') .replaceAll('this.target', 'this.') .replaceAll('this.resName', 'this.') .replaceAll('this.audioContext', 'this.') .replaceAll('this.keyCount', 'this.') .replaceAll('this.classMap', 'this.') .replaceAll('_createDiv', '_') .replaceAll('_renderTarget', '_') .replaceAll('_renderKeys', '_') .replaceAll('_updateLog', '_') .replaceAll('_generateAnswer', '') .replaceAll('_createKeyElement', '') .replaceAll('_getMessage', '') .replaceAll('_next', '_____') .replaceAll('_pos', '__') .replaceAll('PhoneGame', '') .replaceAll('MusicGame', '') .replaceAll('BaseGame', 'xyz');
Mari kita tulis kondisi kreatif
Kami menyiapkan bagian teknis dari permainan, tetapi kami membutuhkan teks kreatif dari kondisi - tidak hanya dengan persyaratan yang harus dipenuhi, tetapi dengan beberapa jenis cerita.
Jenis humor favorit saya adalah absurditas. Ini adalah ketika dengan tatapan serius Anda mengatakan omong kosong konyol. Omong kosong biasanya terdengar tak terduga dan menyebabkan tawa. Saya ingin membuat kondisi tugas tidak masuk akal untuk menyenangkan para peserta. Jadi ada cerita tentang kuda Adolf, yang tidak bisa memanggil teman, karena dia tidak mendapatkan kuku besarnya di kunci telepon.

Lalu ada cerita tentang seorang gadis yang terlibat dalam piano dan ingin mengotomatiskannya, sehingga bukannya kelas dia berjalan-jalan. Ada ungkapan "Jika seorang gadis berhenti bermain, ibu keluar dari ruangan dan menampar wajahnya." Kami diberitahu bahwa ini adalah propaganda pelecehan anak dan kami perlu menulis teks lain. Kemudian kami datang dengan sebuah cerita tentang orkestra di mana seorang pianis jatuh sakit sebelum konser, dan salah satu musisi menulis sebuah program di JS yang akan memainkan perannya.
Secara umum, kami berhasil mencapai efek teks yang diinginkan. Jika mau, Anda bisa membacanya di sini .
Mengatur tugas dalam Kontes
Jadi, kami memiliki persyaratan tugas siap, skrip untuk memeriksa solusi dan solusi referensi. Maka itu perlu untuk mengkonfigurasi semua ini di Kontes. Untuk tugas apa pun, ada beberapa tes, yang masing-masing berisi satu set data input dan jawaban yang benar. Diagram di bawah ini menunjukkan tahapan Kontes. Tahap pertama adalah pelaksanaan program, yang kedua adalah verifikasi hasil:

Pada input tahap pertama, satu set data uji dan program peserta diterima. Di dalam, skrip run.js berfungsi, kode yang kami tulis di atas. Dia bertanggung jawab untuk menjalankan program peserta, menerima dan menulis hasil kerjanya ke file. Program berjalan di mesin virtual terpisah, yang muncul dari gambar Docker sebelum dijalankan. Mesin virtual ini terbatas sumber dayanya, tidak memiliki akses ke jaringan.
Tahap kedua (memeriksa hasilnya) dilakukan di mesin virtual lain. Dengan demikian, program peserta tidak secara fisik memiliki akses ke lingkungan tempat verifikasi berlangsung. Input dari tahap kedua adalah hasil kerja program peserta (diperoleh pada tahap pertama) dan file dengan jawaban yang benar. Outputnya adalah kode keluar dari skrip verifikasi, yang menurutnya Kontes memahami bagaimana verifikasi berakhir:
- OK
= 0,
- PE
(kesalahan presentasi - format hasil yang salah) = 4
- WA
(jawaban salah) = 5
- CF
(kesalahan saat verifikasi) = 6
Kontes tidak diadaptasi dengan baik untuk tugas-tugas di ujung depan, termasuk Node.js. Kami memecahkan masalah dengan mengemas skrip validasi ke dalam file biner menggunakan pkg bersama dengan Node.js dan node_modules. Sekarang kami memiliki pengetahuan rahasia tentang Kontes dan mengalami lebih sedikit kesulitan dalam mempersiapkan kejuaraan saat ini.
Jadi, kami sudah menyiapkan tugas. Setelah itu, ada banyak lagi: tes publik untuk mengkalibrasi kompleksitas, publikasi tugas, tugas dukungan teknis selama kompetisi dan penghargaan pemenang di kantor Yandex. Tetapi ini adalah kisah yang sangat berbeda.
Sekarang, alih-alih berkompetisi di bidang-bidang tertentu, kami mengadakan kejuaraan pemrograman terpadu, di mana hanya ada trek paralel, termasuk frontend.
Saya tidak menyesal sedikit tentang waktu yang dihabiskan untuk menyiapkan tugas. Itu menarik dan menyenangkan, tidak konvensional. Dalam salah satu komentar di Habré menulis bahwa kondisi dipikirkan oleh para penggemar bisnis. Selama kompetisi, itu keren untuk menyadari bahwa para peserta menyelesaikan tugas yang Anda buat.
Referensi:
- Analisis penugasan frontend tahun lalu, yang kami siapkan
- Analisis trek di frontend di kejuaraan pertama tahun ini