丸一日苦心して、それでも通らなかったので、他の方の解いたコードをチラ見しました。無念!
しかし拝見しなかったら、一週間やそこらじゃ解けなかったでしょう。感謝です。
ポイントは3つ
- 新規に「*」になった座標を配列に入れる
- その配列の中身がある限りwhile文でループ
- 処理が終わったら、その配列の中身の使った分をひとつ消去

<?php
// 自分の得意な言語で
// Let's チャレンジ!!
$s = explode(" ",trim(fgets(STDIN)));
$h = $s[0];
$w = $s[1];
//map取得
for ($i = 0; $i < $h; $i++) {
$hoge = trim(fgets(STDIN));
for ($j = 0; $j < $w; $j++) {
$map[$i][$j] = mb_substr($hoge, $j, 1);
if($map[$i][$j]=="*"){
$y = $i;
$x = $j;
}
}
}
//print_r($map);
//初期処理
//新たに*にした場所を$newstarに格納する
if($y>=1 && $map[$y-1][$x]=="."){
$map[$y-1][$x] = "*";
$newstar[]=array($y-1,$x);
}
if($y<$h-1 && $map[$y+1][$x]=="."){
$map[$y+1][$x] = "*";
$newstar[]=array($y+1,$x);
}
if($x>=1 && $map[$y][$x-1]=="."){
$map[$y][$x-1] = "*";
$newstar[]=array($y,$x-1);
}
if($x<$w-1 && $map[$y][$x+1]=="."){
$map[$y][$x+1] = "*";
$newstar[]=array($y,$x+1);
}
while(count($newstar)>=1){//移動可能な座標がある限り続ける
$y = $newstar[0][0];
$x = $newstar[0][1];
//共通操作
if($y>=1 && $map[$y-1][$x]=="."){
$map[$y-1][$x] = "*";
$newstar[]=array($y-1,$x);
}
if($y<$h-1 && $map[$y+1][$x]=="."){
$map[$y+1][$x] = "*";
$newstar[]=array($y+1,$x);
}
if($x>=1 && $map[$y][$x-1]=="."){
$map[$y][$x-1] = "*";
$newstar[]=array($y,$x-1);
}
if($x<$w-1 && $map[$y][$x+1]=="."){
$map[$y][$x+1] = "*";
$newstar[]=array($y,$x+1);
}
array_shift($newstar);//いまつかった配列を消す
}
//print_r($newstar);
//出力
for ($i = 0; $i < $h; $i++) {
for ($j = 0; $j < $w; $j++) {
echo($map[$i][$j]);
}
echo("\n");
}
?>
配列$newstarに、初期座標の上下左右が*にできるなら、そのy,xを格納していきます。
今度はその移動可能な座標を基点に、同様に処理をします。処理後は使用済みの座標を消します。
while文はあまりなじみがなかったので、「配列の中身がある限りループ」という条件式の発想がまったくなく、見たとき衝撃を受けました。

paizaAランクレベルアップメニュー(各言語あり)
https://paiza.jp/works/mondai/a_rank_level_up_problems
参考にさせて頂いたコード:「陣取りゲーム (paizaランク A 相当)をPHPで解いてみた」
https://rnsr0371.boy.jp/2020/09/11/jintori_game/
1+