Go: package main

import "fmt"

var H, W int

type point struct {
	x, y int
}

func (p *point) add(q point) {
	p.x += q.x
	p.y += q.y
	if p.x < 0 {
		p.x += H
	}
	if p.y < 0 {
		p.y += W
	}
	p.x %= H
	p.y %= W
}

func isPalindrome(str string) bool {
	for i, j := 0, len(str)-1; i < j; i, j = i+1, j-1 {
		if str[i] != str[j] {
			return false
		}
	}
	return true
}

func magicSpel(arr []string) string {
	var ans string
	m := map[string]int{}
	for i := range arr {
		for j := range arr[i] {
			for _, d := range []point{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}} {
				cur := point{x: i, y: j}
				str := string(arr[cur.x][cur.y])
				cur.add(d)
				for i != cur.x || j != cur.y {
					str += string(arr[cur.x][cur.y])
					cur.add(d)
					if isPalindrome(str) {
						m[str] += 2
					} else {
						m[str]++
					}
				}
			}
		}
	}
	for s, v := range m {
		if 1 < v {
			if len(ans) < len(s) {
				ans = s
			} else if len(ans) == len(s) && s < ans {
				ans = s
			}
		}
	}

	if len(ans) == 0 {
		return "0"
	}

	return ans
}

func main() {
	for {
		fmt.Scan(&H, &W)
		if H == 0 && W == 0 {
			break
		}

		var arr []string

		for i := 0; i < H; i++ {
			var s string
			fmt.Scan(&s)
			arr = append(arr, s)
		}

		fmt.Println(magicSpel(arr))
	}
}

// 2 3
// ABC
// DEF

C++: #include <iostream>
#include <map>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;

struct P{
    int x;
    int y;
    P() {}
    ~P() {}
    P(const P& r) : x(r.x), y(r.y) {}
    P(int a, int b) : x(a), y(b) {}
};

struct Q{
    string spell;
    P pos; vector<P> visited;
    int dir;
    Q() {}
    ~Q() {}
    Q(const Q& r) : spell(r.spell), pos(r.pos),
                    visited(r.visited), dir(r.dir) {}
    Q(string s, P p, vector<P> v, int d) : spell(s), pos(p),
                                                   visited(v), dir(d) {} };

int dx[8] = {1, 1, 0, -1, -1, -1, 0,   1};
int dy[8] = {0, 1, 1, 1,   0, -1, -1, -1};

int main(){
    int h, w, x, y, z;
    for(; cin >> h >> w, h||w;){
        char field[20][20];
        map<string, int> found;
        for(char c = 'A'; c <= 'Z'; c++){
            found[ string(1, c) ] = 0;
        }
        queue< Q > que;
        vector<P> EMPTY(100);
        for(x = 0; x < h; x++){
            scanf(" %s", field[x]);
            for(y = 0; y < w; y++){
                found[ string(1, field[x][y]) ]++;
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 0) );
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 1) );
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 2) );
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 3) );
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 4) );
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 5) );
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 6) );
                que.push( Q( string(1, field[x][y]), P(x, y), EMPTY, 7) );
            }
        }
        string best = "0";
        for(int l = 1;; l++){
            while(true){
                if( que.empty() ) break;
                Q q = que.front();
                if( q.spell.size() != l ) break;
                que.pop();
                if( found[ q.spell ] < 2 ) continue;
                if( q.spell.size() > best.size() ||
                        (q.spell.size() == best.size() && q.spell < best) ){
                    best = q.spell;
                }
                int cx = q.pos.x, cy = q.pos.y, d = q.dir;
                int nx = (cx + dx[d] + h) % h, ny = (cy + dy[d] + w) % w;
                bool ok = true;
                for(vector<P>::iterator it = q.visited.begin();
                        it != q.visited.end(); it++){
                    if( (it->x == nx) && (it->y == ny) ){
                        ok = false;
                        break;
                    }
                }
                if( ok ){
                    string ns = q.spell;
                    ns.append(1, field[nx][ny]);
                    vector<P> nv = q.visited;
                    nv.push_back( P(cx, cy) );
                    que.push( Q( ns, P(nx, ny), nv, d ) );
                    if( found.find(ns) == found.end() ){
                        found[ns] = 1;
                    }else{
                        found[ns] ++;
                    }
                }
            }
            if( que.empty() ) break;
        }
        cout << best << endl;
    }
    return 0;
}

C++: #include<bits/stdc++.h>
using namespace std;

void reg(int& x,int m){
  x%=m;
  x+=m;
  x%=m;
  return;
}

int main(){
  int h,w;
  while(cin>>h>>w,h){
    vector<string> s(h);
    for(int i=0;i<h;i++) cin>>s[i];
    vector<int> dh={1,-1,0,0,1,1,-1,-1};
    vector<int> dw={0,0,1,-1,1,-1,1,-1};
    map<string,int> dic;
    for(int i=0;i<h;i++){
      for(int j=0;j<w;j++){
	for(int dir=0;dir<8;dir++){
	  string st="";
	  for(int k=0;;k++){
	    int ih=i+dh[dir]*k;
	    reg(ih,h);
	    int jw=j+dw[dir]*k;
	    reg(jw,w);
	    if(k!=0 && i==ih && j==jw) break;
	    st+=s[ih][jw];
	    if(k==0) continue;
	    dic[st]++;
	  }
	}
      }
    }
    string res="";
    for(auto it=dic.begin();it!=dic.end();it++){
      string st=it->first;
      int cnt=it->second;
      if(cnt>1){
	if(st.size()>res.size()){
	  res=st;
	}
	else if(st.size()==res.size()){
	  res=min(res,st);
	}
      }
    }

    cout<<(res!="" ? res : "0")<<endl;
  }
  return 0;

}

C++: #include <iostream>
#include <set>
#include <string>
#include <algorithm>

#define MAX 22

using namespace std;

char f[MAX][MAX];
int dx[8]={1,1,0,-1,-1,-1,0,1};   //右から
int dy[8]={0,1,1,1,0,-1,-1,-1};

int main(void)
{
	int h,w;
	int i1,i2,i3;
	int x,y;
	string s;
	int len;

	while(1){
		cin>>h>>w;
		if(h+w==0) break;

		for(i1=0;i1<h;i1++){
			for(i2=0;i2<w;i2++){
				cin>>f[i1][i2];
			}
		}


		set<string> p;
		set<string> ok;
		len=0;

		for(i1=0;i1<h;i1++){
			for(i2=0;i2<w;i2++){
				for(i3=0;i3<8;i3++){
					x=i2;
					y=i1;
					s="";
					while(1){

						s+=f[y][x];
						if(s.size()!=1 && p.find(s)!=p.end()) {
							ok.insert(s);
							len=max(len,(int)s.size());
						}
						else p.insert(s);
						
						x+=dx[i3];
						y+=dy[i3];
						if(x==w) x=0;
						if(y==h) y=0;
						if(x==-1) x=w-1;
						if(y==-1) y=h-1; 

						if(x==i2 && y==i1) break;
					}
				}
			}
		}

		set<string>::iterator it;
		set<string> ans;
		
		for(it=ok.begin();it!=ok.end();it++){
			if(len==(*it).size()) ans.insert((*it));
		}
		
		if(ans.empty()) cout<<"0"<<endl;
		else cout<<(*ans.begin())<<endl;

	}
	return 0;
}