マルバツゲーム:賢いプレイヤー
Posted feedbacks - Smalltalk
Squeak Smalltalk で。
勝ちの手か、負け回避の必要がなければ、
- 中央が空いていれば中央
- 隅が空いていれば、相手が陣取ったマス目に近いほうの開いている隅。ただし、後手で ○×○ と斜めに列んだときは隅以外。
- ランダム
の判断順としてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | | 全マス目 全ライン 勝敗カウンタ 中央のマス 隅のマス群 縁のマス群 |
中央のマス := #(2 2).
隅のマス群 := #((1 1) (3 3) (1 3) (3 1)).
縁のマス群 := #((1 2) (3 2) (2 1) (2 3)).
全マス目 := (中央のマス, 隅のマス群, 縁のマス群) asOrderedCollection.
全ライン := OrderedCollection new.
(1 to: 3) do: [:座標1 |
全ライン add: ((1 to: 3) collect: [:座標2 | {座標1. 座標2}]).
全ライン add: ((1 to: 3) collect: [:座標2 | {座標2. 座標1}])].
全ライン add: #((1 1) (2 2) (3 3)); add: #((1 3) (2 2) (3 1)).
^#(賢い先手 #賢い後手 #賢い両者) collect: [:モード |
勝敗カウンタ := Bag new.
1e4 timesRepeat: [
| 残りマス群 先手 後手 打ち手順 ランダム 手番 結果 |
残りマス群 := 全マス目 copy.
先手 := OrderedCollection new. 後手 := 先手 copy.
打ち手順 := {先手. 後手}.
ランダム := モード caseOf: {
[#賢い先手] -> [後手].
[#賢い後手] -> [先手]}
otherwise: [nil].
手番 := 0.
結果 := nil.
[残りマス群
ifEmpty: [結果 := #引き分け]
ifNotEmpty: [
| 打ち手 敵の手 必勝手検索 必勝の手 守りの手 詰み回避の手 最善手 打つ手 |
打ち手 := 打ち手順 atWrap: (手番 := 手番 + 1).
敵の手 := 打ち手順 atWrap: 手番 + 1.
必勝手検索 := [:対象マス群 |
| 候補群 |
全ライン
detect: [:構成マス群 |
(候補群 := 構成マス群 difference: 対象マス群) size = 1 and: [
残りマス群 includesAllOf: 候補群]]
ifNone: [候補群 := #()]..
候補群 ifNotEmpty: [候補群 first] ifEmpty: [nil]].
必勝の手 := [必勝手検索 value: 打ち手].
守りの手 := [必勝手検索 value: 敵の手].
詰み回避の手 := [
(残りマス群 includes: 中央のマス) ifTrue: [中央のマス] ifFalse: [
(敵の手 includesAnyOf: {隅のマス群 first: 2. 隅のマス群 last: 2})
ifTrue: [縁のマス群 first]
ifFalse: [
(隅のマス群 intersection: 残りマス群)
ifNotEmptyDo: [:候補群 |
候補群 detectMin: [:候補 |
敵の手 inject: 0 into: [:総和 :敵のマス |
総和 + (敵のマス * 候補) sum]]]
ifEmpty: [nil]]]].
最善手 := [
必勝の手 value ifNil: [
守りの手 value ifNil: [
詰み回避の手 value ifNil: [残りマス群 atRandom]]]].
打つ手 := 打ち手 ~~ ランダム ifTrue: [最善手 value] ifFalse: [残りマス群 atRandom].
打ち手 add: (残りマス群 remove: 打つ手).
(全ライン anySatisfy: [:必須マス群 | 打ち手 includesAllOf: 必須マス群])
ifTrue: [結果 := 打ち手 == 先手 ifTrue: [#先手勝ち] ifFalse: [#後手勝ち]]].
結果 isNil] whileTrue.
勝敗カウンタ add: 結果].
モード -> 勝敗カウンタ sortedCounts asArray]
"=> {#賢い先手->{9774->#先手勝ち. 226->#引き分け}.
#賢い後手->{7962->#後手勝ち. 2038->#引き分け}.
#賢い両者->{10000->#引き分け}} "
|


syat
#6207()
Rating0/2=0.00
マルバツゲームで、賢いプレイヤーの思考ルーチンを実装してください。
賢いといってもいろいろありますが、
1.負けない
2.できるだけ勝つ
という条件でいってみたいと思います。
ランダムプレイヤーと1万回バトルした結果(勝ち・負け・分け)を表示してください。
先攻になっても後攻になっても無敗!となれば言うことなしです。
[ reply ]