package main

import(
	"fmt"
)
// import "time"

// ボードの状態
type Board = [9]int
// パズル全体
type Puzzle struct {
	Brd Board
	Zero int
	Moved int
}
var FINISH_STATE Board = Board{ 1, 2, 3, 4, 5, 6, 7, 8, 0 }
func (this *Puzzle) IsDone() bool {
	return this.Brd == FINISH_STATE
}

func FindZero(board* Board) int {
	for i, v := range board {
		if v == 0 {
			return i
		}
	}
	fmt.Println("Error 0 Not found")
	return -1
}


// 移動可能か
func (this *Puzzle) CanUp() bool {
	return 2 < this.Zero
}

func (this *Puzzle) CanDown() bool {
	return this.Zero < 6
}

func (this *Puzzle) CanLeft() bool {
	return this.Zero % 3 != 0
}

func (this *Puzzle) CanRight() bool {
	return this.Zero % 3 != 2
}

// 移動後の状態を
func (this *Puzzle) Up() Puzzle {
	return Puzzle{ Move(this.Brd, this.Zero, -3), this.Zero - 3, this.Moved + 1 }
}
func (this *Puzzle) Down() Puzzle {
	return Puzzle{ Move(this.Brd, this.Zero, +3), this.Zero + 3, this.Moved + 1 }
}
func (this *Puzzle) Left() Puzzle {
	return Puzzle{ Move(this.Brd, this.Zero, -1), this.Zero -1, this.Moved + 1 }
}
func (this *Puzzle) Right() Puzzle {
	return Puzzle{ Move(this.Brd, this.Zero, 1), this.Zero + 1, this.Moved + 1 }
}
// common move
func Move(board Board, zero int, direction int) Board {
	board[zero], board[zero + direction] = board[zero + direction], board[zero]
	return board
}


type Memo struct {
	Data map[int][]Board
}
func NewMemo() Memo{
	// var data [9][9][]Board = [9][9][]Board{}
	// for i := 0; i < 9; i++ {
	// 	for j := 0; j < 9; j++ {
	// 		data[i][j] = make([]Board, 0)
	// 	}
	// }
	return Memo{ make(map[int][]Board) }
}
func (m *Memo) Add(board Board) {
	index := board[0] * 10000 + board[1] * 1000 + board[2] * 100 + board[3] * 10 + board[4] * 1
	m.Data[index] = append(m.Data[index], board)
}

func (m *Memo) HasTried(board *Board) bool {
	index := board[0] * 10000 + board[1] * 1000 + board[2] * 100 + board[3] * 10 + board[4] * 1
	for _, state := range m.Data[index] {
		if state == *board {
			return true
		}
	}
	return false
}



func Solve(board Board) int {
	// prepare
	queue := make([]Puzzle, 0)
	pzl := Puzzle{ board, FindZero(&board), 0 }
	queue = append(queue, pzl)
	memo := NewMemo()

	count := 0
	for len(queue) != 0 {
		count++
		// before := time.Now()

		e := queue[0]
		queue = queue[1:]

		if e.IsDone() {
			// fmt.Printf("count:%d\n", count)
			return e.Moved
		} else {
			// memo = append(memo, e.Brd)
			memo.Add(e.Brd)
		}
		if e.CanUp() {
			// fmt.Println("up")
			newPzl := e.Up()
			if !memo.HasTried(&newPzl.Brd) {
				queue = append(queue, newPzl)
			}
		}
		if e.CanDown() {
			// fmt.Println("down")
			newPzl := e.Down()
			if !memo.HasTried(&newPzl.Brd) {
				queue = append(queue, newPzl)
			}
		}
		if e.CanLeft() {
			// fmt.Println("left")
			newPzl := e.Left()
			if !memo.HasTried(&newPzl.Brd) {
				queue = append(queue, newPzl)
			}
		}
		if e.CanRight() {
			// fmt.Println("right")
			newPzl := e.Right()
			if !memo.HasTried(&newPzl.Brd) {
				queue = append(queue, newPzl)
			}
		}
		// fmt.Printf("spend: %v\n", time.Now().Sub(before))
	}
	return -1
}

func main() {
	var board Board
	for i := 0; i < 9; i++ {
		var v int
		fmt.Scanf("%d", &v)
		board[i] = v
	}
	result := Solve(board)
	fmt.Println(result)
}


Measured memory_bytes: 118964