import scala.collection.mutable

object Main extends App {
  import scala.io.StdIn.{readLine}
  import scala.collection.mutable._

  class Dice private (private val top:Int = 1, private val south:Int = 2, private val east:Int = 4){
    def turnUp:Dice = new Dice(south, 7 - top, east)
    def turnDown:Dice = new Dice(7 - south, top, east)
    def turnRight:Dice = new Dice(7 - east, south, top)
    def turnLeft:Dice = new Dice(east, south, 7 - top)
    def toIndex:Int = (top - 1) * 4 + (if (south > 3) 2 else 0) + (if (east > 3) 1 else 0) //0 until 24
    def topNumber:Int = top
  }
  case class Point(x:Int, y:Int){
    def up:Point = Point(x, y - 1)
    def right:Point = Point(x + 1, y)
    def down:Point = Point(x, y + 1)
    def left:Point = Point(x - 1, y)
  }
  class Saikorokun private (val position:Point, val dice:Dice) {
    def moveUp:Saikorokun = new Saikorokun(position.up, dice.turnUp)
    def moveRight:Saikorokun = new Saikorokun(position.right, dice.turnRight)
    def moveDown:Saikorokun = new Saikorokun(position.down, dice.turnDown)
    def moveLeft:Saikorokun = new Saikorokun(position.left, dice.turnLeft)
    def neighbors():List[Saikorokun] = List(moveUp, moveRight, moveDown, moveLeft)
  }
  object Saikorokun{
    def apply(start:Point):Saikorokun = new Saikorokun(start, Dice())
  }
  object Dice{
    def apply():Dice = new Dice()
  }
  class Room private (private val mArray:Array[Array[Array[Int]]], private val mGoals:List[(Point, Int)]){
    def isEmpty(saikorokun: Saikorokun):Boolean = (0 until mArray.length).contains(saikorokun.position.y) && (0 until mArray(0).length).contains(saikorokun.position.x) && mArray(saikorokun.position.y)(saikorokun.position.x)(saikorokun.dice.toIndex) == Room.unset
    def update(saikorokun:Saikorokun, value:Int):Unit = mArray(saikorokun.position.y)(saikorokun.position.x)(saikorokun.dice.toIndex) = value
    def isAllGoalReached():Boolean = mGoals.forall{case (p, d) ⇒ (0 until 4).exists{i ⇒ mArray(p.y)(p.x)((d - 1) * 4 + i) != Room.unset}}
    def minCost(point: Point, top:Int):Int = (0 until 4).map{i ⇒ mArray(point.y)(point.x)((top - 1) * 4 + i)}.filter{n ⇒ n != Room.unset}.min
  }
  object Room{
    def apply(strings:Array[String]):Room = {
      var goals :List[(Point, Int)] = Nil
      val array = Array.tabulate(strings.length){
        y ⇒ strings(y).zipWithIndex.map{
          case ('x', _) ⇒ Array.tabulate(24){_ ⇒ blocked}
          case (d, x) if d.isDigit ⇒ goals = (Point(x, y), d.asDigit)::goals
            Array.tabulate(24){_ ⇒ unset}
          case _ ⇒ Array.tabulate(24){_ ⇒ unset}
        }.toArray
      }
      new Room(array, goals)
    }
    private val blocked:Int = -1
    private val unset:Int = -2
  }
  def setShortestCount(room: Room, start:Point):Room = {
    var searching:mutable.Traversable[Saikorokun] = mutable.Queue(Saikorokun(start))
    var count = 0
    room(searching.head) = 0
    while (!room.isAllGoalReached()){
      count += 1
      searching = searching.flatMap{
        case saikoro ⇒ saikoro.neighbors().filter{case s ⇒ room.isEmpty(s)}
      }
      searching.foreach(s ⇒ room(s) = count)
    }
    return room
  }
  val Array(r, c) = readLine().split(' ').map(_.toInt)
  val strings = Array.tabulate(r){_ ⇒ readLine()}
  val start = (0 until r).flatMap{y ⇒ (0 until c).filter{x ⇒ strings(y)(x) == 'o'}.map{x ⇒ Point(x, y)}}
  val goal = (0 until r).flatMap{y ⇒ (0 until c).filter{x ⇒ strings(y)(x).isDigit}.map{x ⇒ Point(x, y)}}
  val minCost = start.map(p ⇒ setShortestCount(Room(strings), p))
  val min = goal.permutations.map{
    case goalPermutation ⇒ goalPermutation.zip(minCost).map{
      case (g, r) ⇒ r.minCost(g, strings(g.y)(g.x).asDigit)
    }.sum
  }.min
  println(min)
}
