diff --git a/bargraph.go b/bargraph.go index 11fa0c7..d07677d 100644 --- a/bargraph.go +++ b/bargraph.go @@ -41,7 +41,7 @@ func (r *barGraphCanvasRenderer) Layout(size fyne.Size) { } func (r *barGraphCanvasRenderer) MinSize() fyne.Size { - return fyne.NewSize(800, 500) + return fyne.NewSize(900, 550) } func (r *barGraphCanvasRenderer) Refresh() { @@ -62,18 +62,18 @@ func (r *barGraphCanvasRenderer) Refresh() { } // Padding - topPadding := float32(40) + topPadding := float32(75) bottomPadding := float32(80) leftPadding := float32(100) rightPadding := float32(20) - graphWidth := float32(800) - leftPadding - rightPadding - graphHeight := float32(500) - topPadding - bottomPadding + graphWidth := float32(900) - leftPadding - rightPadding + graphHeight := float32(550) - topPadding - bottomPadding // Background background := canvas.NewRectangle(color.NRGBA{R: 20, G: 20, B: 20, A: 255}) background.Move(fyne.NewPos(0, 0)) - background.Resize(fyne.NewSize(800, 500)) + background.Resize(fyne.NewSize(900, 550)) r.objects = append(r.objects, background) // Y-axis @@ -91,15 +91,27 @@ func (r *barGraphCanvasRenderer) Refresh() { r.objects = append(r.objects, xAxisLine) // Title - title := canvas.NewText(fmt.Sprintf("Probability Distribution: %d to %d (%d total outcomes)", stats.MinValue, stats.MaxValue, stats.Total), color.White) + title := canvas.NewText("Probability Distribution", color.White) title.TextSize = 16 - title.Move(fyne.NewPos(leftPadding, 10)) + title.Move(fyne.NewPos(leftPadding, 5)) r.objects = append(r.objects, title) + // Statistics info line 1 + statsLine1 := canvas.NewText(fmt.Sprintf("Range: %d to %d | Total Outcomes: %d", stats.MinValue, stats.MaxValue, stats.Total), color.White) + statsLine1.TextSize = 11 + statsLine1.Move(fyne.NewPos(leftPadding, 22)) + r.objects = append(r.objects, statsLine1) + + // Statistics info line 2 + statsLine2 := canvas.NewText(fmt.Sprintf("Average: %.2f | Most Common: %d", stats.Average, stats.MostCommon), color.White) + statsLine2.TextSize = 11 + statsLine2.Move(fyne.NewPos(leftPadding, 36)) + r.objects = append(r.objects, statsLine2) + // Y-axis label yLabel := canvas.NewText("Probability (%)", color.White) yLabel.TextSize = 12 - yLabel.Move(fyne.NewPos(10, topPadding+graphHeight/2-30)) + yLabel.Move(fyne.NewPos(15, topPadding+graphHeight/2-40)) r.objects = append(r.objects, yLabel) // X-axis label @@ -182,6 +194,6 @@ func ShowStatisticsWindow(expression string) { // Create and show the window window := fyne.CurrentApp().NewWindow("Statistics: " + expression) window.SetContent(graph) - window.Resize(fyne.NewSize(800, 500)) + window.Resize(fyne.NewSize(900, 550)) window.Show() } diff --git a/statistics.go b/statistics.go index 4913c14..0a7c84a 100644 --- a/statistics.go +++ b/statistics.go @@ -15,6 +15,8 @@ type DiceStatistics struct { Results map[int]int // outcome -> count of ways to achieve it Total int // total number of possible outcomes Percentages map[int]float64 // outcome -> percentage + Average float64 // average/mean value + MostCommon int // most common (median) value } // CalculateDiceStatistics calculates the theoretical distribution of possible outcomes for a dice expression @@ -58,13 +60,18 @@ func CalculateDiceStatistics(expression string) (*DiceStatistics, error) { percentages[value] = (float64(count) / float64(totalCount)) * 100 } - return &DiceStatistics{ + stats := &DiceStatistics{ MinValue: minVal, MaxValue: maxVal, Results: outcomes, Total: totalCount, Percentages: percentages, - }, nil + } + + // Calculate average and most common value + stats.calculateAverageAndMedian() + + return stats, nil } // Term represents a single term in the expression (dice roll or constant) @@ -290,3 +297,39 @@ func (s *DiceStatistics) GetMaxPercentage() float64 { } return maxPercentage } + +// calculateAverageAndMedian calculates the average and most common value +func (s *DiceStatistics) calculateAverageAndMedian() { + if len(s.Results) == 0 { + s.Average = 0 + s.MostCommon = 0 + return + } + + // Calculate average (mean) + sum := 0 + totalCount := 0 + for value, count := range s.Results { + sum += value * count + totalCount += count + } + s.Average = float64(sum) / float64(totalCount) + + // Find most common (mode) - the value with highest count + maxCount := 0 + for value, count := range s.Results { + if count > maxCount { + maxCount = count + s.MostCommon = value + } + } + + // If there are tied values, choose the smallest one + if maxCount > 0 { + for value, count := range s.Results { + if count == maxCount && value < s.MostCommon { + s.MostCommon = value + } + } + } +}