VBAF.Business.MarketEnvironment.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Multi-Agent Market Environment .DESCRIPTION Simulates a competitive market where multiple company agents interact, compete, and learn from each other. .NOTES Part of VBAF Phase 2 - Week 6 Features: Competition, supply/demand, market events, game theory #> # Load dependencies $basePath = $PSScriptRoot . "$basePath\VBAF.Business.CompanyAgent.ps1" class MarketEnvironment { # Market participants [System.Collections.ArrayList]$Companies # Market state [int]$CurrentQuarter [int]$CurrentYear [double]$EconomyGrowth [double]$InterestRate [string]$MarketCondition [double]$TotalMarketSize # History [System.Collections.ArrayList]$History # Configuration [hashtable]$Config # Constructor MarketEnvironment() { $this.Companies = New-Object System.Collections.ArrayList $this.History = New-Object System.Collections.ArrayList $this.CurrentQuarter = 1 $this.CurrentYear = 1 $this.EconomyGrowth = 0.02 $this.InterestRate = 0.05 $this.MarketCondition = "Neutral" $this.TotalMarketSize = 1000000.0 $this.Config = @{ EnableRandomEvents = $true EventProbability = 0.10 EnableCompetition = $true EnableSupplyDemand = $true } } # Add company to market [void] AddCompany([CompanyAgent]$company) { $this.Companies.Add($company) | Out-Null # Update company's external environment $company.State.EconomyGrowth = $this.EconomyGrowth $company.State.InterestRate = $this.InterestRate $company.State.MarketCondition = $this.MarketCondition $company.State.CompetitorCount = $this.Companies.Count - 1 Write-Host "? Added $($company.Name) to market" -ForegroundColor Green } # Simulate one quarter [hashtable] SimulateQuarter() { Write-Host "`n=== Quarter $($this.CurrentQuarter), Year $($this.CurrentYear) ===" -ForegroundColor Cyan # 1. Update global state $this.UpdateGlobalState() # 2. Random events (recessions, booms, disruptions) if ($this.Config.EnableRandomEvents) { $this.CheckForRandomEvents() } # 3. Each company observes and decides $actions = @{} foreach ($company in $this.Companies) { # Update company's view of environment $company.State.EconomyGrowth = $this.EconomyGrowth $company.State.InterestRate = $this.InterestRate $company.State.MarketCondition = $this.MarketCondition $company.State.CompetitorCount = $this.Companies.Count - 1 # Company decides action $action = $company.DecideAction() $actions[$company.Name] = $action Write-Host " $($company.Name): $($action.Name)" -ForegroundColor Gray } # 4. Resolve interactions (competition!) $interactions = $this.ResolveInteractions($actions) # 5. Execute actions and calculate outcomes $results = @{} foreach ($company in $this.Companies) { $action = $actions[$company.Name] $interaction = $interactions[$company.Name] # Apply interaction effects first $this.ApplyInteractionEffects($company, $interaction) # Then execute company's action (without internal simulation) $result = $company.ExecuteAction($action) # NOW simulate the company's quarter (market controls timing) $company.SimulateQuarter() $results[$company.Name] = $result } # 6. Each company learns foreach ($company in $this.Companies) { $result = $results[$company.Name] $company.Learn($result.Reward) } # 7. Record history $snapshot = $this.CaptureSnapshot($results) $this.History.Add($snapshot) | Out-Null # 8. Increment time $this.CurrentQuarter++ if ($this.CurrentQuarter -gt 4) { $this.CurrentQuarter = 1 $this.CurrentYear++ } return $snapshot } # Update global economic conditions hidden [void] UpdateGlobalState() { # Economy cycles if ($this.CurrentQuarter % 4 -eq 0) { # Slight randomness in economy each year $change = (Get-Random -Minimum -0.01 -Maximum 0.01) $this.EconomyGrowth += $change $this.EconomyGrowth = [Math]::Max(-0.05, [Math]::Min(0.10, $this.EconomyGrowth)) } # Market condition based on economy if ($this.EconomyGrowth -gt 0.04) { $this.MarketCondition = "Bullish" } elseif ($this.EconomyGrowth -lt 0.0) { $this.MarketCondition = "Bearish" } else { $this.MarketCondition = "Neutral" } # Total market size grows with economy $this.TotalMarketSize *= (1 + $this.EconomyGrowth / 4) } # Check for random market events hidden [void] CheckForRandomEvents() { $roll = Get-Random -Minimum 0.0 -Maximum 1.0 if ($roll -lt $this.Config.EventProbability) { $eventType = Get-Random -Minimum 0 -Maximum 5 switch ($eventType) { 0 { # Recession Write-Host " ? EVENT: Economic Recession!" -ForegroundColor Red $this.EconomyGrowth = -0.03 $this.MarketCondition = "Bearish" } 1 { # Boom Write-Host " ? EVENT: Economic Boom!" -ForegroundColor Green $this.EconomyGrowth = 0.08 $this.MarketCondition = "Bullish" } 2 { # Tech disruption Write-Host " ?? EVENT: Technological Breakthrough!" -ForegroundColor Yellow # Random company gets innovation boost if ($this.Companies.Count -gt 0) { $luckyCompany = $this.Companies[(Get-Random -Minimum 0 -Maximum $this.Companies.Count)] $luckyCompany.State.InnovationScore += 0.2 Write-Host " ? $($luckyCompany.Name) gains innovation advantage!" -ForegroundColor Yellow } } 3 { # Regulatory change Write-Host " ?? EVENT: New Regulation!" -ForegroundColor Magenta foreach ($company in $this.Companies) { $company.State.Costs *= 1.05 # 5% cost increase } } 4 { # Consumer trend shift Write-Host " ?? EVENT: Consumer Preferences Shift!" -ForegroundColor Cyan # Rewards quality over price foreach ($company in $this.Companies) { if ($company.State.ProductQuality -gt 0.7) { $company.State.CustomerSatisfaction += 0.05 } } } } } } # Resolve competitive interactions hidden [hashtable] ResolveInteractions([hashtable]$actions) { $interactions = @{} # Initialize interactions for each company foreach ($company in $this.Companies) { $interactions[$company.Name] = @{ PriceAdvantage = 0.0 MarketShareChange = 0.0 CompetitivePressure = 0.0 } } # Price competition if ($this.Config.EnableCompetition) { $this.ResolvePriceCompetition($interactions) } # Market share competition $this.ResolveMarketShareCompetition($interactions) return $interactions } # Price competition (Bertrand model) hidden [void] ResolvePriceCompetition([hashtable]$interactions) { # Find average price $totalPrice = 0.0 $count = 0 foreach ($company in $this.Companies) { $totalPrice += $company.State.AveragePrice $count++ } $avgPrice = if ($count -gt 0) { $totalPrice / $count } else { 100.0 } # Companies below average gain advantage foreach ($company in $this.Companies) { $priceDiff = ($avgPrice - $company.State.AveragePrice) / $avgPrice $interactions[$company.Name].PriceAdvantage = $priceDiff * 0.1 # 10% effect } } # Market share competition hidden [void] ResolveMarketShareCompetition([hashtable]$interactions) { # Calculate total current market share $totalShare = 0.0 foreach ($company in $this.Companies) { $totalShare += $company.State.MarketShare } # If total exceeds 100%, rebalance if ($totalShare -gt 1.0) { foreach ($company in $this.Companies) { $company.State.MarketShare = $company.State.MarketShare / $totalShare } } # Companies with higher quality/innovation gain share foreach ($company in $this.Companies) { $qualityAdvantage = ($company.State.ProductQuality - 0.5) * 0.02 $innovationAdvantage = $company.State.InnovationScore * 0.01 $interactions[$company.Name].MarketShareChange = $qualityAdvantage + $innovationAdvantage } } # Apply interaction effects to company hidden [void] ApplyInteractionEffects([CompanyAgent]$company, [hashtable]$interaction) { # Price advantage affects revenue if ($interaction.PriceAdvantage -ne 0) { # This will be reflected in next quarter's revenue $company.State.CustomerSatisfaction += $interaction.PriceAdvantage * 0.5 $company.State.CustomerSatisfaction = [Math]::Max(0.1, [Math]::Min(1.0, $company.State.CustomerSatisfaction)) } # Market share changes if ($interaction.MarketShareChange -ne 0) { $company.State.MarketShare += $interaction.MarketShareChange $company.State.MarketShare = [Math]::Max(0.0, [Math]::Min(0.5, $company.State.MarketShare)) } } # Capture market snapshot hidden [hashtable] CaptureSnapshot([hashtable]$results) { $snapshot = @{ Quarter = $this.CurrentQuarter Year = $this.CurrentYear MarketCondition = $this.MarketCondition EconomyGrowth = $this.EconomyGrowth Companies = @{} } foreach ($company in $this.Companies) { $snapshot.Companies[$company.Name] = @{ Cash = $company.State.Cash Revenue = $company.State.Revenue Profit = $company.State.Profit MarketShare = $company.State.MarketShare CustomerSatisfaction = $company.State.CustomerSatisfaction Action = $results[$company.Name].Action.Name Reward = $results[$company.Name].Reward } } return $snapshot } # Get market summary [hashtable] GetMarketSummary() { $summary = @{ Quarter = $this.CurrentQuarter Year = $this.CurrentYear MarketCondition = $this.MarketCondition EconomyGrowth = $this.EconomyGrowth TotalCompanies = $this.Companies.Count Companies = @() } foreach ($company in $this.Companies) { $summary.Companies += @{ Name = $company.Name Cash = $company.State.Cash Profit = $company.State.Profit MarketShare = $company.State.MarketShare Revenue = $company.State.Revenue } } return $summary } # Display market status [void] DisplayMarketStatus() { Write-Host "`n+------------------------------------------------------+" -ForegroundColor Cyan Write-Host "� MARKET STATUS �" -ForegroundColor Cyan Write-Host "+------------------------------------------------------+" -ForegroundColor Cyan Write-Host "" Write-Host "Quarter: Q$($this.CurrentQuarter) Y$($this.CurrentYear)" -ForegroundColor White Write-Host "Economy: $($this.EconomyGrowth.ToString('P2')) growth - $($this.MarketCondition)" -ForegroundColor Yellow Write-Host "Companies: $($this.Companies.Count)" -ForegroundColor White Write-Host "" Write-Host "Rankings by Market Share:" -ForegroundColor Cyan $ranked = $this.Companies | Sort-Object { $_.State.MarketShare } -Descending $rank = 1 foreach ($company in $ranked) { $profitColor = if ($company.State.Profit -gt 0) { "Green" } else { "Red" } Write-Host "#$rank " -NoNewline -ForegroundColor Gray Write-Host "$($company.Name): " -NoNewline -ForegroundColor White Write-Host "$($company.State.MarketShare.ToString('P2')) share, " -NoNewline -ForegroundColor Cyan Write-Host "`$($company.State.Profit.ToString('N0')) profit" -NoNewline -ForegroundColor $profitColor Write-Host ", `$($company.State.Cash.ToString('N0')) cash" -ForegroundColor Gray $rank++ } } } |