module AIReversi (aiDecision ) where import Graphics.Rendering.OpenGL import Graphics.UI.GLUT import States import VectorMaps import Control.Applicative import qualified Data.Map as Map import System.Random import General (listRandomSelect , listConnectedComponent , selectByInstanceF , differenceList) import BoardOperater import Data.List import Data.Tuple myTurn :: GameTurn myTurn = Turn2P myStone :: MState -> GStone myStone mst = getTurnStone mst myTurn makePuttable :: MState -> GStone -> GBoardCells -> [(Vector2 GLint)] makePuttable mst s gbcs = filter (dPuttableCell s gbcs) (bCellsList mst) ------AIボードの作成 makeAIBoard :: GStone -> GBoardCells -> (Vector2 GLint) -> GBoardCells makeAIBoard s gbcs cPos = putStone s gbcs cPos ------AIボードの作成(辺座標) makeAIBoardEdge :: MState -> GStone -> GBoardCells -> EdgeType -> (Vector2 GLint) -> GBoardCells makeAIBoardEdge mst s gbcs eType cPos = putStone s gbcs (tCoordEdgeIntoNormal mst eType cPos) ------AIボードの作成(角座標) makeAIBoardCorner :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> (Vector2 GLint) -> GBoardCells makeAIBoardCorner mst s gbcs baseP cPos = putStone s gbcs (tCoordCornerIntoNormal mst baseP cPos) ------AI aiDecision :: MState -> ((Vector2 GLint) , AIMValues) aiDecision mst =let aipv = (setAIPreValue) $! mst gbcs = gBoardCells mst in putPosVector mst (smallValue0 valueRangeSup (map (makePutValue mst aipv) (makePuttable mst (myStone mst) gbcs))) ------PutValueListからおく位置を決定する putPosVector :: MState ->[((Vector2 GLint) , GLint)] -> ((Vector2 GLint) , AIMValues) putPosVector mst xs = let sumValue = sum (map snd xs) rnd = randomR (1 , sumValue) (randGen mst) pV = putPosVector' mst xs sumValue (fst rnd) in ((fst pV) , (AIMValues (snd rnd) (MValues [(snd pV) , 0] [0.0]))) ------PutValueListからおく位置を決定する(再帰) putPosVector' :: MState -> [((Vector2 GLint) , GLint)] -> GLint -> GLint -> ((Vector2 GLint) ,GLint) putPosVector' mst [] sv rnd = ((Vector2 0 0) , 0) -----念のため putPosVector' mst (x : xs) sv rnd = let cv = snd x in if rnd >= (sv - cv) then (fst x , cv) else putPosVector' mst xs (sv - cv) rnd ------開放度理論に使う深さ ddeg0 :: GLint ddeg0 = 3 ------小さい値を切り捨て valueRangeSup :: GLint valueRangeSup = 50 ------AIPreValueのセット setAIPreValue :: MState -> AIPreValue setAIPreValue mst = let gbcs = gBoardCells mst puttable = makePuttable mst (myStone mst) gbcs puttable' = differenceList puttable (cXCornerAllSet mst) s = myStone mst leastOpendeg = minimum (map (openDegreeTheoremExpand' ddeg0 mst s s gbcs) puttable') in (AIPreValue leastOpendeg) ------PutValueList の作成 makePutValueList :: MState -> AIPreValue -> [(Vector2 GLint)] -> [((Vector2 GLint) , GLint)] makePutValueList mst aipv (v:vs) = (makePutValue mst aipv v) : (makePutValueList mst aipv vs) makePutValue :: MState -> AIPreValue -> (Vector2 GLint) -> ((Vector2 GLint) , GLint) makePutValue mst aipv v = let value = 100000 value2 = aiConstruct aiGeneraters aipv mst v value in (v , (max value2 1)) -------PutValueListにおいて最大値と一定の差が付いたときvalueを0にする smallValue0 :: GLint -> [((Vector2 GLint) , GLint)] -> [((Vector2 GLint) , GLint)] smallValue0 a xs = let mxs = maximum (map snd xs) in map (\(v,x) -> if (mxs `quot` x) <= a then (v,x) else (v,0) ) xs type AIGenerater = (AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint) ------AIを構成する関数たち aiGeneraters :: [AIGenerater] aiGeneraters = [winPutValue , losePutValue , completeThinkingLastPart , evenTheorem , putCXOnly , cornerPutValue , (openDegreeTheoremExpand ddeg0) , xPutValue , cPutValue , cornerLosePut] ------AIに用いる値であらかじめ計算しておくもの data AIPreValue = AIPreValue { leastOpendeg :: GLint } deriving (Show) -------AIの作成(再帰) aiConstruct :: [AIGenerater] -> AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint aiConstruct [] apV mst v value = value aiConstruct (ai : ais) apV mst v value = ai apV mst v (aiConstruct ais apV mst v value) -------X打ち xPutValue :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint xPutValue aipV mst pos value = let cs = myStone mst gbcs = gBoardCells mst in if (dPutX mst pos) && (not (dcornerLosePutOnly mst cs gbcs pos)) then putXCornerStateValue mst pos value else value -------C打ち cPutValue :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint cPutValue aipV mst pos value = let cs = myStone mst gbcs = gBoardCells mst in if (dPutC mst pos) then if dcornerLosePutOnly mst cs gbcs pos then edgeValueC mst cs gbcs pos value else value `quot` 80 else value -------角優先 cornerPutValue :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint cornerPutValue aipV mst pos value = if pos `elem` (cornerSetv mst) then value * 800 else value -------全滅するような手を避ける losePutValue :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint losePutValue aipV mst pos value = if dLosePutValue mst pos then 1 else value -------全滅させる手を優先 winPutValue :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint winPutValue aipV mst pos value = let cs = myStone mst aiBoard = makeAIBoard cs gbcs pos gbcs = gBoardCells mst in if (numberStone (opStone cs) aiBoard) == 0 then value * 1000 else value -------全滅するような手であるか? dLosePutValue :: MState -> (Vector2 GLint) -> Bool dLosePutValue mst pos = let cs = myStone mst gbcs = gBoardCells mst aiBoard = makeAIBoard cs gbcs pos puttable2 = makePuttable mst (opStone cs) aiBoard aiBoard2List = map (makeAIBoard (opStone cs) aiBoard) puttable2 num0aiBoardList = map (numberStone cs) aiBoard2List in 0 `elem` num0aiBoardList -------角を取られるような手であるか? dcornerLosePut :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> Bool dcornerLosePut mst s gbcs pos = let aiBoard = makeAIBoard s gbcs pos in or (map (dPuttableCell (opStone s) aiBoard) (cornerSetv mst)) -------角を取られるような手をさける cornerLosePut :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint cornerLosePut aipV mst pos value = let cs = myStone mst gbcs = gBoardCells mst in if (dcornerLosePut mst cs gbcs pos) && (not (dcornerLosePutOnly mst cs gbcs pos)) then value `quot` 600 else value -------角を取られるような手以外の残っていない dcornerLosePutOnly :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> Bool dcornerLosePutOnly mst s gbcs pos = foldl (&&) True (map (dcornerLosePut mst s gbcs) (makePuttable mst s gbcs)) --------終盤完全読み makeCompleteThinkingLastPart :: MState -> (Vector2 GLint) -> GLint -> GLint makeCompleteThinkingLastPart mst pos value = let gbcs = gBoardCells mst cs = myStone mst puttable = makePuttable mst (myStone mst) gbcs cValuesList = map (compThinkValue mst cs cs gbcs 0) puttable maxfilterValue = maximum (map valueNLC cValuesList) eVector = positionNLC ( head (selectByInstanceF cValuesList valueNLC maximum)) in if maxfilterValue >= 0 then if pos == eVector then 30000 else 0 else let maxfilterWinPoint = maximum (map winPointNLC cValuesList) ewVector = positionNLC (head (selectByInstanceF cValuesList winPointNLC maximum)) in if pos == ewVector then 30000 else 0 ------残りが少なくなったときに完全読み開始 completeThinkingLastPart :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint completeThinkingLastPart aipv mst pos value = if (numberEmptyCells mst (gBoardCells mst)) <= 7 then makeCompleteThinkingLastPart mst pos value else value ------ data NodeLastComp = NodeLastComp { positionNLC :: (Vector2 GLint) ,valueNLC :: GLint ,winPointNLC :: GLint } deriving (Show , Ord , Eq) -------終盤完全読み(再帰) compThinkValue :: MState -> GStone -> GStone -> GBoardCells -> GLint -> (Vector2 GLint) -> NodeLastComp compThinkValue mst s initS gbcs depth pos = let aiBoard = makeAIBoard s gbcs pos in if dEndGame mst aiBoard then (NodeLastComp (Vector2 (-1) (-1)) (ddnumberStone initS aiBoard) (if (ddnumberStone initS aiBoard) >= 0 then 1 else 0)) else let curStone = if existPuttableCell mst (opStone s) aiBoard then (opStone s) else s puttable = makePuttable mst curStone aiBoard valuesList = map (compThinkValue mst curStone initS aiBoard (depth + 1)) puttable numberNonMinusVList = fromIntegral (length (filter (>= 0) (map valueNLC valuesList))) wPointSum = sum (map winPointNLC valuesList) filterFunc = if curStone == initS then maximum else minimum newNLC = head (selectByInstanceF valuesList valueNLC filterFunc) in NodeLastComp pos (valueNLC newNLC) (wPointSum + numberNonMinusVList) ------開放度理論------------------------------------------------------------------------------- ------ ------開放度の測定 getOpenDegree :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> GLint getOpenDegree mst s gbcs spos = let nSList = (stoneNeighbor mst s gbcs spos) nSEmptyList = filter (== 0) nSList in fromIntegral (length nSEmptyList) ------開放度の総和 sumOpenDegree :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> GLint sumOpenDegree mst s gbcs cPos = foldl (+) 0 (map ((flip (sumOpenDegreeD mst s gbcs)) cPos) eightList) ------方向ベクトルへ開放度の総和(再帰) sumOpenDegreeD :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> (Vector2 GLint) -> GLint sumOpenDegreeD mst s gbcs v cPos = if dReversiD s gbcs v cPos then let newPos = (+) <$> v <*> cPos in if (getStoneBoard gbcs s newPos) == 2 then (getOpenDegree mst s gbcs newPos) + (sumOpenDegreeD mst s gbcs v newPos) else 0 else 0 ------n回以上の開放度理論 openDegreeTheoremExpand :: GLint -> AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint openDegreeTheoremExpand ddeg aipv mst pos value = let gbcs = gBoardCells mst s = myStone mst lOpendeg = leastOpendeg aipv opendeg = openDegreeTheoremExpand' ddeg mst s s gbcs pos dopendeg = opendeg - lOpendeg in if pos `elem` (cXCornerAllSet mst) then value else value `quot` (5^(fromIntegral dopendeg)) ------n回以上の開放度測定(再帰) openDegreeTheoremExpand' :: GLint -> MState -> GStone -> GStone -> GBoardCells -> (Vector2 GLint) -> GLint openDegreeTheoremExpand' 0 mst s initS gbcs pos = 0 openDegreeTheoremExpand' ddeg mst s initS gbcs pos = let aiBoard = makeAIBoard s gbcs pos curStone = if existPuttableCell mst (opStone s) aiBoard then (opStone s) else s puttable = makePuttable mst curStone aiBoard oThmC = if s == initS then 1 else (-1) fFunc = if curStone == initS then minimum else maximum opnvalues = sumOpenDegree mst s gbcs pos in opnvalues * oThmC + (fFunc (map (openDegreeTheoremExpand' (ddeg - 1) mst curStone initS aiBoard) puttable)) ------------------------------------------------------------------------------------------------ ------置くことが出来る場所がC,X,Cornerしかない dPuttableOnlyCXCorner :: MState -> GStone -> GBoardCells -> Bool dPuttableOnlyCXCorner mst s gbcs = null (differenceList (makePuttable mst s gbcs) (cXCornerAllSet mst)) ------偶数理論 evenTheorem :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint evenTheorem aipv mst pos value = let gbcs = gBoardCells mst s = myStone mst in if dPuttableOnlyCXCorner mst s gbcs then evenThmValue mst s gbcs pos value else value ------偶数理論の値の設定 evenThmValue :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> GLint -> GLint evenThmValue mst s gbcs pos value = let baseP = getCornerNeighber mst pos cXC = cXCornerSet mst baseP in if (numberEmptyInList gbcs cXC) `mod` 2 == 0 then value else value * 10 ------------------------------------------------------------------------------------------------ -------角集合 cornerSet :: [(Vector2 GLint)] cornerSet = [(Vector2 0 0) , (Vector2 1 0) , (Vector2 0 1) , (Vector2 1 1)] -------角集合実値 cornerSetv :: MState -> [(Vector2 GLint)] cornerSetv mst = let bx = (divBoardNumX mst) - 1 by = (divBoardNumY mst) - 1 in [(Vector2 0 0) , (Vector2 bx 0) , (Vector2 0 by) , (Vector2 bx by)] ------X打ちの値 putXCornerStateValue :: MState -> (Vector2 GLint) -> GLint -> GLint putXCornerStateValue mst pos value = let cornerB = getCornerNeighber mst pos cs = myStone mst gbcs = gBoardCells mst in if dCornerStateCorner mst cs gbcs cornerB >= 1 then value else if dcornerLosePutOnly mst cs gbcs pos then value else value `quot` 500 -------C,X,Cornerの集合(角指定) cXCornerSet :: MState -> (Vector2 GLint) -> [(Vector2 GLint)] cXCornerSet mst baseP = map (tCoordNormalIntoCorner mst baseP) [(Vector2 x y) | x <- [0,1] , y <- [0,1]] -------C,X,Cornerの集合(全体) cXCornerAllSet :: MState -> [(Vector2 GLint)] cXCornerAllSet mst = [(tCoordNormalIntoCorner mst baseP v) | baseP <- cornerSet , v <- [(Vector2 x y) | x <- [0,1] , y <- [0,1]]] -------辺座標タイプ集合 edgeSet :: [EdgeType] edgeSet = [EdgeTop1 , EdgeBottom1 , EdgeRight1 , EdgeLeft1 , EdgeTop2 , EdgeBottom2 , EdgeRight2 , EdgeLeft2] -------Cであるか dPutC :: MState -> (Vector2 GLint) -> Bool dPutC mst pos = let cset = map ((flip(tCoordNormalIntoEdge mst)) pos) edgeSet in (Vector2 1 0) `elem` cset -------Xであるか dPutX :: MState -> (Vector2 GLint) -> Bool dPutX mst pos = let cset = map ((flip(tCoordNormalIntoCorner mst)) pos) cornerSet in (Vector2 1 1) `elem` cset ------角において角は埋まっているか dCornerStateCorner :: MState -> GStone -> GBoardCells -> (Vector2 GLint)-> GLint dCornerStateCorner mst s gbcs v = case (getStoneCorner mst gbcs v (Vector2 0 0)) of Nothing -> 0 Just x -> if x == s then 1 else 2 ------辺において手前の角が埋まっているか dEdgeStateCorner0 :: MState -> GStone -> GBoardCells -> EdgeType -> GLint dEdgeStateCorner0 mst s gbcs eType = case (getStoneEdge mst gbcs eType (Vector2 0 0)) of Nothing -> 0 Just x -> if x == s then 1 else 2 ------辺において(2,0)が埋まっているか dEdgeState20 :: MState -> GStone -> GBoardCells -> EdgeType -> GLint dEdgeState20 mst s gbcs eType = case (getStoneEdge mst gbcs eType (Vector2 2 0)) of Nothing -> 0 Just x -> if x == s then 1 else 2 -------辺においてCは埋まっているか dEdgeState10 :: MState -> GStone -> GBoardCells -> EdgeType -> GLint dEdgeState10 mst s gbcs eType = case (getStoneEdge mst gbcs eType (Vector2 1 0)) of Nothing -> 0 Just x -> if x == s then 1 else 2 ------辺において奥の角が埋まっているか dEdgeStateCornerX :: MState -> GStone -> GBoardCells -> EdgeType -> GLint dEdgeStateCornerX mst s gbcs eType = let bx = (divBoardNumX mst) - 1 by = (divBoardNumY mst) - 1 b = if eType `elem` [EdgeLeft1 , EdgeLeft2 , EdgeRight1 , EdgeRight2] then by else bx in case (getStoneEdge mst gbcs eType (Vector2 b 0)) of Nothing -> 0 Just x -> if x == s then 1 else 2 ------C打ちにおいて辺の状態によるValueの変化 edgeValueC :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> GLint -> GLint edgeValueC mst s gbcs pos value | c0 == 0 , c1 == 1 , c2 == 0 = edgeValueC010 mst s gbcs eType pos value | c0 == 0 , c1 == 0 , c2 == 0 = edgeValueC000 mst s gbcs eType pos value | c0 == 0 , c1 == 1 , c2 == 1 = value `quot` 10 ----チェック | c0 == 0 , c2 == 2 = value `quot` 200 ----もっと細かく分岐をしてもいいかもしれない | c0 == 0 , c2 == 1 = value `quot` 500 | c0 == 0 = value `quot` 300 | c0 == 1 , c1 == 1 = value * 100 | c0 == 1 = value * 25 | c0 == 2 , c2 == 0 = edgeValueC2x0 mst s gbcs eType pos value | c0 == 2 , c2 == 2 = edgeValueC2x2 mst s gbcs eType pos value | c0 == 2 , c2 == 1 = edgeValueC2x1 mst s gbcs eType pos value | otherwise = value where eType = getEdgeNeighberC mst pos c0 = dEdgeStateCorner0 mst s gbcs eType c1 = dEdgeState20 mst s gbcs eType c2 = dEdgeStateCornerX mst s gbcs eType ------両辺が埋まっていない状態の辺の状態によるValueの変化 edgeValueC010 :: MState -> GStone -> GBoardCells -> EdgeType -> (Vector2 GLint) -> GLint -> GLint edgeValueC010 mst s gbcs eType pos value | take 4 (edgeConnectedComponent mst gbcs s eType) == [0 , 1 , 0 , 1] = value `quot` 500 | otherwise = value ------両辺が埋まっていない状態の辺の状態によるValueの変化 edgeValueC000 :: MState -> GStone -> GBoardCells -> EdgeType -> (Vector2 GLint) -> GLint -> GLint edgeValueC000 mst s gbcs eType pos value | take 5 eList == [0 , 0 , 0 , 2 , 1] = value `quot` 500 | take 5 eList == [0 , 0 , 0 , 1 , 2] , listConnectedComponent (drop 5 eList) == [2,0] , cx1 == 2 = value `quot` 10 | take 4 eList == [0 , 0 , 0 , 1 ] = value `quot` 500 | take 5 eList == [0 , 0 , 0 , 0 , 2 ] , take 2 (listConnectedComponent (drop 5 eList)) == [2,0] = value `quot` 500 | listConnectedComponent eList == [0] = value `quot` 400 | otherwise = value `quot` 3 where eList = getStoneBoardEdgeList mst gbcs s eType cx1 = dEdgeState10 mst s gbcs (getReverseEdge eType) ----反対側のC ------両辺が2の状態の辺の状態によるValueの変化 edgeValueC2x0 :: MState -> GStone -> GBoardCells -> EdgeType -> (Vector2 GLint) -> GLint -> GLint edgeValueC2x0 mst s gbcs eType pos value | eGType == 201 = value * 500 | eGType == 200 = value * 20 | eGType == 101 = value * 8 | eGType == 100 = value * 30 | otherwise = value where eGType = dEdgeBlockTypeBaseColor mst s gbcs eType ------両辺が2の状態の辺の状態によるValueの変化 edgeValueC2x2 :: MState -> GStone -> GBoardCells -> EdgeType -> (Vector2 GLint) -> GLint -> GLint edgeValueC2x2 mst s gbcs eType pos value | eGType == 201 = value * 16 | eGType == 200 = value * 32 | eGType == 101 = value * 200 | eGType == 100 = value `quot` 40 | otherwise = value where eGType = dEdgeBlockTypeBaseColor mst s gbcs eType ------両辺が2の状態の辺の状態によるValueの変化 edgeValueC2x1 :: MState -> GStone -> GBoardCells -> EdgeType -> (Vector2 GLint) -> GLint -> GLint edgeValueC2x1 mst s gbcs eType pos value | eGType == 201 = value * 200 | eGType == 200 = value * 8 | eGType == 101 = value * 16 | eGType == 100 = value `quot` 50 | otherwise = value where eGType = dEdgeBlockTypeBaseColor mst s gbcs eType ------辺における石の連結成分の類別 edgeConnectedComponent :: MState -> GBoardCells -> GStone -> EdgeType -> [GLint] edgeConnectedComponent mst gbcs s eType = listConnectedComponent (getStoneBoardEdgeList mst gbcs s eType) ------辺の石の配列の取得 getStoneBoardEdgeList :: MState -> GBoardCells -> GStone -> EdgeType -> [GLint] getStoneBoardEdgeList mst gbcs s eType = let xs = map (\x -> (Vector2 x 0)) [0 .. ((divBoardNumX mst) - 1)] ys = map (\x -> (Vector2 x 0)) [0 .. ((divBoardNumY mst) - 1)] in case getEdgeTypeDirect eType of EdgeH -> map (getStoneBoardEdge mst gbcs s eType) xs EdgeV -> map (getStoneBoardEdge mst gbcs s eType) ys ------辺座標において第1成分の石の配列の取得(部分) getStoneBoardEdgeListInterval :: MState -> GBoardCells -> GStone -> (GLint , GLint) -> GLint -> EdgeType -> [GLint] getStoneBoardEdgeListInterval mst gbcs s (a , b) y eType = let xs = map (\x -> (Vector2 x y)) [a .. ((divBoardNumX mst) - b)] ys = map (\x -> (Vector2 x y)) [a .. ((divBoardNumY mst) - b)] in case getEdgeTypeDirect eType of EdgeH -> map (getStoneBoardEdge mst gbcs s eType) xs EdgeV -> map (getStoneBoardEdge mst gbcs s eType) ys -----辺座標における-石の取得(0 空 ,1 自石 , 2 敵石 ) getStoneBoardEdge :: MState -> GBoardCells -> GStone -> EdgeType -> (Vector2 GLint) -> GLint getStoneBoardEdge mst gbcs s eType pos = getStoneBoard gbcs s (tCoordEdgeIntoNormal mst eType pos) -----角座標における-石の取得(0 空 ,1 自石 , 2 敵石 ) getStoneBoardCorner :: MState -> GBoardCells -> GStone -> (Vector2 GLint) -> (Vector2 GLint) -> GLint getStoneBoardCorner mst gbcs s v pos = getStoneBoard gbcs s (tCoordCornerIntoNormal mst v pos) ------辺座標における石の取得 getStoneEdge :: MState -> GBoardCells -> EdgeType -> (Vector2 GLint) -> (Maybe GStone) getStoneEdge mst gbcs eType pos = Map.lookup (tCoordEdgeIntoNormal mst eType pos) gbcs ------角座標における石の取得 getStoneCorner :: MState -> GBoardCells -> (Vector2 GLint) -> (Vector2 GLint) -> (Maybe GStone) getStoneCorner mst gbcs v pos = Map.lookup (tCoordCornerIntoNormal mst v pos) gbcs -----辺座標においてプット可能セルであるか dPuttableCellEdge :: MState -> GStone -> GBoardCells -> EdgeType -> (Vector2 GLint) -> Bool dPuttableCellEdge mst s gbcs eType pos = let ePos = tCoordEdgeIntoNormal mst eType pos in (dReversi s gbcs ePos) && (dEmptyCell gbcs ePos) -----角座標においてプット可能セルであるか dPuttableCellCorner :: MState -> GStone -> GBoardCells -> (Vector2 GLint) -> (Vector2 GLint) -> Bool dPuttableCellCorner mst s gbcs baseP pos = let ePos = tCoordCornerIntoNormal mst baseP pos in (dReversi s gbcs ePos) && (dEmptyCell gbcs ePos) -------辺の形---------------------------------------------------------------------------------- -------辺の形を判定 dEdgeBlock :: MState -> GStone -> GBoardCells -> EdgeType -> GLint dEdgeBlock mst s gbcs eType = let eList22 = (getStoneBoardEdgeListInterval mst gbcs s (2 , 2) 0 eType) in if 0 `elem` eList22 then (-2) else dEdgeBlockTypeBaseColor mst s gbcs eType -------辺の形を判定 dEdgeBlockTypeBaseColor :: MState -> GStone -> GBoardCells -> EdgeType -> GLint dEdgeBlockTypeBaseColor mst s gbcs eType | listConnectedComponent eList22 == [2] = dEdgeBlockType mst s gbcs eType 2 | listConnectedComponent eList22 == [1] = dEdgeBlockType mst s gbcs eType 1 | take 3 (listConnectedComponent eList22) == [2, 1 , 2] = dEdgeBlockType mst s gbcs eType 3 | take 3 (listConnectedComponent eList22) == [1, 2 , 1] = dEdgeBlockType mst s gbcs eType 4 | otherwise = (-1) where eList = getStoneBoardEdgeList mst gbcs s eType eList22 = (getStoneBoardEdgeListInterval mst gbcs s (2 , 2) 0 eType) -------辺の形を判定 dEdgeBlockType :: MState -> GStone -> GBoardCells -> EdgeType -> GLint -> GLint dEdgeBlockType mst s gbcs eType i | c1 == 0 , cx1 == 0 = 100 * i + 0 | c1 == 0 , cx1 /= 0 = 100 * i + 1 | c1 /= 0 , cx1 == 0 = 100 * i + 10 | c1 /= 0 , cx1 /= 0 = 100 * i + 11 where c1 = dEdgeState10 mst s gbcs eType cx1 = dEdgeState10 mst s gbcs (getReverseEdge eType) -------CXしかうつ手がない場合 putCXOnly :: AIPreValue -> MState -> (Vector2 GLint) -> GLint -> GLint putCXOnly aipv mst pos value = let cornerB = getCornerNeighber mst pos cs = myStone mst gbcs = gBoardCells mst cornerS = getStoneBoardCorner mst gbcs cs cornerB (Vector2 0 0) aiBoard = makeAIBoard cs gbcs pos in if (dPuttableOnlyCXCorner mst cs gbcs) && (cornerS == 0) && (dPuttableCellCorner mst (opStone cs) aiBoard cornerB pos) then if dPutC mst pos then putCXOnlyValueC mst gbcs aiBoard cs pos value else putCXOnlyValueX mst gbcs aiBoard cs pos value else value -------CXしかうつ手がない場合の値の設定 C putCXOnlyValueC :: MState -> GBoardCells -> GBoardCells ->GStone -> (Vector2 GLint) ->GLint -> GLint putCXOnlyValueC mst gbcs aiBoard cs pos value = let eType = getEdgeNeighberC mst pos dcPos = tCoordEdgeIntoNormal mst eType (Vector2 0 1) aiBoard2 = makeAIBoardEdge mst (opStone cs) aiBoard eType (Vector2 0 0) in if dPuttableCellEdge mst cs aiBoard2 eType dcPos then let aiBoard3 = makeAIBoard cs aiBoard2 dcPos in if dPuttableCellEdge mst cs aiBoard3 (getReverseEdge eType) (Vector2 0 0) then value * 100 else putCXOnlyValueDetailC mst gbcs aiBoard2 cs pos (getEdgeDualCorner eType) value else value -------CXしかうつ手がない場合の値の設定 C putCXOnlyValueDetailC :: MState -> GBoardCells -> GBoardCells ->GStone -> (Vector2 GLint) -> EdgeType -> GLint -> GLint putCXOnlyValueDetailC mst gbcs aiBoard2 cs pos eType value = valueedgesB mst gbcs aiBoard2 cs pos eType value -------CXしかうつ手がない場合の値の設定 X putCXOnlyValueX :: MState -> GBoardCells -> GBoardCells ->GStone -> (Vector2 GLint) ->GLint -> GLint putCXOnlyValueX mst gbcs aiBoard cs pos value = let baseP = getCornerNeighber mst pos edges = getEdgeRootCorner baseP aiBoard2 = makeAIBoardCorner mst (opStone cs) aiBoard baseP (Vector2 0 0) aiEdges = filter ((flip (dPuttableCellEdge mst cs gbcs)) (Vector2 1 0)) edges in if and (map (filteredgesA mst gbcs cs pos) edges) then value * 100 else value -------上の補助関数 filteredgesA :: MState -> GBoardCells -> GStone -> (Vector2 GLint) -> EdgeType -> Bool filteredgesA mst gbcs cs pos eType = let aiBoard3 = makeAIBoardEdge mst (opStone cs) gbcs eType (Vector2 1 0) in dPuttableCellEdge mst cs aiBoard3 (getReverseEdge eType) (Vector2 0 0) -------CXしかうつ手がない場合の値の設定 C putCXOnlyValueDetailX :: MState -> GBoardCells -> GBoardCells ->GStone -> (Vector2 GLint) -> [EdgeType] -> GLint -> GLint putCXOnlyValueDetailX mst gbcs aiBoard2 cs pos edges value = maximum (map ((flip (valueedgesB mst gbcs aiBoard2 cs pos )) value) edges) -------上の補助関数 valueedgesB :: MState -> GBoardCells -> GBoardCells -> GStone -> (Vector2 GLint) -> EdgeType -> GLint -> GLint valueedgesB mst gbcs aiBoard2 cs pos eType value = if dPuttableCellEdge mst cs aiBoard2 eType (Vector2 1 0) then case (dEdgeBlockTypeBaseColor mst cs gbcs eType) of 300 -> value * 50 301 -> value * 200 401 -> value * 80 400 -> value * 80 _ -> value else value -------------------------------------------------------------------------------------------------- ------Cで考える辺を得る getEdgeNeighberC :: MState -> (Vector2 GLint) -> EdgeType getEdgeNeighberC mst (Vector2 x y) | x == 1 , y == 0 = EdgeBottom1 | x == bx - 1 , y == 0 = EdgeBottom2 | x == 1 , y == by = EdgeTop1 | x == bx - 1,y == by = EdgeTop2 | x == 0 , y == 1 = EdgeLeft1 | x == 0 , y == by - 1 = EdgeLeft2 | x == bx , y == 1 = EdgeRight1 | x == bx , y == by - 1 = EdgeRight2 where bx = (divBoardNumX mst) - 1 by = (divBoardNumY mst) - 1 ------ ------どの角が最も近いかを得る getCornerNeighber :: MState -> (Vector2 GLint) -> (Vector2 GLint) getCornerNeighber mst (Vector2 x y) | x <= hbx , y <= hby = (Vector2 0 0) | x > hbx , y <= hby = (Vector2 1 0) | x <= hbx , y > hby = (Vector2 0 1) | x > hbx , y > hby = (Vector2 1 1) where bx = (divBoardNumX mst) - 1 by = (divBoardNumY mst) - 1 hbx = bx `quot` 2 hby = by `quot` 2 --------座標変換(標準座標から角座標に変換) tCoordNormalIntoCorner :: MState ->(Vector2 GLint) -> (Vector2 GLint) -> (Vector2 GLint) tCoordNormalIntoCorner mst baseP (Vector2 x y) = let bx = (divBoardNumX mst) - 1 by = (divBoardNumY mst) - 1 in case baseP of (Vector2 0 0) -> (Vector2 x y) (Vector2 1 0) -> (Vector2 (bx - x) y) (Vector2 1 1) -> (Vector2 (bx - x) (by - y)) (Vector2 0 1) -> (Vector2 x (by - y)) --------座標変換(角座標から標準座標に変換) tCoordCornerIntoNormal :: MState ->(Vector2 GLint) -> (Vector2 GLint) -> (Vector2 GLint) tCoordCornerIntoNormal = tCoordNormalIntoCorner data EdgeType = EdgeTop1 | EdgeBottom1 | EdgeRight1 | EdgeLeft1 | EdgeTop2 | EdgeBottom2 | EdgeRight2 | EdgeLeft2 deriving (Show , Eq , Ord) data EdgeTypeDirect = EdgeV | EdgeH deriving (Show , Eq ,Ord) --------EdgeTypeの分類 getEdgeTypeDirect :: EdgeType -> EdgeTypeDirect getEdgeTypeDirect eType = if eType `elem` [EdgeTop1 , EdgeBottom1 , EdgeTop2 , EdgeBottom2] then EdgeH else EdgeV ---------向きのみが逆の辺の取得 getReverseEdge :: EdgeType -> EdgeType getReverseEdge eType = case eType of EdgeTop1 -> EdgeTop2 EdgeBottom1 -> EdgeBottom2 EdgeRight1 -> EdgeRight2 EdgeLeft1 -> EdgeLeft2 EdgeTop2 -> EdgeTop1 EdgeBottom2 -> EdgeBottom1 EdgeRight2 -> EdgeRight1 EdgeLeft2 -> EdgeLeft1 --------辺の両端にある角の取得 (やや再帰的な定義)第1項が根 getCornersOfEdgeSide :: EdgeType -> ((Vector2 GLint) , (Vector2 GLint)) getCornersOfEdgeSide eType = case eType of EdgeTop1 -> ((Vector2 0 1) , (Vector2 1 1)) EdgeBottom1 -> ((Vector2 0 0) , (Vector2 1 0)) EdgeRight1 -> ((Vector2 1 0) , (Vector2 1 1)) EdgeLeft1 -> ((Vector2 0 0) , (Vector2 0 1)) e -> swap (getCornersOfEdgeSide (getReverseEdge e)) --------角を根にもつ辺 getEdgeRootCorner :: (Vector2 GLint) -> [EdgeType] getEdgeRootCorner baseP = case baseP of (Vector2 0 0) -> [EdgeBottom1 , EdgeLeft1] (Vector2 1 0) -> [EdgeBottom2 , EdgeRight1] (Vector2 0 1) -> [EdgeTop1 , EdgeLeft2] (Vector2 1 1) -> [EdgeTop2 , EdgeRight2] --------角で同じ根を持つ辺 getEdgeDualCorner :: EdgeType -> EdgeType getEdgeDualCorner eType = head (differenceList (getEdgeRootCorner (fst (getCornersOfEdgeSide eType))) [eType]) --------座標変換(標準座標から辺座標に変換) tCoordNormalIntoEdge :: MState -> EdgeType -> (Vector2 GLint) -> (Vector2 GLint) tCoordNormalIntoEdge mst edge (Vector2 x y) = let bx = (divBoardNumX mst) - 1 by = (divBoardNumY mst) - 1 in case edge of EdgeBottom1 -> (Vector2 x y) EdgeBottom2 -> (Vector2 (bx - x) y) EdgeTop1 -> (Vector2 x (by - y)) EdgeTop2 -> (Vector2 (bx - x) (by - y)) EdgeLeft1 -> (Vector2 y x) EdgeLeft2 -> (Vector2 (by - y) x) EdgeRight1 -> (Vector2 y (bx - x)) EdgeRight2 -> (Vector2 (by - y) (bx - x)) --------座標変換(辺座標から標準座標に変換) tCoordEdgeIntoNormal :: MState -> EdgeType -> (Vector2 GLint) -> (Vector2 GLint) tCoordEdgeIntoNormal = tCoordNormalIntoEdge