Что нового

[GDIPlus, Игры] Tictactoe (Крестики-Нолики)

firex

AutoIT Гуру
Сообщения
943
Репутация
207
AutoIt: 3.3.8.1
Версия: 1.0

Категория: Графика, GDI+, Элементы GUI, Разное

Описание: Захотелось чем то поделиться :3 Примерно с год назад была задана курсовая (На Delphi), но так как с ним я не особо дружу, то разработал первоначально на AutoIt, а затем перенес в Delphi.

Крестики-нолики 3x3, стандартные правила. Еще при создании учел вариант быстрого добавления других алгоритмов. Создание своих профилей, скинов и тому подобное.

Код/Пример:
players.cfg
Код:
1,1,default,Бот #1 "Простой алгоритм";
2,1,default,Бот #2 "Простой алгоритм";
3,2,playercontrol,Человек #1;
4,2,playercontrol,Человек #2;
5,1,bullshit,Бот #3 "Рандом алгоритм";
6,1,bullshit,Бот #4 "Рандом алгоритм";

skin_default.cfg
Код:
1,images\bg_blue.png;
2,images\title_main.png;
3,images\grid_main.png;
4,images\x_1.png;
5,images\o_1.png;
6,images\line_h.png;
7,images\line_v.png;
8,images\line_m.png;
9,images\line_s.png;

Код:
#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=Tictactoe.exe
#AutoIt3Wrapper_UseUpx=N
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

; #HEAD# ========================================================================================================================
; Title .........: Tictactoe
; Version .......: 1.0.0
; Language ......: Russian
; Description ...:
; Author(s) .....: Firex
; ===============================================================================================================================
#Region Initialization
#NoAutoIt3Execute

#Include <GDIPlus.au3>
#Include <Array.au3>
#Include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("TrayMenuMode",1)
Opt("WinWaitDelay",5)

;Basic constants
Global Const $STM_SETIMAGE = 0x0172
Global Const $ALG_MOVEMENT[ 4 ] = [ 'last|new|player_num', 0, 0, 0 ]
Global Const $ALG_FIELDSTATE[ 10 ] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
Global Const $ALG_REVERSEDFIELD[ 10 ] = [ 0, 1, 2, 3, 8, 0, 4, 7, 6, 5 ]
Global Const $ALG_PRIORITYCELLS[ 5 ] = [ 4, 2, 4, 6, 8 ] ;For default algorithm
; ==
Global Const $GUI_GRIDCELLS[ 10 ][ 2 ] = [ [''], [ 5, 10], [99, 10], [198, 10], [5, 125], [99, 125], [198, 125], [5, 238], [99, 238], [198, 238] ]
Global Const $GUI_BUTTONGRID[ 10 ] [ 2 ] = [ [''], [ 5, 10], [100, 10], [203, 10], [5, 124], [100, 124], [203, 124], [5, 238], [100, 238], [203, 238] ]
Global Const $GUI_LINES[ 9 ][ 5 ] = [ [''], [ 6,0,45,290,30], [6,0,160,290,30], [6,0,275,290,30], [7,35,0,30,350], [7,128,0,30,350], [7,225,0,30,350], [8,0,0,290,350], [9,0,0,290,350] ]

;Basic variables
Global $hSkin = _Tictactoe_SkinLoad('skin_default.cfg')
Global $hPlayer = _Tictactoe_PlayersLoad('players.cfg')

Global $hCtrls[13]
Global $hGui = _GUI_Main( 'Tictactoe - v.0.1.a' )
#EndRegion Initialization

#Region Body
While 1
	$hMsg = GUIGetMsg()
	Switch $hMsg
		Case $GUI_EVENT_CLOSE, $hCtrls[5]
			Exit
		Case $hCtrls[3]
			_GUI_Manual( 'Tictactoe - Manual Set' )
		Case $hCtrls[4]
			_GUI_About( 'Tictactoe - About' )
		Case $hCtrls[0]
			_GUI_Game( 1, 2 )
		Case $hCtrls[1]
			_GUI_Game( 3, 2 )
		Case $hCtrls[2]
			_GUI_Game( 3, 4 )

	EndSwitch
WEnd
#EndRegion Body

Func _Tictactoe_SkinLoad( $cfg )
	_GDIPlus_Startup()

	Local $temp, $index, $hskin[10] = ['hImages']
	Local $data = FileRead( @ScriptDir & '\' & $cfg )
	If $data = -1 Then _
		_Tictactoe_Quit( 1488, 'Can not load skin!' )

	$data = StringSplit(StringReplace(StringStripCR($data),@LF,''), ';' )
	For $index = 1 To $data[0] Step 1
		$temp = StringSplit($data[$index],',')
		If IsArray($temp) And UBound($temp) = 3 Then _
			$hskin[$temp[1]] = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\' & $temp[2])
	Next
	Return $hskin
EndFunc

Func _Tictactoe_PlayersLoad( $cfg )
	Local $temp, $index, $size, $hplayer[1][3] = [['player','alg','name']]
	Local $data = FileRead( @ScriptDir & '\' & $cfg )
	If $data = -1 Then _
		_Tictactoe_Quit( 1488, 'Can not load player profiles!' )

	Local $CPoint = 1
	$data = StringSplit(StringReplace(StringStripCR($data),@LF,''), ';' )
	For $index = 1 To $data[0] Step 1
		$temp = StringSplit($data[$index],',')
		If IsArray($temp) And UBound($temp) = 5 Then
			If $CPoint = $temp[1] Then
				$size = UBound($hplayer)
				ReDim $hplayer[$size+1][3]
				$hplayer[$size][0] = $temp[2]
				$hplayer[$size][1] = $temp[3]
				$hplayer[$size][2] = $temp[4]
			EndIf
			$CPoint += 1
		EndIf
	Next
	Return $hplayer
EndFunc

Func _Tictactoe_CheckLines( $stt, $player, $count, $ret = 0 )
	Local $IndexA, $IndexB, $Null, $Occupied, $LineNum = 0
	Local $Lines[8][3] = [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]]
	For $IndexA = 0 To UBound($Lines) - 1 Step 1
		Local $Null = 1, $Occupied = 0
		For $IndexB = 0 To 2 Step 1
			If Not $stt[$Lines[$IndexA][$IndexB]] Then
				$Null = $Lines[$IndexA][$IndexB]
			ElseIf $stt[$Lines[$IndexA][$IndexB]] = $player Then
				$Occupied += 1
			Else
				$Occupied = 0
				ExitLoop
			EndIf
		Next
		If $Occupied = $count And $Occupied Then
			If $ret Then
				Return $IndexA + 1
			Else
				Return $Null
			EndIf
		EndIf
	Next
	Return 0
EndFunc

Func _Tictactoe_GetRandomCell( $stt )
	Local $Array = _ArrayCreate(0), $Index
	For $Index = 1 To 9 Step 1
		If Not $stt[$Index] Then _
			_ArrayAdd($Array,$Index)
	Next

	If UBound($Array) = 1 Then
		Return 0
	ElseIf UBound($Array) = 2 Then
		Return $Array[1]
	EndIf

	Return $Array[Random(1,UBound($Array)-1,1)]
EndFunc

Func _Tictactoe_Quit( $exitcode, $errmsg = -1, $errcode = -1 )
	If $errmsg <> -1 Then _
		MsgBox( 16, 'Error - ' & $errcode, $errmsg )

	Exit $exitcode
EndFunc

#Region GUIs
Func _GUI_Main( $guiname )
	Local $hGui = GUICreate($guiname, 290, 350, -1, -1, 0x94CA0000, 0x00000100)
	GUISetBkColor($GUI_BKCOLOR_TRANSPARENT)

	_GUICtrlPic_Create($hSkin[1], 0, 0, 290, 350 )

	$hCtrls[0] = GUICtrlCreateButton("newfag - algorithm vs algorithm", 20, 146, 250, 26)
	$hCtrls[1] = GUICtrlCreateButton("foreveralone - player vs algorithm ", 20, 175, 250, 26)
	$hCtrls[2] = GUICtrlCreateButton("alphamale - player vs player", 20, 204, 250, 26)
	$hCtrls[3] = GUICtrlCreateButton("manualset - undefined vs undefined", 20, 233, 250, 26)

	$hCtrls[4] = GUICtrlCreateButton("About", 20, 284, 250, 26)
	$hCtrls[5] = GUICtrlCreateButton("Exit - :C", 20, 313, 250, 26)

	$hCtrls[6] = _GUICtrlPic_Create($hSkin[2], 0, -10, 290, 160 )
	GUISetState(@SW_SHOW, $hGui)

	Return $hGui
EndFunc

Func _GUI_Game( $playerid_1 = 0, $playerid_2 = 0 )
	If Not $playerid_1 Or Not $playerid_2 Then _
		Return ;Не все игроки определены

	Local $iPos = WinGetPos($hGui, "")
	GUISetState(@SW_DISABLE, $iPos)

	Local $guiname = 'Game[' & $hPlayer[$playerid_1][2] & ' vs ' & $hPlayer[$playerid_2][2] & ']'
	$hGuiGame = GUICreate( $guiname, 290, 350, $iPos[0], $iPos[1] + 100, -1, -1, $hGui)
	GUISetBkColor($GUI_BKCOLOR_TRANSPARENT)

	_GUICtrlPic_Create($hSkin[1], 0, 0, 290, 350 )
	_GUICtrlPic_Create($hSkin[3], 0, 0, 290, 350 )

	Local $hButtons[10] = [ 9 ], $Index
	#CS
	For $Index = 1 To 9 Step 1
		Local $shifts = 0
		Local $shiftx = Int(($Index/4)+1)+3
		Local $shifty = Int(($Index/3)+0.67)
		If Mod($Index + 1, 3) = -1 Then _
			$shifts = 8

		$hButtons[$Index] = GUICtrlCreateLabel('', $GUI_GRIDCELLS[$shiftx], $GUI_GRIDCELLS[$shifty],  80+$shifts, 102 )
		;GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
		Sleep(10)
	Next
	#CE
	For $Index = 1 To 9 Step 1
		Local $shifts = 0
		If Not Mod($Index + 1, 3) Then _
			$shifts = 8
		$hButtons[$Index] = GUICtrlCreateLabel('', $GUI_BUTTONGRID[$Index][0], $GUI_BUTTONGRID[$Index][1],  80+$shifts, 102 )
		GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
	Next
	GUISetState( @SW_SHOW )

	Local $Moves = $ALG_MOVEMENT, $State = $ALG_FIELDSTATE
	Local $Major[3] = ['',$playerid_1,$playerid_2]
	Local $Another[3] = ['',$playerid_2,$playerid_1]
	Local $Cellf, $Celle, $Winner = -1 ;f - friendly, e - enemy, -1 - undefined
	$Moves[3] = 1
	While 1
		Switch $hPlayer[$Major[$Moves[3]]][1] ;Алгоритм
			Case 'default' ;Ходит компьютер с алгоритмом default
				$Cellf = _Tictactoe_CheckLines( $State, $Major[$Moves[3]], 2 )
				$Celle = _Tictactoe_CheckLines( $State, $Another[$Moves[3]], 2 )
				If $Cellf Then ;Есть ряд, где две клетки наши и одна свободна
					$Moves[2] = $Cellf
				ElseIf $Celle Then ;Есть ряд, где две клетки противника и одна свободна
					$Moves[2] = $Celle
				ElseIf Not $State[5] And Random(1,3,1) <> 3 Then ;Центр свободен & Рандом для непредсказуемости
					$Moves[2] = 5 ;Занимаем центр
				ElseIf $State[5] = $Major[$Moves[3]] Then ;Центр наш
					;Ставим фишку в центральную вертикаль/горизонталь. - $ALG_PRIORITYCELLS
					For $Index = 1 To UBound($ALG_PRIORITYCELLS) - 1 Step 1
						If Not $State[$ALG_PRIORITYCELLS[$Index]] And (Not $Moves[2] Or Random(0,1,1)) Then _
							$Moves[2] = $ALG_PRIORITYCELLS[$index]
					Next
				EndIf
				If Not $Moves[2] Then
					$Cellf = _Tictactoe_CheckLines( $State, $Major[$Moves[3]], 1 )
					If $Cellf Then ;Есть ряд, где одна клетка наша и две свободны
						$Moves[2] = $Cellf
					Else
						$Cellf = _Tictactoe_GetRandomCell( $State )
						If $Cellf Then _
							$Moves[2] = $Cellf
					EndIf
				EndIf
			Case "bullshit"
				$Cellf = _Tictactoe_GetRandomCell( $State )
				If $Cellf Then _
					$Moves[2] = $Cellf

			Case 'playercontrol' ;Ходит игрок (управление мышкой). - Для возможности игры по сети(в будущем)
				While Not $Moves[2]
					$hMsg = GUIGetMsg()
					If $hMsg = $GUI_EVENT_CLOSE Then
						$Winner = 0
						ExitLoop 2
					EndIf

					For $Index = 1 To $hButtons[0] Step 1
						If $hMsg = $hButtons[$Index] And Not $State[$Index] Then
							$Moves[2] = $Index
							ExitLoop
						EndIf
					Next
					Sleep(10)
				WEnd
		EndSwitch

		;ConsoleWrite('Игрок ' & $Major[$Moves[3]] & ' ходит в ' & $Moves[2] & ' клетку' & @LF) ;DEBUG
		If $Moves[2] Then
			$Moves[1] = $Moves[2]
			$State[$Moves[2]] = $Major[$Moves[3]]
			If $Moves[3] = 1 Then
				$Moves[3] = 2
				_GUICtrlPic_Create($hSkin[4], $GUI_GRIDCELLS[$Moves[2]][0], $GUI_GRIDCELLS[$Moves[2]][1], 90, 100 )
			ElseIf $Moves[3] = 2 Then
				$Moves[3] = 1
				_GUICtrlPic_Create($hSkin[5], $GUI_GRIDCELLS[$Moves[2]][0], $GUI_GRIDCELLS[$Moves[2]][1], 90, 100 )
			EndIf
			$Moves[2] = 0
		Else
			$Winner = 0
		EndIf
		Sleep(500)

		If $Winner = -1 Then
			$Cellf = _Tictactoe_CheckLines( $State, $Another[$Moves[3]], 3, 1 )
			If $Cellf Then ;Проверка для игрока
				_GUICtrlPic_Create($hSkin[$GUI_LINES[$Cellf][0]], $GUI_LINES[$Cellf][1], $GUI_LINES[$Cellf][2], $GUI_LINES[$Cellf][3], $GUI_LINES[$Cellf][4] )
				$Winner = $Another[$Moves[3]]
				ExitLoop
			ElseIf Not _Tictactoe_GetRandomCell( $State ) Then
				$Winner = 0
				ExitLoop
			EndIf

			ContinueLoop
		EndIf

		ExitLoop
	WEnd
	Sleep(500)
	If $Winner Then
		MsgBox( 64, 'EndGame', 'Победил: ' & $hPlayer[$Winner][2] )
	Else
		MsgBox( 64, 'EndGame', 'Ничья!' )
	EndIf

	GUISetState(@SW_ENABLE, $hGui)
	GUIDelete($hGuiGame)
EndFunc

Func _GUI_Manual( $guiname )
	Local $hGuiManual, $hMsg, $hCtrlsManual[13]
	Local $iPos = WinGetPos($hGui, ""), $index
	Local $size = UBound($hPlayer) - 1, $sdata = ''
	GUISetState(@SW_DISABLE, $iPos)

	$hGuiManual = GUICreate( $guiname, 290, 178, $iPos[0], $iPos[1] + 100, -1, -1, $hGui)
	GUISetBkColor($GUI_BKCOLOR_TRANSPARENT)

	_GUICtrlPic_Create($hSkin[1], 0, -50, 290, 350 )

	$hCtrlsManual[0 ] = GUICtrlCreateList("", 5, 5, 280, 80)
	$hCtrlsManual[1 ] = GUICtrlCreateList("", 5, 80, 280, 80)
	$hCtrlsManual[2 ] = GUICtrlCreateButton("Set players and start", 5, 154, 280, 22)
	GUICtrlSetState( $hCtrlsManual[2 ], $GUI_DISABLE )

	For $index = 1 To $size Step 1
		$sdata &= $hPlayer[$index][2]
		If $size > $index Then _
			$sdata &= '|'
	Next
	GUICtrlSetData($hCtrlsManual[0 ],$sdata,'')
	GUISetState(@SW_SHOW, $hGuiManual)

	Local $nsitem = '', $ositem = ''
	Local $nitem = '', $oitem = '', $ids
	While 1
		$hMsg = GUIGetMsg()
		Switch $hMsg
			Case $GUI_EVENT_CLOSE
				ExitLoop
			Case $hCtrlsManual[2 ]
				If $ids[0] And $ids[1] Then
					_GUI_Game( $ids[0], $ids[1] )
					ExitLoop
				Else
					_Tictactoe_Quit( 4, 'Shift fucking arrays!', 1337 )
				EndIf
		EndSwitch

		$nitem = GUICtrlRead($hCtrlsManual[0 ])
		$nsitem = GUICtrlRead($hCtrlsManual[1 ])
		If $oitem <> $nitem Then
			$sdata = ''
			For $index = 1 To $size Step 1
				If $hPlayer[$index][2] <> $nitem Then
					$sdata &= $hPlayer[$index][2]
					If $size > $index Then _
						$sdata &= '|'
				EndIf
			Next
			GUICtrlSetData($hCtrlsManual[1 ],'','')
			GUICtrlSetData($hCtrlsManual[1 ],$sdata,'')
			GUICtrlSetState($hCtrlsManual[2 ], $GUI_DISABLE )
			$oitem = $nitem
		ElseIf $nsitem <> $ositem Then
			$ositem = $nsitem
			Dim $ids[2] = [0,0]
			For $index = 1 To $size Step 1
				If $hPlayer[$index][2] = $nitem Then
					$ids[0] = $index
				ElseIf $hPlayer[$index][2] = $nsitem Then
					$ids[1] = $index
				EndIf
			Next
			GUICtrlSetState( $hCtrlsManual[2 ], $GUI_ENABLE )
		EndIf
	WEnd

	GUISetState(@SW_ENABLE, $hGui)
	GUIDelete($hGuiManual)
EndFunc

Func _GUI_About( $guiname )
	MsgBox( 64, $guiname, 'Tictactoe - concept' & @LF & _
		'Version:' & @TAB & '0.1.b' & @LF & _
		'Thanks:' & @TAB & 'Hidan' & @LF & _
		'Author:' & @TAB & 'Firex' & @LF & @LF & _
		'Not specifically for codhacks.ru', 0, $hGui )
EndFunc
#EndRegion GUIs

Func _GUICtrlPic_Create($hImage, $iX, $iY, $iW, $iH )
	Local $iCtrl, $hBitmap, $hObject

	$iCtrl = GUICtrlCreatePic('', $iX, $iY, $iW, $iH)
	GUICtrlSetState(-1, $GUI_DISABLE)

	$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
	$hObject = _SendMessage(GUICtrlGetHandle($iCtrl), 0x0172, 0, $hBitmap )
	_WinAPI_DeleteObject( $hObject )

	Return $iCtrl
EndFunc

Func _GUICtrlPic_Show($iCtrl)
	GUICtrlSetState($iCtrl, $GUI_SHOW)
	GUICtrlSetState($iCtrl, $GUI_DISABLE)
EndFunc

Func _GUICtrlPic_Hide($iCtrl)
	GUICtrlSetState($iCtrl, $GUI_HIDE)
EndFunc

Файл: Rar

Снимок:


Источник: autoit-script.ru
Автор(ы): Firex

P.S. Можете предложить свой алгоритм, посоревнуетесь с моим. (default alg)
 

mef-t

Осваивающий
Сообщения
306
Репутация
30
В этой игре не так много вариантов.
При условии стандартных правил, и поля 3х3 знаю алгоритм, как 100% не проиграть, и даже выиграть, если противник сделал не правильным первый ход.


Добавлено:
Сообщение автоматически объединено:

Разберусь с Вашим алгоритмом, напишу свой
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Ну не знаю.
За GUI, конечно, 5. :thumbs_up: А алгоритм тянет на 3-. :(
Адлгоритм рабочий, да. Делает правильные ходы. Но напоминает латание дыр. Извините, если это курсовая, которая была написана год назад, то автор, по-моему, уже должен быть знаком с теорией игр.
А на какую тему была курсовая?
Почему то теорию игр начинают изучать с поля 2х2, а потом сразу перескакивают на шахматную доску. имхо, вот прекрасный пример для изучения в "школе" - ограниченное поле и конечное количество ходов, то есть функция оценки небольшой глубины, для оценки хода достаточно трёх значений (выиграл, ничья, проиграл). Вобщем хороший вариант чтобы попрактиковаться.
firex, я советую переписать алгоритм, сделать всё как положено и сдать как работу уже по другому предмету. ;D
 

mef-t

Осваивающий
Сообщения
306
Репутация
30
Алгоритм:
1. Если ходим первыми, то
- первый крестик в угол
- если оппонент ставит нолик в центр, то ставим крестик в противоположный угол от первого
далее все свои крестики ставить напротив ноликов оппонента, т.е. симметрично (чтобы не проиграть, т.к. у него нолик в центре)
- если оппонент ставит нолик в угол, то ставим крестик в любой другой угол
далее, оппонент закрывается и ставим крестик в оставшийся свободный угол
- если оппонент ставит нолик на грани, то ставим крестик в противоположный угол.
далее оппонент закрывается, и ставим крестик в другой угол, но угол нужно выбрать так, чтобы образовалось 2 потенциальные линии.

!!! в любой момент, если образовалась возможность сделать три крестика, то нарушаем алгоритм и делаем 3 крестика в ряд.

2. Если ходим вторыми, то
- если центр занят, ставим в угол
далее если противник поставил нолик в противоположный угол, то занимаем любой другой угол, иначе закрываемся
- если центр свободен, занимаем
далее или закрываемся, если требуется, или занимаем грани (не углы)

P.S. наверно единственный правильный алгоритм :smile: Высчитывал сам, но других вариантов просто и быть не может, так как и ходов то мало
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
C2H5OH [?]
firex, я советую переписать алгоритм, сделать всё как положено и сдать как работу уже по другому предмету.
Еще во время разработки подумывал сделать граф-алгоритм(если учесть все ситуации, ты выиграть невозможно), но поскольку был первый семестр - от нас много и не ждали.

А алгоритм на самом деле слабоват, это я понимаю. Если поставить Рандом с Default, то были случаи, когда Рандом побеждал ;D



Добавлено:
Сообщение автоматически объединено:

mef-t
Знаешь, на момент разработки я тоже так думал о кол-ве вариантов, но на самом деле не все так просто.

Код:
0 - 1 - 2 - 3 - 6,w
          - 4 - 6,w
          - 5 - 6,w
          - 6 - 7 - *
          - 7 - 6,w
          - 8 - 6,w
  - 2 - 1 - 3 - 5,w
          - 4 - 5,w
          - 7 - 5,w
          - 6 - 5,w
          - 8 - 5,w
          - 5 - 8 - 3 - 7,w
                  - 4 - 7,w
                  - 6 - 7,w
                  - 7 - 4,w

И тут описана лишь (1+1/5)/(5*5*5*5)*100 = 0,192%
И это при условии, что первым ходит компьютер и поле представлено в виде:
Код:
1 2 3
8 0 4
7 6 5

(хотя в графе описано не для такого поля, это пример что бы вы поняли масштабы результата).


Добавлено:
Сообщение автоматически объединено:

mef-t
Сейчас попробую перенести ваши идеи и сопоставим его с моим. ;D
Весело бывает наблюдать за борьбой компьютеров с разными алгоритмами.


Добавлено:
Сообщение автоматически объединено:

mef-t
Код:
Case "meftalg_2"
	$Cellf = _Tictactoe_CheckLines( $State, $Major[$Moves[3]], 2 )
	$Celle = _Tictactoe_CheckLines( $State, $Another[$Moves[3]], 2 )
	If $Cellf Then
		$Moves[2] = $Cellf
	ElseIf $Celle Then
		$Moves[2] = $Celle
	ElseIf $Another[$Moves[3]] = $State[5] Then
		$Cellf = _Tictactoe_CheckCells( $State, $Major[$Moves[3]], 1, 3, 7, 9 ) ;Возвращает массив из предложенных ячеек(принадлежащие нам)
		For $Index = 1 To $Cellf[0] Step 1
			If Not $Moves[2] Or Random( 0, 2, 1 ) Then
				Select
					Case $Cellf[$Index] = '1' And Not $State[9]
						$Moves[2] = 9
					Case $Cellf[$Index] = '3' And Not $State[7]
						$Moves[2] = 7
					Case $Cellf[$Index] = '9' And Not $State[1]
						$Moves[2] = 1
					Case $Cellf[$Index] = '7' And Not $State[3]
						$Moves[2] = 3
				EndSelect
			EndIf
		Next
		If Not $Moves[2] Then
			$Cellf = _Tictactoe_CheckCells( $State, 0, 1, 3, 7, 9 ) ;0 - свободны
			If $Cellf[0] > 0 Then
				$Moves[2] = Int( $Cellf[ Random( 1, $Cellf[0], 1 ) ] )
			Else ;Все углы заняты, центр занят.
				;Этот вариант вами не описан, поэтому рандом:
				$Cellf = _Tictactoe_GetRandomCell( $State )
				If $Cellf Then _
					$Moves[2] = $Cellf
			EndIf
		EndIf
	ElseIf Not $State[5] Then
		$Moves[2] = 5
	ElseIf $State[5] = $Major[$Moves[3]] Then
		$Cellf = _Tictactoe_CheckCells( $State, 0, 2, 4, 6, 8 ) ;0 - свободны
		If $Cellf[0] > 0 Then
			$Moves[2] = Int( $Cellf[ Random( 1, $Cellf[0], 1 ) ] )
		Else
			$Cellf = _Tictactoe_GetRandomCell( $State )
			If $Cellf Then _
				$Moves[2] = $Cellf
		EndIf
	EndIf


Вариант вашего алгоритма (если вторым ходить).
Не обойдется без функции:

Код:
Func _Tictactoe_CheckCells( $stt, $player, $c1, $c2 = 0, $c3 = 0, $c4 = 0 )
	Local $_sResult, $_aRet, $Idx, $Tmp

	For $Idx = 1 To 4 Step 1
		$Tmp = Int(Eval('c' & $Idx))
		If $stt[$Tmp] = $player And $Tmp Then
			$_sResult &= $Tmp
			If $Idx < 4 Then _
				$_sResult &= '_'
		EndIf
	Next

	$_aRet = StringSplit( $_sResult, '_' )
	If $_aRet[$_aRet[0]] = '' Then
		$_aRet[0] = 0
	EndIf

	Return $_aRet
EndFunc


Пойду тестировать.

*Запустил 8 игр - все в ничью.
*Поправил.
 

AZJIO

Меценат
Меценат
Сообщения
2,791
Репутация
1,161
Первый ход может начинаться с угла, с середины стороны, с центра. Остальные ходы это копия этих трёх просто с разной точкой отсчёта. Надо сразу "поворачивать" чтобы легко воспринимать остальные ходы относительно первого хода.
Можно добавить сложность "Непобедимый, средний, рандомный. Средний я думаю не должен делать точных ходов для выйгрыша, но выбирающий к этому разумный ход.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Совершенно неожиданно понадобилось вдруг написать для одного бота...
Алгоритм, естественно, такой как в учебниках по теории игр.
Код:
#include <Array.au3>
$str = "000000000"
; стартовое поле
; "0" - пустая клетка
; "X" - крестик (ИКС, не путать с Ха)
; "O" - нолик (ЛАТИНСКАЯ O, не путать с русской)

While _x0_calc($str) == "Unknown"
	$aPole = StringSplit($str,"")
	$xod = InputBox("", $aPole[1]&'|'&$aPole[2]&'|'&$aPole[3]&@CRLF&'-+-+-'&@CRLF&$aPole[4]&'|'&$aPole[5]&'|'&$aPole[6]&@CRLF&'-+-+-'&@CRLF&$aPole[7]&'|'&$aPole[8]&'|'&$aPole[9])
	If @error Then ExitLoop
	$str = _x0_setBet($str, $xod, "X")
	ConsoleWrite($str&@CRLF)
	$k = _x0_Select_0($str)
	ConsoleWrite("выбран ход "&$k&@CRLF)
	$str = _x0_setBet($str, $k, "O")
WEnd
$aPole = StringSplit($str,"")
MsgBox(0, "", $aPole[1]&'|'&$aPole[2]&'|'&$aPole[3]&@CRLF&'-+-+-'&@CRLF&$aPole[4]&'|'&$aPole[5]&'|'&$aPole[6]&@CRLF&'-+-+-'&@CRLF&$aPole[7]&'|'&$aPole[8]&'|'&$aPole[9])

Func _x0_Select_X($sPole)
; выбор клетки куда поставить Х
; $sPole - исходное поле 9 символов
; возращает номер клетки для хода
	Local $aEmpty = _x0_SearchEmptyCells($sPole)
	If $aEmpty[0] = 0 Then Return 0
	Local $aEst[$aEmpty[0]+1]
	$aEst[0] = $aEmpty[0]
	Local $sVariant
	For $i = 1 To $aEmpty[0]
		$sVariant = _x0_setBet($sPole, $aEmpty[$i], "X")
		ConsoleWrite($sVariant&@CRLF)
		$aEst[$i] = _x0_Explore_X($sVariant)
	Next
	Local $iRes = 1
	For $i = 2 To $aEst[0]
		If $aEst[$i] > $aEst[$iRes] Then $iRes = $i
	Next
	Return $aEmpty[$iRes]
EndFunc

Func _x0_Select_0($sPole)
; выбор клетки куда поставить O
; $sPole - исходное поле 9 символов
; возращает номер клетки для хода
	Local $aEmpty = _x0_SearchEmptyCells($sPole)
	If $aEmpty[0] = 0 Then Return 0
	;_ArrayDisplay($aEmpty)
	Local $aEst[$aEmpty[0]+1]
	$aEst[0] = $aEmpty[0]
	Local $sVariant
	For $i = 1 To $aEst[0]
		$sVariant = _x0_setBet($sPole, $aEmpty[$i], "O")
		ConsoleWrite("рассматривается ход "&$sVariant)
		$aEst[$i] = _x0_Explore_0($sVariant)
		ConsoleWrite("  оценка "&$aEst[$i]&@CRLF)
	Next
	Local $iRes = 1
	For $i = 2 To $aEst[0]
		If $aEst[$i] < $aEst[$iRes] Then $iRes = $i
	Next
	Return $aEmpty[$iRes]
EndFunc

Func _x0_Explore_X($sPole)
; оценка поля для варианта хода крестиком
; $sPole - исходное поле 9 символов
; возращает оценку:
; 1 - выиграл Х
; 0 - ничия
; -1 - выиграл 0
	Local $point = _x0_calc($sPole)
	If $point == "Unknown" Then
		; старнный глюк при условии  $point <> "Unknown"
	Else
		Return $point
	EndIf

	Local $aPole = StringSplit($sPole,"")
	Local $aEmpty = _x0_SearchEmptyCells($sPole)
	;_ArrayDisplay($aEmpty)
	Local $aEst[$aEmpty[0]+1]
	$aEst[0] = $aEmpty[0]
	Local $sVariant
	For $i = 1 To $aEst[0]
		$sVariant = _x0_setBet($sPole, $aEmpty[$i], "O")
		$aEst[$i] = _x0_Explore_0($sVariant)
	Next
	Local $Res = $aEst[1]
	For $i = 2 To $aEst[0]
		If $aEst[$i] < $Res Then $Res = $aEst[$i]
	Next
	Return $Res
EndFunc

Func _x0_Explore_0($sPole)
; оценка поля для варианта хода ноликом
; $sPole - исходное поле 9 символов
; возращает оценку:
; 1 - выиграл Х
; 0 - ничия
; -1 - выиграл 0
	Local $point = _x0_calc($sPole)
	If $point == "Unknown" Then
		; старнный глюк при условии  $point <> "Unknown"
	Else
		Return $point
	EndIf
	Local $aPole = StringSplit($sPole,"")
	Local $aEmpty = _x0_SearchEmptyCells($sPole)
	Local $aEst[$aEmpty[0]+1]
	$aEst[0] = $aEmpty[0]
	Local $sVariant
	For $i = 1 To $aEst[0]
		$sVariant = _x0_setBet($sPole, $aEmpty[$i], "X")
		$aEst[$i] = _x0_Explore_X($sVariant)
	Next
	;_ArrayDisplay($aEst,$sPole)
	Local $Res = $aEst[1]
	For $i = 2 To $aEst[0]
		If $aEst[$i] > $Res Then $Res = $aEst[$i]
	Next
	Return $Res
EndFunc

Func _x0_calc($sPole)
; проверка поля на предмет окончания игры
; $sPole - исходное поле 9 символов
; возращает оценку:
; 1 - выиграл Х
; 0 - ничия
; -1 - выиграл 0
; "Unknown" - игра не закончена
	If StringRegExp($sPole, "X..X..X|X...X...X|..X.X.X..|^(...){0,2}XXX", 0) Then Return 1
	If StringRegExp($sPole, "O..O..O|O...O...O|..O.O.O..|^(...){0,2}OOO", 0) Then Return -1
	If StringInStr($sPole,"0") = 0 Then Return 0
	Return "Unknown"
EndFunc

Func _x0_setBet($sPole, $index, $fishka)
; формирует поле для варианта хода
; $sPole - исходное поле 9 символов
; $index - номер клетки куда делается ход
; $fishka - кто ходит: Х - O
	Return StringLeft($sPole, $index-1) & $fishka & StringTrimLeft($sPole, $index)
EndFunc

Func _x0_SearchEmptyCells($sPole)
; формирует массив номеров незанятых клеток поля
; $sPole - исходное поле 9 символов
; незанятое поле - "0"
	StringReplace($sPole,"0","0")
	Local $N = @extended
	Local $aEmpty[$N+1]
	$aEmpty[0] = $N
	If $N = 0 Then Return $aEmpty
	Local $aPole = StringSplit($sPole,"")
	Local $ind = 1
	For $i=1 To $aPole[0]
		If $aPole[$i] == "0" Then
			$aEmpty[$ind] = $i
			$ind += 1
		EndIf
	Next
	Return $aEmpty
EndFunc

Код не использует специфичные функции AutoIt, так как будет переводиться на js. Просто для меня писать на AutoIt намного легче.
 

unsend

Новичок
Сообщения
27
Репутация
2
Хотите беспроигрышный вариант ваших версий?;D Повторять ходы противника))) Кто проверку делать будет что клетка занята???)))
 
Верх