// Week 3 – Two-dimensional arrays (matrices) in Go
// Run: go run ./w03/matrix
package main

import "fmt"

func print(m [][]int) {
	for _, row := range m {
		for _, v := range row {
			fmt.Printf("%4d", v)
		}
		fmt.Println()
	}
}

// diagonalSums: sum of the main diagonal (i == j) and of the anti-diagonal (i + j == n-1).
func diagonalSums(m [][]int) (int, int) {
	n, main, anti := len(m), 0, 0
	for i := 0; i < n; i++ {
		main += m[i][i]
		anti += m[i][n-1-i]
	}
	return main, anti
}

func newMatrix(rows, cols int) [][]int {
	m := make([][]int, rows)
	for i := range m {
		m[i] = make([]int, cols)
	}
	return m
}

func transpose(m [][]int) [][]int {
	t := newMatrix(len(m[0]), len(m))
	for i := range m {
		for j := range m[i] {
			t[j][i] = m[i][j]
		}
	}
	return t
}

// multiply: (n×k)·(k×m) – O(n·k·m)
func multiply(a, b [][]int) [][]int {
	n, k, m := len(a), len(b), len(b[0])
	c := newMatrix(n, m)
	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			for x := 0; x < k; x++ {
				c[i][j] += a[i][x] * b[x][j]
			}
		}
	}
	return c
}

func main() {
	m := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
	fmt.Println("m:")
	print(m)
	d1, d2 := diagonalSums(m)
	fmt.Println("main diagonal sum =", d1, ", anti-diagonal sum =", d2)

	r := [][]int{{1, 2, 3}, {4, 5, 6}}
	fmt.Println("transpose of r (2x3):")
	print(transpose(r))
	fmt.Println("r · I:")
	print(multiply(r, [][]int{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}))

	// True 2D array: [3][4]int – one contiguous block of memory, row-major
	var grid [3][4]int
	for i := 0; i < 3; i++ {
		for j := 0; j < 4; j++ {
			grid[i][j] = i*4 + j // exactly the row-major index
		}
	}
	fmt.Println("[3][4]int:", grid)

	// Slice of slices: the rows may have different lengths (as in Java)
	jagged := [][]int{{1, 2, 3}, {4, 5}, {6, 7, 8, 9}}
	fmt.Println("jagged:")
	print(jagged)

	flat := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	cols := 3
	fmt.Println("flat[1*3 + 2] = A[1][2] =", flat[1*cols+2])
}
