1- import {
2- Tile ,
3- Sym ,
4- Mode ,
5- ReversiOptions ,
6- directionXYs ,
7- Reversi ,
8- } from './Reversi.js'
1+ import { Tile , Sym , ReversiOptions , directionXYs , Reversi } from './Reversi.js'
2+ import { HistoryData } from './View.svelte.js'
93
104export type AILV = 0 | 1 | 2 | 3 | 4 | 5
115
@@ -18,10 +12,16 @@ export interface Hand {
1812 x : number
1913 y : number
2014 count : number
15+ /**
16+ * 着手点
17+ * * 配列は自分(0)、相手(1)
18+ */
19+ choices : number [ ]
2120 opens : number
2221 fixed : number
2322 scores : {
2423 count : number
24+ choices : number
2525 opens : number
2626 position_corner : number
2727 position_corner_clue : number
@@ -32,24 +32,40 @@ export interface Hand {
3232 }
3333}
3434
35- interface BoardLog {
36- // hand: Hand
37- tiles : Tile [ ]
38- counter : number
39- }
40-
4135// 考慮の重要度
4236export interface AISetting {
4337 /**
4438 * ひっくり返せる石の数
39+ * * 配列は序盤(0)、中盤(1)、終盤(2)を表す
4540 */
4641 count ?: number [ ]
42+ /**
43+ * 着手点
44+ * * 配列は自分(0)、相手(1)
45+ */
46+ choices ?: number [ ]
4747 /**
4848 * 開放度理論:隣接する空きマスの数
49+ * * 配列は序盤(0)、中盤(1)、終盤(2)を表す
4950 */
5051 opens ?: number [ ]
5152 position_corner ?: number
5253 position_corner_clue ?: number
54+
55+ /**
56+ * ```
57+ * 00000000
58+ * 01111110
59+ * 01222210
60+ * 01233210
61+ * 01233210
62+ * 01222210
63+ * 01111110
64+ * 00000000
65+ * ```
66+ *
67+ * [5,6,7] の場合上の図の0を5点、1を6点、2を7点とする
68+ */
5369 position_edge ?: number [ ]
5470 next_turn ?: number
5571 fixed ?: number
@@ -75,6 +91,7 @@ export const AIsettings: AISettings = [
7591 // 4
7692 {
7793 count : [ - 1 , 0 , 1 ] ,
94+ choices : [ 1 , 1 ] ,
7895 opens : [ 0.5 , 0.5 , 0.5 ] ,
7996 position_corner : 1 ,
8097 position_corner_clue : - 1 ,
@@ -84,6 +101,7 @@ export const AIsettings: AISettings = [
84101 // 5
85102 {
86103 count : [ - 1 , 0 , 1 ] ,
104+ choices : [ 0 , 1 ] ,
87105 opens : [ 0.5 , 0.5 , 0.5 ] ,
88106 position_corner : 1 ,
89107 position_corner_clue : - 1 ,
@@ -98,7 +116,7 @@ export const AILVMAX = (AIsettings.length - 1) as AILV
98116export abstract class AIReversi extends Reversi {
99117 hiScore : number
100118
101- boardLog : BoardLog [ ] = [ ]
119+ boardLog : HistoryData [ ] = [ ]
102120 /**
103121 * If this is true, it is the thinking stage of AI
104122 */
@@ -132,6 +150,7 @@ export abstract class AIReversi extends Reversi {
132150 }
133151 const {
134152 count,
153+ choices,
135154 opens,
136155 position_corner,
137156 position_corner_clue,
@@ -145,6 +164,12 @@ export abstract class AIReversi extends Reversi {
145164 scores . count += hand . count * count [ term ]
146165 }
147166
167+ if ( choices ) {
168+ for ( let i = 0 ; i < 2 ; i ++ ) {
169+ scores . choices += hand . choices [ i ] * choices [ i ]
170+ }
171+ }
172+
148173 // 開放度が低いほど高スコア
149174 // 開放度理論
150175 // ひっくり返した石に隣接する空きマスが少ないほど良い手
@@ -188,7 +213,7 @@ export abstract class AIReversi extends Reversi {
188213 }
189214
190215 if ( next_turn ) {
191- this . logging ( )
216+ this . logging ( x , y )
192217 if ( this . term === 2 ) {
193218 const slots = this . addTile ( x , y )
194219 if ( slots . empty ) {
@@ -224,20 +249,36 @@ export abstract class AIReversi extends Reversi {
224249 return hand
225250 }
226251
227- logging ( ) {
252+ logging ( x : number , y : number ) {
253+ this . thinking = true
254+ this . boardLog . push ( {
255+ x,
256+ y,
257+ sym : this . sym ,
258+ tiles : this . tiles . slice ( ) ,
259+ turn : this . turn ,
260+ } )
261+ }
262+
263+ virtualHit ( x : number , y : number ) {
228264 this . thinking = true
229265 this . boardLog . push ( {
266+ x,
267+ y,
268+ sym : this . sym ,
230269 tiles : this . tiles . slice ( ) ,
231- counter : this . turn ,
270+ turn : this . turn ,
232271 } )
272+
273+ return this . addTile ( x , y )
233274 }
234275
235276 reset ( index = 0 ) {
236277 const log = this . boardLog [ index ]
237278 if ( log ) {
238- const { tiles, counter } = log
279+ const { tiles, turn } = log
239280 this . tiles = tiles
240- this . turn = counter
281+ this . turn = turn
241282 this . sym = this . turn % 2 === 0 ? Tile . W : Tile . B
242283 }
243284 this . boardLog = [ ]
@@ -253,11 +294,11 @@ export abstract class AIReversi extends Reversi {
253294 }
254295
255296 /**
256- * 序 中 終
297+ * 序0 中1 終2
257298 * +----+----+----+----+----+
258299 * 0 0.2 0.4 0.6 0.8 1
259300 */
260- get term ( ) {
301+ get term ( ) : 0 | 1 | 2 {
261302 const per = this . countPer
262303 if ( per > 0.8 ) {
263304 return 2
@@ -305,15 +346,13 @@ export abstract class AIReversi extends Reversi {
305346
306347 for ( let y = 0 ; y < boardSize ; y ++ ) {
307348 for ( let x = 0 ; x < boardSize ; x ++ ) {
308- if ( this . isTileEmpty ( x , y ) ) {
309- if ( this . checkOKtoPlace ( x , y ) ) {
310- const hand = this . getHand ( x , y , lv )
311- if ( hand . scores . total > this . hiScore ) {
312- this . hiScore = hand . scores . total
313- }
314- if ( hand ) {
315- hands . push ( hand )
316- }
349+ if ( this . checkOKtoPlace ( x , y ) ) {
350+ const hand = this . getHand ( x , y , lv )
351+ if ( hand . scores . total > this . hiScore ) {
352+ this . hiScore = hand . scores . total
353+ }
354+ if ( hand ) {
355+ hands . push ( hand )
317356 }
318357 }
319358 }
@@ -326,10 +365,12 @@ export abstract class AIReversi extends Reversi {
326365 x,
327366 y,
328367 count : this . accumulator ( x , y ) ,
368+ choices : this . getChoices ( x , y ) ,
329369 opens : this . opens ( x , y ) ,
330370 fixed : this . fixedCount ( x , y ) ,
331371 scores : {
332372 count : 0 ,
373+ choices : 0 ,
333374 opens : 0 ,
334375 position_corner : 0 ,
335376 position_corner_clue : 0 ,
@@ -343,13 +384,53 @@ export abstract class AIReversi extends Reversi {
343384 return hand
344385 }
345386
387+ /**
388+ * いくつ石を返せるか
389+ */
346390 accumulator ( x : number , y : number ) {
347391 let totalChanged = 0
348392 this . directionEach ( x , y , ( ) => totalChanged ++ )
349393 return totalChanged
350394 }
351395
352- // 開放度理論
396+ /**
397+ * 着手可能数(自分の打てる選択肢ー相手の打てる選択肢)
398+ *
399+ * virtualHit後に使用
400+ * * 自分の打てる選択肢を多くすると有利になる
401+ * * 相手の打てる選択肢を減らせば不利にできる
402+ */
403+ getChoices ( x : number , y : number ) {
404+ // 自分の手を打つ
405+ this . virtualHit ( x , y )
406+
407+ // 相手のターンなので相手の打てる選択肢を数える
408+ const enemy = - this . _getChoices ( )
409+ // 相手の手は打たずターンだけ進めて
410+ this . nextTurn ( )
411+ // 自分の打てる選択肢を数える
412+ const self = this . _getChoices ( )
413+
414+ this . reset ( )
415+
416+ return [ self , enemy ]
417+ }
418+ private _getChoices ( ) {
419+ let score = 0
420+ const { boardSize } = this
421+ for ( let y = 0 ; y < boardSize ; y ++ ) {
422+ for ( let x = 0 ; x < boardSize ; x ++ ) {
423+ if ( this . checkOKtoPlace ( x , y ) ) {
424+ score ++
425+ }
426+ }
427+ }
428+ return score
429+ }
430+
431+ /**
432+ * 開放度理論
433+ */
353434 opens ( x : number , y : number ) {
354435 const { boardSize } = this
355436 const opens = new Set < number > ( )
0 commit comments