#include <stdio.h>
#include <queue>
#include <vector>
#include <algorithm>
#define IN -1
#define OUT -2
#define DRAGON 0
#define FREE -3
#define BLOCKED -4
using namespace std;
typedef struct {
int i, j;
int d;
} TPos;
typedef struct compare {
bool operator () (const TPos a, const TPos b) {
return a.d < b.d;
}
} compare;
int R, C, Ii, Ij, m = 99999999, reached;
int M[1005][1005];
vector <TPos> H;
bool comp (TPos a, TPos b) {
return (a.d < b.d) ? true : false;
}
void read() {
scanf("%d %d\n", &R, &C);
char buffer[1005];
for (int i = 0; i < R; ++i) {
fgets(buffer, 1005, stdin);
for (int j = 0; j < C; ++j) {
switch (buffer[j]) {
case '.': M[i][j] = FREE; break;
case 'D': M[i][j] = DRAGON; break;
case '*': M[i][j] = BLOCKED; break;
case 'O': M[i][j] = OUT; break;
case 'I': {
M[i][j] = IN;
Ii = i; Ij = j;
break;
}
default: break;
}
}
}
}
int findDist (int i, int j) {
int dist[1005][1005] = {{0}};
dist[i][j] = 1;
queue < pair <int, int> > Q;
Q.push(make_pair(i, j));
while (!Q.empty()) {
auto c = Q.front();
if (M[c.first][c.second] == DRAGON) return dist[c.first][c.second]-1;
if (c.first > 0 && !dist[c.first-1][c.second] && M[c.first-1][c.second] > BLOCKED) {
dist[c.first-1][c.second] = dist[c.first][c.second] + 1;
Q.push(make_pair(c.first-1, c.second));
}
if (c.first < R-1 && !dist[c.first+1][c.second] && M[c.first+1][c.second] > BLOCKED) {
dist[c.first+1][c.second] = dist[c.first][c.second] + 1;
Q.push(make_pair(c.first+1, c.second));
}
if (c.second > 0 && !dist[c.first][c.second-1] && M[c.first][c.second-1] > BLOCKED) {
dist[c.first][c.second-1] = dist[c.first][c.second] + 1;
Q.push(make_pair(c.first, c.second - 1));
}
if (c.second < C-1 && !dist[c.first][c.second+1] && M[c.first][c.second+1] > BLOCKED) {
dist[c.first][c.second+1] = dist[c.first][c.second] + 1;
Q.push(make_pair(c.first, c.second + 1));
}
Q.pop();
}
return -999; //shouldn't happen
}
int solve () {
TPos init = {Ii, Ij, 999};
H.push_back(init);
push_heap(H.begin(), H.end(), compare());
while (!H.empty()) {
auto c = H.front();
if (c.d < m) m = c.d;
//printf("%d %d %d\n", c.i, c.j, c.d);
pop_heap(H.begin(), H.end(), comp);
H.pop_back();
if (c.i > 0) {
if (M[c.i-1][c.j] == OUT) {
return m;
} else if (M[c.i-1][c.j] == FREE) {
M[c.i-1][c.j] = findDist(c.i-1, c.j);
TPos temp = {c.i-1, c.j, M[c.i-1][c.j]};
H.push_back(temp), push_heap(H.begin(), H.end(), compare());
}
}
if (c.i < R-1) {
if (M[c.i+1][c.j] == OUT) {
return m;
} else if (M[c.i+1][c.j] == FREE) {
M[c.i+1][c.j] = findDist(c.i+1, c.j);
TPos temp = {c.i+1, c.j, M[c.i+1][c.j]};
H.push_back(temp), push_heap(H.begin(), H.end(), compare());
}
}
if (c.j > 0) {
if (M[c.i][c.j-1] == OUT) {
return m;
} else if (M[c.i][c.j-1] == FREE) {
M[c.i][c.j-1] = findDist(c.i, c.j-1);
TPos temp = {c.i, c.j-1, M[c.i][c.j-1]};
H.push_back(temp), push_heap(H.begin(), H.end(), compare());
}
}
if (c.j < C-1) {
if (M[c.i][c.j+1] == OUT) {
return m;
} else if (M[c.i][c.j+1] == FREE) {
M[c.i][c.j+1] = findDist(c.i, c.j+1);
TPos temp = {c.i, c.j+1, M[c.i][c.j+1]};
H.push_back(temp), push_heap(H.begin(), H.end(), compare());
}
}
}
return -1;
}
int main (void) {
freopen("barbar.in", "r", stdin);
freopen("barbar.out", "w", stdout);
read();
make_heap(H.begin(), H.end(), compare());
printf("%d", solve());
return 0;
}