PHPカンファレンス福岡2019内企画 マネクラからの挑戦状、開催時間内にはほとんどやってませんでしたが、後日やってみて、スコア60230を出せたので解説してみます。開催時間外なので非公認スコアです。
(記事公開後、 @m3m0r7)さんと相談しながら縮めた結果、60300→60230へとさらに70短縮できました。
PHPカンファレンス福岡2019 マネクラからの挑戦状 Webサイトコードゴルフ
スコア60230(PHPファイル(480文字)+画像ファイル)
まずは入念にレギュレーションをチェック
プログラム一式をマネージドクラウドインスタンスにデプロイ後、オンライン上に用意されたDiffツールを使って、ブラウザレンダリング結果が一致しているかチェックします。合格したら、make check
コマンドでスコアを計測する、という流れです。また以下のレギュレーションが存在します。
- PHPで作成されたサイト https://phpconfuk-codegolf-php.lolipop.io/ (正解サイト)のソースコードをお渡しします(このリポジトリです)。
- サイトの 表示を一切変えずに Webサイトを構成する全コード全ファイルの合計ファイルサイズを小さくして、あなたのロリポップ!マネージドクラウドの
PHPプロジェクト
にデプロイしてください。- 最も小さいファイルサイズになった人が優勝です
- コンテナ内の
/var/www/html
内にWebサイトを表示するのに必要な全てのコード、およびファイルを設置してください
/var/www
等への設置は禁止です- Makefile内の
check
タスク内のコマンドの変更は禁止です
プログラムがやっていること
エントリーポイントとなる index.php
を見てみましょう。
コアとなるロジックは、
- クエリストリングのキーと値の組み合わせを
tokens
テーブルに保存。 - 値降順(第一ソート順), キー降順(第二ソート順)でとりだし、3番目の値の文字列を取得し逆さにする
- HTMLテンプレートに文字列を埋め込んで表示
という感じでした。
vendors
ディレクトリ、データベースアクセスを取り除く
初期のスコアは400万を超えていますが、その大部分が vendors
ディレクトリであることがわかります。
プログラムを把握した上であらためてレギュレーションを確認してみると、データベースに関してはなんら記述がないので、データベースへ保存するコードを除去できます。
よって、受け取ったクエリストリング配列を処理して、レンダリングに必要な文字列を返すコードと、その他のHTMLを全てindex.php
に入れれば、大分スコアが減らせそうです。そうして出来たコードにインデント・スペースを補完したコードが以下。
<? $a=$_GET; krsort($a); arsort($a); echo strrev(array_values($a)[2]) ?>
最初のforeach で配列を整形してる部分をなくせないかな、と思いましたが思いつかなかったです。
ユーザー定義のソート関数ではキーと値のソートルールが同じだったので、$i = $a[1] != $b[1];
で $i
が true
なら値、false
ならキーでソートされます。
コードゴルフなのに、そこそこ読みやすいコードになってしまいましたね。
short open tag
short open tagは将来的に廃止されそう(PHP: rfc:deprecate_php_short_tags)ですが、PHP 7.3.2ではまだ動作しますし、マネクラの環境でもデフォルトで使えます。タグとforeach キーワードの間にスペースが無くても動きます。
不要なファイルを削除する
これで、 vendors
も削除できますし、 model/token.php
も不要になりました。表示に必要なファイルは、 index.php
, mc.png
の2つになったので、改変不可な make check
ファイルを含む Makefile
を入れて、3ファイル以外の全てのファイルを削除しましょう。 .env
, .htaccess
が無くてもDiffチェッカーはパスします。
HTMLドキュメントを短くする
残るはHTMLを短くするのみです。PNGファイルは、名前を変える以外の変更はしていません。
無駄なCSSを取り除く。
lolipop-mc-codegolf-challenge/home.liquid at master · pepabo/lolipop-mc-codegolf-challenge · GitHub
CSS定義でファイルサイズがかなり大きくなってます。 まず、HTMLにはクラス属性が1個も定義されてなかったので、セレクタにクラスを含むものは安全に削除できます。 使ってないタグを含むセレクタの定義も削れます。 結果以下が残りました。
body { height: 100vh; font-family: Helvetica; letter-spacing: .04em } table { height: 100% } * { border: none; padding: 0; margin: 0; font-weight: 400; color: #465560; text-align: center } td { height: 50%; width: 5% }
font-family
は、レンダリングに使われている物だけをのこしました。画面に表示されている文字列要素が h2
だけだったので、 *
に統合することができました。
表示に影響しないタグを削除していく
<html><header><meta><body>
などを削ってもチェッカーにパスしました。
表示に影響しない閉じタグを削除していく
一箇所 </table>
が残りましたが、それ以外は削除できます。
</style>
については、ドキュメントの最後に移動すると、削除できます。
ところどころにある
も不要です。
属性値を"
で囲まない
はい。業務で真似してはいけない。
DOCTYPE宣言
<!DOCTYPEhtml>
宣言内のスペース不要でした。
pngファイル名をmc.png
→ m
へ
5文字縮まりましたね。拡張子なんていらなかった。
まとめ
これで解説は終わりです。 全般的に業務で役に立たない知識です。
没テクニック
テーブルレイアウトをやめてdivにする
挑戦しましたが、Diffが出てしまうので断念。
PNGファイルサイズを縮める
PNGファイルからアルファチャンネルを削除すれば、スコアを縮められるかと思ってGIMPでやってみましたが、Diffチェッカーに引っかかって失敗しました。サイズは8,000ほど縮まりそうだったので残念です。
レギュレーションを守った上で最高のスコアは
#phpconfuk 今日のゴルフのホールアウトスコアです、ありがとうございました。 pic.twitter.com/eOWEGxtt8y
— uzulla (@uzulla) June 30, 2019
なんと0になります。スコアチェッカーのコマンドは以下の通りですが、 *.git/*
, Makefile
, .env
が除外されているため、.git/
ディレクトリ以下に index.php
, mc.png
を移動して、シンボリックリンクを作れば、レギュレーションを完全に守った上で0が達成できます。
チェッカーで除外するのではなく、デプロイ時に除外すればこの穴はできないので、運営側で意図した穴なのかな、と思います。
@ssh -p ${SSH_PORT} ${SSH_USER}@${SSH_HOST} 'find /var/www/html -type f -not -iwholename "*/.git/*" -not -name "Makefile" -not -name ".env" | xargs cat | wc -c'