マガジン

オセロで先手が2回連続で打てるルール:先手有利はどこまで強まるか

遊びを見つける

執筆にClaudeを使用しています。

一人が小さなパズルを試し、制作者がノートを持って様子を観察するテストプレイ風景
記事のテーマをもとに制作したAI生成の写真風イメージ。

オセロの黒(先手)が、最初に2回続けて石を置けるとします。白が最初の一手を打つのは、黒が2枚置いたあとです。これだけで黒の勝率はどれほど動くのでしょうか。「かなり有利になりそう」という直感は誰にでもありますが、どのくらい強まるのかは、数えてみないと分かりません。 この記事は、その答えを書くものではなく、自分で10局ぶん記録して確かめるための設計書です。核になるのは、手番のルールだけを変えて、黒の勝敗と石差を同じ書式で10局ずつ記録するという方法です。 10局は、勝率の話をするには少ない数です。そこで、少ない数からどこまで言えて、どこから言えないのかも、読み方の基準として先に決めておきます。

この記事の目次
  1. 「2回連続」を一つに決める
  2. 準備と、10局の進め方
  3. 何を、どの単位で書くか
  4. 試行回数を増やすための最小コード
  5. 起こりやすい誤り
  6. 次の行動

「2回連続」を一つに決める

実験の最初の作業は、ルールの言葉を一つの意味に固定することです。「先手が2回連続で打てる」には、少なくとも次の二つの読み方があります。

  • 開幕だけ:黒が最初に2手続けて打ち、その後は通常どおり交互に打つ。
  • 毎ターン:黒の番が来るたびに2手続けて打つ。

毎ターン2手では、白が一手打つ間に黒が二手打つことになり、比較の意味が薄くなります。この記事では開幕だけを実験の対象にします。比べる条件は次の二つです。

  • A(標準)、内容:黒が1手、白が1手と交互に打つ。置けなければパス。
  • B(開幕2連続)、内容:黒が最初に2手続けて打つ。その後は標準と同じ。

条件Bには決めておくべき細部があります。黒の2手目に置ける場所がなかったらどうするか、という点です。ここでは「2手目に置ける場所がなければ、その権利は消えて白の番になる」と決めます。通常のパスと同じ扱いです。この取り決めは対局前に二人で声に出して確認してください。対局の途中で揉めると、そのぶん記録も崩れます。

初期配置は標準の4石のままで、黒が先手です。石の数え方も先に決めておきます。終局時に盤上の黒石と白石を数え、空きマスはどちらにも足さないことにします。この決め方なら、石差は「黒の石数 − 白の石数」で一意に出せます。

準備と、10局の進め方

準備するもの

  • 実物のオセロ盤(石の数を数えやすいもの)。
  • 打ち手が二人(同じ二人が全局を打つのが前提です)。
  • 記録用紙。下の表の列をそのまま写せます。

アソバースの「潮目のオセロ」では、条件Bのルールは再現できません。確認済みの範囲では、手番はつねに交互だからです。ただし、標準ルールの感触をつかむ練習には役立ちます。ひとり対局では3段階の相手が選べ、置ける場所に返る石のプレビューが出ます。友達との対局は招待リンクのオンライン対局で、黒が先手です。ヒントと一手戻すはひとり対局のみなので、条件Aの基準対局にオンラインを使う場合は、そもそも使えません。この実験の本体は、条件Bを遊べる実物の盤で行います。

進め方

  1. 条件ごとに10局、合計20局を予定します。1局が長引くなら、日を分けても構いません。
  2. 局の順番は A→B→A→B… と交互にします。「前半はA、後半はB」にすると、後半に慣れた効果が条件の差に混ざります。
  3. 黒を持つ人は条件ごとに5局ずつ交代します。二人の腕前の差が「黒の勝率」に紛れ込むのを防ぐためです。
  4. 条件Bの局では、最初の黒の手を打ったあと、白に渡さず、もう一度黒が打ちます。2手目の置き場所がなければ、そのまま白の番です。
  5. 終局後すぐに石を数え、記録用紙に書きます。数え直しが必要になりそうな盤は、写真を撮る代わりに、黒石の数と白石の数を二人で読み上げて確認します。

条件ごとに黒を5局ずつ持つ形にしたのは、「黒を持つ人」と「条件」を切り離すためです。仮に同じ人が条件Aの黒を全部持つと、強い弱いの差が条件の差に見えてしまいます。

何を、どの単位で書くか

1局ごとに1行、次の列を埋めます。

  • 1、条件:A、黒を持った人:、黒の石:、白の石:、石差(黒−白):、勝敗(黒視点):、気づき:
  • 2、条件:B、黒を持った人:、黒の石:、白の石:、石差(黒−白):、勝敗(黒視点):、気づき:

勝敗は「勝・負・分」の3種類で書きます。石差は符号を付けて書き、黒が負けた局はマイナスです。「気づき」の欄は短くて構いません。たとえば、条件Bの2手目で置ける場所が極端に少なかった、といった状況をその場で書き留めます。結果を読み解くとき、数字だけでは見えない手がかりになります。

10局が終わったら、条件ごとに次の三つを集計します。

  • 黒の勝ち数(引き分けは0.5勝として数えるか、別枠にするかを先に決めます)。
  • 石差の平均。
  • 石差の最大と最小(大勝や大敗が平均を引っ張っていないかを見るため)。

条件の比較は、Bの数値からAの数値を引いた差で見ます。たとえば「黒の勝ち数の差」と「石差の平均の差」です。この差が「先手有利がどこまで強まったか」の、このセッションでの答えになります。

結果の読み方

勝ち数だけを見るとき、10局は大きくぶれます。仮に黒と白がまったく互角で、各局の勝敗がコイン投げと同じだとします。この場合でも10局のうち黒が7勝以上になる確率は約17%、8勝以上でも約5.5%あります。つまり、黒が7勝3敗だったとしても、それだけで「黒有利」とは言いにくいのです。

そこで、次のように順に読んでいきます。

  1. まず条件Aの結果を見ます。 黒の勝ち数が5前後なら標準でも黒は大きく有利ではない、極端に偏っていれば二人の組み合わせ自体に偏りがある、と読めます。標準ルールで先手がどのくらい有利かは、ここで初めて自分のデータとして出てきます。
  2. 次にBとの差を見ます。 勝ち数の差が1〜2勝なら、偶然の範囲に十分収まります。3勝以上離れていても、10局では断定しないでください。
  3. 石差の平均で確認します。 勝敗は「1点差でも大差でも1勝」ですが、石差は大きさも拾います。勝ち数にあまり差がなくても、石差の平均が一貫して黒側に動いているなら、先手有利が強まった方向の手がかりになります。
  4. 気づきの欄を読み返します。 2手目に置ける場所が少なかった局、逆に黒が一気に有利な形を作れた局に、傾向がないかを確認します。

この読み方の要点は、「差が出たかどうか」ではなく「差がどの程度の確かさで出たか」を分けて書くことです。10局で言えるのは、せいぜい「傾向が見えた」「見えなかった」までです。

試行回数を増やすための最小コード

実物の盤では、20局でも時間がかかります。補助として、ランダムに合法手を選ぶだけの打ち手同士で、条件AとBを何千局も回すコードを用意しました。ブラウザの開発者ツールのコンソールにそのまま貼れば動きます。

js
const N=8,D=[[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];
function flips(b,r,c,p){
  if(b[r][c])return[];
  const out=[];
  for(const[dr,dc]of D){
    let y=r+dr,x=c+dc;const line=[];
    while(y>=0&&y<N&&x>=0&&x<N&&b[y][x]===-p){line.push([y,x]);y+=dr;x+=dc;}
    if(line.length&&y>=0&&y<N&&x>=0&&x<N&&b[y][x]===p)out.push(...line);
  }
  return out;
}
function moves(b,p){
  const m=[];
  for(let r=0;r<N;r++)for(let c=0;c<N;c++){
    const f=flips(b,r,c,p);if(f.length)m.push([r,c,f]);
  }
  return m;
}
function play(extra){
  const b=Array.from({length:N},()=>Array(N).fill(0));
  b[3][3]=b[4][4]=-1;b[3][4]=b[4][3]=1;
  let p=1,left=1+extra,passes=0;
  while(passes<2){
    const m=moves(b,p);
    if(m.length){
      passes=0;
      const[r,c,f]=m[Math.floor(Math.random()*m.length)];
      b[r][c]=p;for(const[y,x]of f)b[y][x]=p;
      left--;
    }else{passes++;left=0;}
    if(left<=0){p=-p;left=1;}
  }
  return b.flat().reduce((a,v)=>a+v,0);
}
function rate(extra,n){
  let w=0,d=0,sum=0;
  for(let i=0;i<n;i++){const s=play(extra);sum+=s;if(s>0)w++;else if(s===0)d++;}
  return{黒勝ち:w,引分:d,白勝ち:n-w-d,石差平均:sum/n};
}
for(const e of[0,1])console.log(e?"B":"A",rate(e,10),rate(e,3000));

play(0) が条件A、play(1) が条件Bです。黒は先手で、2手目に置けない場合は自動的に白へ回ります。出力は、10局ぶんと3000局ぶんが並びます。

このコードの使い道は二つです。一つは、10局だけ回した結果が、実行のたびにどれだけ変わるかを見ることです。同じコードを何度か実行して、10局の黒勝ち数が毎回どの範囲で動くかを見てください。実物の10局がどれほど偶然に左右されるかを実感できます。

もう一つは、3000局の結果を、実物の10局を読むときの参考にすることです。ただし、ランダムに打つだけの打ち手は、人間の対局とは打ち方がまったく違います。隅を取る、相手の置ける場所を減らすといった戦略を一切含みません。コードの数字は「ルールの構造だけが効いた場合」の目安にとどまり、人間同士の答えとは別物として扱います。

起こりやすい誤り

  • 黒を同じ人が持ち続ける。 上に書いたとおり、腕前の差が条件の差に見えてしまいます。必ず交代します。
  • 条件Bで2手目の扱いを局ごとに変える。 置き場所がなければ白へ、という取り決めを最後まで貫いてください。
  • 結果を見ながらルールを足す。 「Bは強すぎるから途中で制限しよう」と始めると、比較が成り立たなくなります。調整したいなら、そこで実験を一度区切り、新しい条件Cとして別に10局を取ります。
  • 勝ち数だけで結論を出す。 石差と気づきの欄を併用します。
  • 石数の数え間違い。 終局直後に二人で読み上げて確認します。空きマスを足さないという取り決めも、最初に守ってください。
  • 慣れの偏り。 AとBを交互に並べておけば、後半に腕が上がった影響がどちらかに偏るのを避けられます。
  • ランダム対戦の結果を人間の結論にする。 コードの数字は補助で、実物の記録が主役です。

次の行動

まず二人で条件Bの細部(2手目に置けないときの扱いと、石の数え方)を決め、記録用紙を印刷するか書き写してください。そのうえでA→B→Aの順に交互に打ち、10局ずつ記録します。標準ルールの感覚を戻したいときは、潮目のオセロのひとり対局で数局だけ練習してから始めると、条件Aの打ち方が安定します。