From db340b41edc0c7b78447c60b0cd21008cb1f2108 Mon Sep 17 00:00:00 2001 From: NINI Date: Sat, 10 Oct 2026 08:35:08 +0900 Subject: [PATCH] Exclude crop-border scenery from native friend steering --- tools/android/exercise-playground.ps1 | 5 ++-- tools/android/test-playground-contracts.ps1 | 26 ++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/tools/android/exercise-playground.ps1 b/tools/android/exercise-playground.ps1 index 01a6413..e0f3fd7 100644 --- a/tools/android/exercise-playground.ps1 +++ b/tools/android/exercise-playground.ps1 @@ -151,10 +151,11 @@ function BlueFriends([string]$Path){ for($y=0;$y-lt$height;$y++){for($x=0;$x-lt$width;$x++){$pixel=$bitmap.GetPixel(530+$x*4,280+$y*4);$mask[$y*$width+$x]=$pixel.R-lt135-and$pixel.B-ge100-and($pixel.B-$pixel.R)-gt45-and($pixel.G-$pixel.R)-gt20}} $friends=[Collections.Generic.List[object]]::new();$queue=[Collections.Generic.Queue[int]]::new() for($index=0;$index-lt$mask.Length;$index++){ - if(!$mask[$index]){continue};$mask[$index]=$false;$queue.Enqueue($index);$count=0;$sumX=0;$sumY=0 + if(!$mask[$index]){continue};$mask[$index]=$false;$queue.Enqueue($index);$count=0;$sumX=0;$sumY=0;$touchesBorder=$false while($queue.Count){$cell=$queue.Dequeue();$x=$cell%$width;$y=[int][Math]::Floor($cell/$width);$count++;$sumX+=$x;$sumY+=$y + if($x-eq0-or$x-eq($width-1)-or$y-eq0-or$y-eq($height-1)){$touchesBorder=$true} foreach($neighbor in @(($cell-1),($cell+1),($cell-$width),($cell+$width))){if($neighbor-lt0-or$neighbor-ge$mask.Length){continue};if([Math]::Abs(($neighbor%$width)-$x)+[Math]::Abs([int][Math]::Floor($neighbor/$width)-$y)-ne1){continue};if($mask[$neighbor]){$mask[$neighbor]=$false;$queue.Enqueue($neighbor)}}} - if($count-ge30){$friends.Add(@{x=530+4*$sumX/$count;y=280+4*$sumY/$count;sampledBluePixels=$count})} + if($count-ge30-and!$touchesBorder){$friends.Add(@{x=530+4*$sumX/$count;y=280+4*$sumY/$count;sampledBluePixels=$count})} } return @($friends|Sort-Object sampledBluePixels -Descending|Select-Object -First 2) }finally{$bitmap.Dispose()} diff --git a/tools/android/test-playground-contracts.ps1 b/tools/android/test-playground-contracts.ps1 index 2223625..4c3886e 100644 --- a/tools/android/test-playground-contracts.ps1 +++ b/tools/android/test-playground-contracts.ps1 @@ -1,4 +1,4 @@ -param([Parameter(Mandatory)][string]$EvidenceDir,[string]$FinalSource=(Join-Path $PSScriptRoot 'exercise-final.ps1'),[string]$PlaygroundSource=(Join-Path $PSScriptRoot 'exercise-playground.ps1'),[string]$PreservationFixtureDir,[string]$BoardReadyPng,[string]$HomePng,[string]$ReentryFixtureDir,[string]$DepthFixtureDir,[string]$PauseFixtureDir) +param([Parameter(Mandatory)][string]$EvidenceDir,[string]$FinalSource=(Join-Path $PSScriptRoot 'exercise-final.ps1'),[string]$PlaygroundSource=(Join-Path $PSScriptRoot 'exercise-playground.ps1'),[string]$PreservationFixtureDir,[string]$BoardReadyPng,[string]$HomePng,[string]$ReentryFixtureDir,[string]$DepthFixtureDir,[string]$PauseFixtureDir,[string]$BlueFriendsPng) $ErrorActionPreference='Stop' New-Item -ItemType Directory -Path $EvidenceDir -Force|Out-Null $checks=[Collections.Generic.List[object]]::new() @@ -288,6 +288,30 @@ exit ([int]$env:PLAYGROUND_CONTROL_TOUCH_EXIT) $friends=@(BlueFriends $path);$expectedCount=if($kind-eq'two-blue-friends'){2}else{0} Probe "actual-live-steering-vision-$kind" ($friends.Count-eq$expectedCount) @{friends=$friends;expectedCount=$expectedCount;scope='Synthetic semantic control, not native screenshot verdict'} } + foreach($kind in @('top-edge','bottom-edge','left-edge','right-edge','partial-and-one-friend','hill-edge-and-two-friends','one-interior-friend','near-edge-interior-friend')){ + $bitmap=[Drawing.Bitmap]::new(2400,1080);$graphics=[Drawing.Graphics]::FromImage($bitmap);$brush=[Drawing.SolidBrush]::new([Drawing.Color]::FromArgb(30,130,190)) + try{ + $graphics.Clear([Drawing.Color]::FromArgb(147,211,218)) + switch($kind){ + 'top-edge'{$graphics.FillRectangle($brush,900,260,200,100)} + 'bottom-edge'{$graphics.FillRectangle($brush,900,700,200,100)} + 'left-edge'{$graphics.FillRectangle($brush,500,400,100,100)} + 'right-edge'{$graphics.FillRectangle($brush,1800,400,100,100)} + 'partial-and-one-friend'{$graphics.FillEllipse($brush,1000,250,60,60);$graphics.FillEllipse($brush,1450,470,60,60)} + 'hill-edge-and-two-friends'{$graphics.FillRectangle($brush,900,200,300,140);$graphics.FillEllipse($brush,1000,470,60,60);$graphics.FillEllipse($brush,1450,470,60,60)} + 'one-interior-friend'{$graphics.FillEllipse($brush,1450,470,60,60)} + 'near-edge-interior-friend'{$graphics.FillRectangle($brush,534,400,60,60)} + } + $path=Join-Path $EvidenceDir "vision-border-$kind.png";$bitmap.Save($path,[Drawing.Imaging.ImageFormat]::Png) + }finally{$brush.Dispose();$graphics.Dispose();$bitmap.Dispose()} + $friends=@(BlueFriends $path);$expectedCount=if($kind-eq'hill-edge-and-two-friends'){2}elseif($kind-in@('partial-and-one-friend','one-interior-friend','near-edge-interior-friend')){1}else{0} + Probe "actual-live-steering-border-$kind" ($friends.Count-eq$expectedCount-and@($friends|Where-Object {$_.y-lt400-or$_.y-gt600}).Count-eq0) @{friends=$friends;expectedCount=$expectedCount;scope='Actual BlueFriends AST on synthetic crop-edge and no-pair controls; no native verdict'} + } + if($BlueFriendsPng){ + $friends=@(BlueFriends $BlueFriendsPng|Sort-Object x) + $correct=$friends.Count-eq2-and$friends[0].sampledBluePixels-eq103-and$friends[1].sampledBluePixels-eq126-and[Math]::Abs($friends[0].x-1143.320388349515)-lt.001-and[Math]::Abs($friends[0].y-609.5533980582524)-lt.001-and[Math]::Abs($friends[1].x-1384.984126984127)-lt.001-and[Math]::Abs($friends[1].y-609.6190476190476)-lt.001 + Probe 'actual-native-blue-friend-regions-exclude-border-hill' $correct @{png=$BlueFriendsPng;sha256=(Get-FileHash -LiteralPath $BlueFriendsPng).Hash;friends=$friends;scope='Actual BlueFriends AST on NativeDepth3 live0/14 PNG: exact103/126 blue samples and known friend centroids; no live gesture/contact verdict'} + } $boardReader=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.FunctionDefinitionAst]-and$node.Name-eq'BoardScreen'},$true) $boardWait=$gestureAst.Find({param($node)$node-is[Management.Automation.Language.FunctionDefinitionAst]-and$node.Name-eq'WaitBoard'},$true) Probe 'actual-board-readiness-functions-present' ($null-ne$boardReader-and$null-ne$boardWait) 'Actual suite screen predicate and bounded wait'