00001 //---------------------------------------------------------------------------- 00002 /** @file 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "Hex.hpp" 00007 #include "BitsetIterator.hpp" 00008 #include "TwoDistance.hpp" 00009 #include "VCSet.hpp" 00010 00011 using namespace benzene; 00012 00013 //---------------------------------------------------------------------------- 00014 00015 TwoDistance::TwoDistance(NeighbourType ntype) 00016 : m_brd(0), 00017 m_ntype(ntype), 00018 m_score(0) 00019 { 00020 } 00021 00022 TwoDistance::~TwoDistance() 00023 { 00024 } 00025 00026 //---------------------------------------------------------------------------- 00027 00028 void TwoDistance::Evaluate(const HexBoard& brd) 00029 { 00030 m_brd = &brd; 00031 for (BWIterator it; it; ++it) 00032 ComputeScores(*it, m_scores[*it]); 00033 ComputeScore(); 00034 } 00035 00036 void TwoDistance::ComputeScores(HexColor color, HexEval* out) 00037 { 00038 HexEval dist[2][BITSETSIZE]; 00039 ComputeDistanceToEdge(color, HexPointUtil::colorEdge1(color), dist[0]); 00040 ComputeDistanceToEdge(color, HexPointUtil::colorEdge2(color), dist[1]); 00041 00042 for (BoardIterator it(m_brd->Const().Interior()); it; ++it) 00043 { 00044 if (m_brd->GetPosition().IsOccupied(*it)) 00045 out[*it] = 0; 00046 else 00047 out[*it] = TwoDistUtil::AddDistance(dist[0][*it], dist[1][*it]); 00048 //out[*it] = dist[0][*it]; 00049 } 00050 } 00051 00052 void TwoDistance::FindBest(HexEval* po, HexPoint& who, int& count) 00053 { 00054 HexEval best = EVAL_INFINITY; 00055 who = INVALID_POINT; 00056 count = 1; 00057 00058 for (BitsetIterator it(m_brd->GetPosition().GetEmpty()); it; ++it) 00059 { 00060 if (po[*it] < best) 00061 { 00062 best = po[*it]; 00063 who = *it; 00064 count=1; 00065 } 00066 else if (po[*it] == best) 00067 count++; 00068 } 00069 00070 HexAssert(who != INVALID_POINT); 00071 HexAssert(best != EVAL_INFINITY); 00072 } 00073 00074 void TwoDistance::ComputeScore() 00075 { 00076 HexPoint black, white; 00077 int black_count, white_count; 00078 int SCALE_FACTOR = 1; // FIXME: what is a good value? 00079 00080 FindBest(m_scores[BLACK], black, black_count); 00081 FindBest(m_scores[WHITE], white, white_count); 00082 00083 m_score = (black - white)*SCALE_FACTOR + (black_count - white_count); 00084 } 00085 00086 //---------------------------------------------------------------------------- 00087 00088 bool TwoDistance::IsAdjacent(HexColor color, HexPoint p1, HexPoint p2) 00089 { 00090 VC vc; 00091 if (m_brd->Cons(color).SmallestVC(p1, p2, VC::FULL, vc)) { 00092 switch(m_ntype) { 00093 case ADJACENT: return vc.IsEmpty(); 00094 case FULL_VC: return true; 00095 } 00096 } 00097 return false; 00098 } 00099 00100 void TwoDistance::ComputeDistanceToEdge(HexColor color, 00101 HexPoint edge, 00102 HexEval* out) 00103 { 00104 SetAllToInfinity(out); 00105 00106 // 00107 // FIXME: how to sort queue by increasing order without using 00108 // negative priorities? 00109 // 00110 // q(std::less<std::pair<int, HexPoint> >) 00111 // 00112 // doesn't seem to work. 00113 // 00114 00115 std::priority_queue<std::pair<int, HexPoint> > q; 00116 std::set<HexPoint> done; 00117 std::set<HexPoint> once; 00118 00119 // add immediate neighbours of edge 00120 for (BitsetIterator it(m_brd->GetPosition().GetEmpty()); it; ++it) 00121 { 00122 if (IsAdjacent(color, *it, edge)) 00123 { 00124 out[*it] = 1; 00125 q.push(std::make_pair(-1, *it)); 00126 done.insert(*it); 00127 } 00128 } 00129 00130 while (!q.empty()) { 00131 std::pair<int, HexPoint> pp = q.top(); 00132 q.pop(); 00133 00134 int dist = -pp.first; 00135 HexPoint p = pp.second; 00136 00137 for (BitsetIterator it(m_brd->GetPosition().GetEmpty()); it; ++it) 00138 { 00139 if (IsAdjacent(color, *it, p)) 00140 { 00141 // it has been seen at least twice before, ignore it. 00142 if (done.count(*it)) 00143 continue; 00144 // it has been seen once before, add it to queue 00145 // and add to 'done'. 00146 else if (once.count(*it)) 00147 { 00148 out[*it] = dist+1; 00149 q.push(std::make_pair(-(dist+1), *it)); 00150 done.insert(*it); 00151 } 00152 // it hasn't been seen before: add it to 'once'. 00153 else 00154 once.insert(*it); 00155 } 00156 } 00157 } 00158 } 00159 00160 void TwoDistance::SetAllToInfinity(HexEval* out) 00161 { 00162 for (BoardIterator it(m_brd->Const().Interior()); it; ++it) 00163 out[*it] = EVAL_INFINITY; 00164 } 00165 00166 //---------------------------------------------------------------------------- 00167 00168 HexEval TwoDistUtil::AddDistance(HexEval a, HexEval b) 00169 { 00170 if (a == EVAL_INFINITY || b == EVAL_INFINITY) 00171 return EVAL_INFINITY; 00172 return a + b; 00173 } 00174 00175 //----------------------------------------------------------------------------