ニュース ゲーム アプリ ブログ サポート
しおやフットボール アイコン

しおやフットボール

海外サッカー日本人選手日程確認アプリ

海外で奮闘する日本人選手を応援する、すべてのサッカーファンのための情報アプリです。
欧州5大リーグをはじめ、世界中で活躍する日本人選手の最新の試合日程や結果を、いつでもどこでもひと目で確認できます。

5つのメイン機能

予定を確認 試合日程と万全のネタバレ対策

「今日の日本人選手所属チームの対戦カード」「明日の対戦カード」に加え、「昨日の対戦カード」を一覧で確認することができます。

フィルター機能により、日本人のチェックを外せば日本人所属チーム以外の全チームの日程も網羅可能です。

また、大きな特徴として徹底したネタバレ対策を施しています。「昨日」のタブを開いた際、デフォルトではチーム名以外のスコアなどは隠されています。「結果を見る」ボタンを押さない限り結果が表示されることはないため、後から録画や配信で試合を楽しみたい方も安心してご利用いただけます。

昨日の日本人 出場状況と活躍をひと目で

昨日の試合に日本人選手が出場したのか、またどのような活躍(ゴール、アシスト、出場時間など)をしたのかをスピーディーに一覧で確認できるタブです。

※こちらには試合結果に関する情報が直接表示されるため、ネタバレを避けたい方は閲覧にご注意ください。

今週の日本代表 独自のアルゴリズムによるベストイレブン

本アプリの目玉機能の一つです。毎週火曜日に、直近1週間の欧州リーグで活躍した日本人選手の中から、最も活躍した11人と最適なフォーメーションを選出します。

数理最適化による選出ロジック

このベストイレブンは単なる印象ではなく、高度な自動化システムと数学的アルゴリズムによって計算されています。

  • 完全自動実行: GitHub Actionsを利用し、毎週火曜の午前3時〜午前9時にデータ収集から選出までを行います。
  • リーグ評価係数: プレミアリーグなど、所属するリーグのレベルに応じた独自の評価係数を乗算します。この評価係数はOpta社のLeague Power Rankingsを参考にしています。
  • 割当の最適化: ハンガリアン法の最大重み割当という思想をベースに、チーム全体の合計評点が最高となる11人の配置を数学的に導き出します。
ロジックをもっと詳しく

移籍 手作業で管理される正確な情報

今シーズンの日本人選手の移籍情報を確認できます。機械的な自動収集ではなく、管理人が情報を精査し、完全手作業で丁寧にデータベースを管理しています。移籍の噂レベルから、公式発表による確定情報までを正確に把握できます。

シーズン 蓄積されたデータの分析

今シーズンの日本人選手のデータをまとめて確認できるタブです。欧州5大リーグにとどまらず、オランダ、ベルギー、ポルトガル、さらには2部リーグやスコットランド(セルティック等)に所属する選手まで幅広く網羅しています。

「得点数」「アシスト数」「平均評点」「合計出場時間」などを一覧で確認し、自由に並べ替えて分析することが可能です。

アプリの基本機能

こんな方におすすめ

数理最適化による選出ロジックをもっと詳しく解説!

「しおやフットボール」の目玉機能である「今週の日本代表」は、完全に自動化されたプロセスと数学的アルゴリズムによって毎週算出されています。ここでは、その裏側で実際に稼働しているコードの一部をご紹介します。

1. GitHub Actionsによる完全自動化

毎週火曜日の午前3時(JST)に、サーバー上でCronジョブが起動し、自動的に処理を開始します。

# .github/workflows/best11_update.yml
name: Weekly Best 11 Generator

on:
  schedule:
    # 毎週火曜 03:00 JST (月曜 18:00 UTC) に実行
    - cron: '17 18 * * 1'
  workflow_dispatch: # 手動実行ボタンを有効化

jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - name: Generate and Optimize Best 11
        run: node generate_best11.js

2. リーグレベルを考慮した評価係数

各選手の試合におけるレーティング(評点)に対し、所属リーグの難易度に応じた「リーグ評価係数」を乗算し、基準スコアを算出します。

// generate_best11.js の一部
const LEAGUE_MULTIPLIER = {
    "PL": 1.10, "PD": 1.09, "BL1": 1.08, "SA1": 1.07, "FL1": 1.06, 
    "ELC": 1.04, "BSA": 1.03, "PPL": 1.02, "DED": 1.01, "SPL": 1.00, "J1": 1.00
};

3. 数理最適化による最適配置

フォーメーションごとに決められた11のポジション枠に対し、選手の「基準スコア」と「そのポジションへの適性係数」を掛け合わせた実効スコアを計算します。そして、チーム全体の合計スコアが最大になる組み合わせを全探索(バックトラッキング)によって厳密に導き出します。

function solveAssignment(players, positions) {
    const n = players.length;
    const m = positions.length; // 11
    
    // スコア行列の作成 (選手 x ポジション)
    const matrix = players.map(player => {
        return positions.map(pos => {
            const suitMap = PLAYER_MASTER[player.name] || {};
            const suit = suitMap[pos.reqPos] || 0.1;
            return player.baseScore * suit;
        });
    });

    // 2. 再帰的なバックトラッキングによる最適化探索
    const assignedPlayers = new Set();
    const currentAssignment = new Array(m);

    function backtrack(posIndex, currentScore) {
        if (posIndex === m) {
            if (currentScore > bestScore) {
                bestScore = currentScore;
                bestAssignment = [...currentAssignment];
            }
            return;
        }

        // 上位候補から探索し、計算量を抑えるための「枝刈り」を適用
        const candidates = posCandidates[posIndex];
        let branchCount = 0;
        for (let cand of candidates) {
            if (!assignedPlayers.has(cand.i)) {
                assignedPlayers.add(cand.i);
                currentAssignment[posIndex] = { playerIndex: cand.i, score: cand.score };
                
                backtrack(posIndex + 1, currentScore + cand.score);
                
                assignedPlayers.delete(cand.i);
                branchCount++;
                if (branchCount > 5) break; // 枝刈り
            }
        }
    }
    backtrack(0, 0);
    
    return { score: bestScore, assignment: bestAssignment };
}

4. 結果のアーカイブ保存

最もスコアが高かったフォーメーションと選手の組み合わせをJSONデータとして保存し、同時に目次となるファイル(best11_index.json)も自動で更新します。

// 保存処理 (Confirmed_... と 目次更新)
const confirmedResult = {
    updated: new Date().toISOString(),
    dateLabel: dateLabel,
    formation: absoluteBest.formationName,
    totalScore: absoluteBest.totalScore,
    list: absoluteBest.list
};

fs.writeFileSync(path.join(best11Dir, `Confirmed_best11_${dateStr}.json`), JSON.stringify(confirmedResult, null, 2), 'utf8');

このように、システムが完全に自律して評価と配置のパズルを解き続けることで、しおやフットボールの「今週の日本代表」は作られています。