問題文
🦙 < Happy New Year! フラグはこのサービス名に含まれる動物の名前だよ
Alpaca{+ 動物名(英小文字) +}を送るパカ
https://alpacahack.com/daily/challenges/happy-new-year
方針
サービス名は『AlpacaHack』なので、小文字表記のalpacahackに含まれる部分文字列であって動物の名前となるものがフラグになりそうです。めちゃくちゃマイナーな動物の名前が答えである可能性も否定できませんが、難易度がWelcomeになっているのでとりあえずWikipediaに載っている動物のいずれかであると仮定しましょう。「animal name list」でググると英語版WikipediaのList of animal namesというページが出てきたので、alpacahackの部分文字列を列挙してこのリストに含まれるか確かめていきます。
ソルバー
alpacahackは10文字なので、長さが1以上の部分文字列は通りあります。また、List of animal namesには執筆時点で190以上の動物が載っています。これだけあると目視で確かめていくのはちょっと大変なので、スクリプトを書きましょう。僕はDenoが好きなのでDenoを使います。
import { DOMParser } from "jsr:@b-fuze/deno-dom"
const TARGET = "alpacahack"
const document = await fetch(
"https://en.wikipedia.org/wiki/List_of_animal_names",
)
.then((res) => res.text())
.then((html) => new DOMParser().parseFromString(html, "text/html"))
const animalNames = new Set<string>()
const tables = document.querySelectorAll("table.wikitable")
for (const table of tables) {
const rows = table.querySelectorAll("tr")
for (const row of rows) {
const firstCell = row.querySelector("td")
if (!firstCell) {
continue
}
const link = firstCell.querySelector("a")
if (link) {
const animalName = link.textContent.trim().toLowerCase()
animalNames.add(animalName)
}
}
}
const candidates: string[] = []
for (let i = 0; i < TARGET.length; i++) {
for (let j = i + 1; j <= TARGET.length; j++) {
const sub = TARGET.slice(i, j)
if (animalNames.has(sub)) {
candidates.push(sub)
}
}
}
console.log(candidates)
これを適当な場所に保存してdeno run --allow-net solve.tsなどのように実行すれば、以下の出力が得られます。
[ "alpaca" ]
ということで、フラグはAlpaca{alpaca}であることが分かりました!
ちなみに2026年は午年ですが、アルパカは別に馬とは関係ないっぽいです。