1
1
import type { GomokuDirectionType } from './constant'
2
2
import { GomokuDirectionTypeBitset , GomokuDirectionTypes } from './constant'
3
- import type { IGomokuContext } from './context.type '
4
- import type { IGomokuCountMap } from './count-map.type '
3
+ import type { IGomokuContext } from './types/ context'
4
+ import type { IGomokuCountMap } from './types/ count-map'
5
5
import { createHighDimensionArray } from './util/createHighDimensionArray'
6
6
7
7
const { rightHalf : halfDirectionTypes } = GomokuDirectionTypes
8
8
const { rightHalf : allDirectionTypeBitset } = GomokuDirectionTypeBitset
9
9
10
10
export class GomokuCountMap implements IGomokuCountMap {
11
11
public readonly context : Readonly < IGomokuContext >
12
- protected readonly _mustDropPosSet : Array < Set < number > > // [playerId] => <must-drop position set>
12
+ protected readonly _mustWinPosSet : Array < Set < number > > // [playerId] => <must-drop position set>
13
13
protected readonly _candidateCouldReachFinal : number [ ] [ ] // [playerId][posId]
14
14
15
15
constructor ( context : Readonly < IGomokuContext > ) {
16
16
this . context = context
17
- this . _mustDropPosSet = createHighDimensionArray ( ( ) => new Set < number > ( ) , 2 )
17
+ this . _mustWinPosSet = createHighDimensionArray ( ( ) => new Set < number > ( ) , context . TOTAL_PLAYER )
18
18
this . _candidateCouldReachFinal = createHighDimensionArray (
19
19
( ) => 0 ,
20
20
context . TOTAL_PLAYER ,
@@ -23,28 +23,30 @@ export class GomokuCountMap implements IGomokuCountMap {
23
23
}
24
24
25
25
public init ( ) : void {
26
- this . _mustDropPosSet . forEach ( set => set . clear ( ) )
27
26
this . _candidateCouldReachFinal . forEach ( item => item . fill ( 0 ) )
27
+ this . _mustWinPosSet . forEach ( set => set . clear ( ) )
28
28
29
- const { context, _mustDropPosSet, _candidateCouldReachFinal } = this
30
- const { TOTAL_POS } = context
29
+ const { context } = this
30
+ const { TOTAL_POS , board } = context
31
+ const [ ccrf0 , ccrf1 ] = this . _candidateCouldReachFinal
32
+ const [ mwps0 , mwps1 ] = this . _mustWinPosSet
31
33
32
34
// Initialize _candidateCouldReachFinal.
33
35
for ( let posId = 0 ; posId < TOTAL_POS ; ++ posId ) {
34
- if ( context . board [ posId ] >= 0 ) continue
36
+ if ( board [ posId ] >= 0 ) continue
35
37
36
38
let flag0 = 0
37
39
let flag1 = 0
38
40
for ( const dirType of halfDirectionTypes ) {
39
41
const bitFlag : number = 1 << dirType
40
- if ( this . _couldReachFinalInDirection ( 0 , posId , dirType ) ) flag0 |= bitFlag
41
- if ( this . _couldReachFinalInDirection ( 1 , posId , dirType ) ) flag1 |= bitFlag
42
+ if ( context . couldReachFinalInDirection ( 0 , posId , dirType ) ) flag0 |= bitFlag
43
+ if ( context . couldReachFinalInDirection ( 1 , posId , dirType ) ) flag1 |= bitFlag
42
44
}
43
45
44
- if ( flag0 > 0 ) _mustDropPosSet [ 0 ] . add ( posId )
45
- if ( flag1 > 0 ) _mustDropPosSet [ 1 ] . add ( posId )
46
- _candidateCouldReachFinal [ 0 ] [ posId ] = flag0
47
- _candidateCouldReachFinal [ 1 ] [ posId ] = flag1
46
+ ccrf0 [ posId ] = flag0
47
+ ccrf1 [ posId ] = flag1
48
+ if ( flag0 > 0 ) mwps0 . add ( posId )
49
+ if ( flag1 > 0 ) mwps1 . add ( posId )
48
50
}
49
51
}
50
52
@@ -58,8 +60,8 @@ export class GomokuCountMap implements IGomokuCountMap {
58
60
this . _updateRelatedCouldReachFinal ( posId )
59
61
}
60
62
61
- public mustDropPos ( playerId : number ) : Iterable < number > & { size : number } {
62
- return this . _mustDropPosSet [ playerId ]
63
+ public mustWinPosSet ( playerId : number ) : Iterable < number > & { size : number } {
64
+ return this . _mustWinPosSet [ playerId ]
63
65
}
64
66
65
67
public candidateCouldReachFinal ( playerId : number , posId : number ) : boolean {
@@ -96,14 +98,14 @@ export class GomokuCountMap implements IGomokuCountMap {
96
98
97
99
protected _updateCouldReachFinal ( posId : number , expiredBitset : number ) : void {
98
100
if ( expiredBitset > 0 ) {
99
- const { _mustDropPosSet , _candidateCouldReachFinal } = this
101
+ const { context , _mustWinPosSet , _candidateCouldReachFinal } = this
100
102
const prevFlag0 = _candidateCouldReachFinal [ 0 ] [ posId ]
101
103
const prevFlag1 = _candidateCouldReachFinal [ 1 ] [ posId ]
102
104
103
- _mustDropPosSet [ 0 ] . delete ( posId )
104
- _mustDropPosSet [ 1 ] . delete ( posId )
105
+ _mustWinPosSet [ 0 ] . delete ( posId )
106
+ _mustWinPosSet [ 1 ] . delete ( posId )
105
107
106
- if ( this . context . board [ posId ] >= 0 ) {
108
+ if ( context . board [ posId ] >= 0 ) {
107
109
_candidateCouldReachFinal [ 0 ] [ posId ] = 0
108
110
_candidateCouldReachFinal [ 1 ] [ posId ] = 0
109
111
return
@@ -114,8 +116,8 @@ export class GomokuCountMap implements IGomokuCountMap {
114
116
for ( const dirType of halfDirectionTypes ) {
115
117
const bitFlag : number = 1 << dirType
116
118
if ( bitFlag & expiredBitset ) {
117
- if ( this . _couldReachFinalInDirection ( 0 , posId , dirType ) ) nextFlag0 |= bitFlag
118
- if ( this . _couldReachFinalInDirection ( 1 , posId , dirType ) ) nextFlag1 |= bitFlag
119
+ if ( context . couldReachFinalInDirection ( 0 , posId , dirType ) ) nextFlag0 |= bitFlag
120
+ if ( context . couldReachFinalInDirection ( 1 , posId , dirType ) ) nextFlag1 |= bitFlag
119
121
} else {
120
122
nextFlag0 |= prevFlag0 & bitFlag
121
123
nextFlag1 |= prevFlag1 & bitFlag
@@ -124,34 +126,8 @@ export class GomokuCountMap implements IGomokuCountMap {
124
126
125
127
_candidateCouldReachFinal [ 0 ] [ posId ] = nextFlag0
126
128
_candidateCouldReachFinal [ 1 ] [ posId ] = nextFlag1
127
- if ( nextFlag0 > 0 ) _mustDropPosSet [ 0 ] . add ( posId )
128
- if ( nextFlag1 > 0 ) _mustDropPosSet [ 1 ] . add ( posId )
129
- }
130
- }
131
-
132
- protected _couldReachFinalInDirection (
133
- playerId : number ,
134
- posId : number ,
135
- dirType : GomokuDirectionType ,
136
- ) : boolean {
137
- const { context } = this
138
- const { MAX_ADJACENT , board } = context
139
- const revDirType : GomokuDirectionType = dirType ^ 1
140
-
141
- let count = 1
142
- const maxMovableSteps0 : number = context . maxMovableSteps ( posId , revDirType )
143
- for ( let id = posId , step = 0 ; step < maxMovableSteps0 ; ++ step ) {
144
- id = context . fastMoveOneStep ( id , revDirType )
145
- if ( board [ id ] !== playerId ) break
146
- count += 1
147
- }
148
-
149
- const maxMovableSteps2 : number = context . maxMovableSteps ( posId , dirType )
150
- for ( let id = posId , step = 0 ; step < maxMovableSteps2 ; ++ step ) {
151
- id = context . fastMoveOneStep ( id , dirType )
152
- if ( board [ id ] !== playerId ) break
153
- count += 1
129
+ if ( nextFlag0 > 0 ) _mustWinPosSet [ 0 ] . add ( posId )
130
+ if ( nextFlag1 > 0 ) _mustWinPosSet [ 1 ] . add ( posId )
154
131
}
155
- return count >= MAX_ADJACENT
156
132
}
157
133
}
0 commit comments