← Home
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

var in = bufio.NewReaderSize(os.Stdin, 1<<20)
var out = bufio.NewWriterSize(os.Stdout, 1<<20)

func askArea(i, j, k int) int64 {
	fmt.Fprintf(out, "1 %d %d %d\n", i, j, k)
	out.Flush()
	var x int64
	if _, err := fmt.Fscan(in, &x); err != nil {
		os.Exit(0)
	}
	return x
}

func askSign(i, j, k int) int {
	fmt.Fprintf(out, "2 %d %d %d\n", i, j, k)
	out.Flush()
	var x int
	if _, err := fmt.Fscan(in, &x); err != nil {
		os.Exit(0)
	}
	return x
}

func main() {
	defer out.Flush()

	var n int
	if _, err := fmt.Fscan(in, &n); err != nil {
		return
	}

	if n == 2 {
		fmt.Fprintln(out, "0 1 2")
		out.Flush()
		return
	}

	area := make([]int64, n+1)
	sign12 := make([]int, n+1)

	pos := make([]int, 0)
	neg := make([]int, 0)

	for i := 3; i <= n; i++ {
		area[i] = askArea(1, 2, i)
		sign12[i] = askSign(1, 2, i)
		if sign12[i] == 1 {
			pos = append(pos, i)
		} else {
			neg = append(neg, i)
		}
	}

	up := 0
	for _, v := range pos {
		if up == 0 || area[v] > area[up] {
			up = v
		}
	}

	down := 0
	for _, v := range neg {
		if down == 0 || area[v] > area[down] {
			down = v
		}
	}

	posChain := make([]int, 0)
	if up != 0 {
		s2 := askSign(1, up, 2)
		before := make([]int, 0)
		after := make([]int, 0)
		for _, v := range pos {
			if v == up {
				continue
			}
			s := askSign(1, up, v)
			if s == s2 {
				after = append(after, v)
			} else {
				before = append(before, v)
			}
		}
		sort.Slice(before, func(i, j int) bool {
			return area[before[i]] < area[before[j]]
		})
		sort.Slice(after, func(i, j int) bool {
			return area[after[i]] > area[after[j]]
		})
		posChain = append(posChain, before...)
		posChain = append(posChain, up)
		posChain = append(posChain, after...)
	}

	negChain := make([]int, 0)
	if down != 0 {
		s2 := askSign(1, down, 2)
		before := make([]int, 0)
		after := make([]int, 0)
		for _, v := range neg {
			if v == down {
				continue
			}
			s := askSign(1, down, v)
			if s == s2 {
				before = append(before, v)
			} else {
				after = append(after, v)
			}
		}
		sort.Slice(before, func(i, j int) bool {
			return area[before[i]] < area[before[j]]
		})
		sort.Slice(after, func(i, j int) bool {
			return area[after[i]] > area[after[j]]
		})
		negChain = append(negChain, before...)
		negChain = append(negChain, down)
		negChain = append(negChain, after...)
	}

	ans := make([]int, 0, n)
	ans = append(ans, 1)
	ans = append(ans, posChain...)
	ans = append(ans, 2)
	ans = append(ans, negChain...)

	fmt.Fprint(out, "0")
	for _, v := range ans {
		fmt.Fprintf(out, " %d", v)
	}
	fmt.Fprintln(out)
	out.Flush()
}