package main import ( "encoding/csv" "fmt" "github.com/lucasb-eyer/go-colorful" "image" "image/draw" "image/png" "log" "os" "strconv" ) const OutputEnable = true const CreateImage = true const LightColor = `#00fbfb` const DarkColor = `#330066` func main() { number, err := strconv.Atoi(os.Args[1]) if err != nil { log.Fatal("Please enter a valid number.") } matrice := make([][]int, number+1) var inverses []int for i := 0; i <= number; i++ { matrice[i] = make([]int, number+1) for j := 0; j <= number; j++ { multiple := (j * i) % number matrice[i][j] = multiple if multiple == 1 { inverses = append(inverses, j) } } } // Save it if err := csvExport(matrice); err != nil { log.Fatal(err) } // output it if OutputEnable { fmt.Print("\t") for i := 0; i <= number; i++ { fmt.Print(i, "\t") } fmt.Println() for rownumber, row := range matrice { fmt.Print(rownumber, "\t") for _, col := range row { fmt.Print(col, "\t") } fmt.Println() } fmt.Println("Inverses: ", inverses) } // Build an image if CreateImage { log.Println("Starting image creation...") size := getImageBlockSize(number) lightColor, _ := colorful.Hex(LightColor) darkColor, _ := colorful.Hex(DarkColor) img := image.NewRGBA(image.Rect(0, 0, number*size+size-1, number*size+size-1)) for rownumber, row := range matrice { for colnumber, col := range row { x := colnumber*size - 1 y := rownumber*size - 1 draw.Draw(img, image.Rect(x, y, x+size, y+size), &image.Uniform{lightColor.BlendRgb(darkColor, float64(col)/float64(number-1))}, image.ZP, draw.Src) } } imgpath := strconv.Itoa(number) + "x.png" toimg, err := os.Create(imgpath) if err != nil { log.Fatal(err) } defer toimg.Close() err = png.Encode(toimg, img) if err != nil { log.Fatal(err) } log.Println("Image saved to " + imgpath) } } func csvExport(data [][]int) error { file, err := os.Create("result.csv") if err != nil { return err } defer file.Close() writer := csv.NewWriter(file) defer writer.Flush() //Prepare dataStrings := make([][]string, len(data)) for in := range data { dataStrings[in] = make([]string, len(data[in])) for in2, val2 := range data[in] { dataStrings[in][in2] = strconv.Itoa(val2) } } for _, value := range dataStrings { if err := writer.Write(value); err != nil { return err // let's return errors if necessary, rather than having a one-size-fits-all error handler } } return nil } func getImageBlockSize(number int) int { if number < 50 { return 10 } if number < 100 { return 8 } if number < 200 { return 4 } if number < 500 { return 3 } if number < 900 { return 2 } return 1 }