// writePump pumps messages from the hub to the websocket connection.
func (c *connection) writePump() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.ws.Close()
	}()
	for {
		select {
		case threadToResponse, ok := <-c.send:
			if !ok {
				c.write(websocket.CloseMessage, []byte{})
				return
			}
			if err := c.ws.WriteJSON(threadToResponse); err != nil {
				l.Output(
					logrus.Fields{
						l.ErrMsg:   l.ErrToStr(err),
						l.TraceMsg: l.TraceToStr(l.Trace()),
						"Thread":   l.Sprintf(threadToResponse),
					},
					"can not write JSON",
					l.Debug,
				)
				return
			}
		case <-ticker.C:
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				l.PutErr(err, l.Trace(), l.E_R_PingMsg, websocket.PingMessage)
				return
			}
		}
	}
}
// readPump pumps messages from the websocket connection to the hub.
func (c *connection) readPump() {
	defer func() {
		H.Unregister <- c
		c.ws.Close()
	}()
	c.ws.SetReadLimit(maxMessageSize)
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
	c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {

		err := c.ws.ReadJSON(&thread)
		if err != nil {
			if thread == nil {
				break
			}
			l.Output(
				logrus.Fields{
					l.ErrMsg:   l.ErrToStr(err),
					l.TraceMsg: l.TraceToStr(l.Trace()),
					"Thread":   l.Sprintf(thread),
				},
				"can not read JSON or Closed Websocket",
				l.Debug,
			)
			break
		}

		if newThread, err = m.UpdateExistingTimeLine(thread); err != nil {
			l.PutErr(err, l.Trace(), l.E_R_Upsert, thread)
		}

		H.Broadcast <- newThread
	}
}
func PostApplyScoreData(teamName string, ApplyScore *PostApplyScore) (*Status, error) {
	l.PutInfo(l.I_M_PostPage, teamName, ApplyScore)

	//更新情報をGlobal変数に格納する
	defer SetPlayerCol(ApplyScore.UserIds)

	AUserIdInTheTeam := teams[teamName].UserIds[0]
	if players[AUserIdInTheTeam].Apply != 0 {
		l.Output(
			logrus.Fields{
				"User Apply": l.Sprintf(players[AUserIdInTheTeam].Apply),
			},
			"Apply score is already registered",
			l.Debug,
		)
		return &Status{"already registered"}, nil
	}
	for playerIndex, userId := range ApplyScore.UserIds {

		findQuery := bson.M{"userid": userId}
		setQuery := bson.M{"$set": bson.M{"apply": ApplyScore.Apply[playerIndex]}}
		if err = UpdateMongoData("player", findQuery, setQuery); err != nil {
			l.PutErr(err, l.Trace(), l.E_M_Update, ApplyScore.Apply[playerIndex])
			return &Status{"failed"}, err
		}
	}

	return &Status{"success"}, nil
}
func UpsertNewTimeLine(thread *Thread) error {
	l.PutInfo(l.I_M_PostPage, thread, nil)

	//更新情報をGlobal変数に格納する
	defer SetAllThreadCol()

	defaultColor := "#c0c0c0"

	if len(thread.ThreadId) != 0 {
		l.PutErr(nil, l.Trace(), l.E_WrongData, thread)
		return errors.New("thread id exists")
	}

	db, session := mongoConn()
	threadCol := db.C("thread")
	defer session.Close()

	thread.ThreadId = make20lengthHashString()
	thread.CreatedAt = time.Now().Format(c.DatetimeFormat)
	thread.ColorCode = defaultColor
	if err = threadCol.Insert(thread); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_Insert, thread)
		return err
	}

	ThreadChan <- thread

	return nil
}
func RegisterFieldColData(date string, fieldCols []FieldCol) (*Status, error) {
	l.PutInfo(l.I_M_RegisterCol, date, fieldCols)

	defer SetAllFieldCol()

	db, session := mongoConn()
	fieldC := db.C("field")
	defer session.Close()

	var createCnt, updateCnt int
	for _, fieldCol := range fieldCols {
		if fieldCol.Hole > 18 || fieldCol.Hole < 0 {
			l.PutErr(nil, l.Trace(), l.E_WrongData, fieldCol.Hole)
			return &Status{"this is not hole number"}, err
		}

		fieldCol.Ignore = false
		fieldCol.Date = date
		findQuery := bson.M{"hole": fieldCol.Hole}

		change, err := fieldC.Upsert(findQuery, fieldCol)
		if err != nil {
			l.PutErr(err, l.Trace(), l.E_M_Upsert, fieldCol.Hole)
			return &Status{"can not upsert"}, err
		}
		if change.Updated == 0 {
			createCnt += 1
		} else {
			updateCnt += 1
		}
	}

	return &Status{"success"}, nil
}
func RegisterThreadImg(r *RequestTakePictureStatus) (*RequestTakePictureStatus, error) {
	l.PutInfo(l.I_M_RegisterCol, r, nil)

	defer SetPlayerCol([]string{r.UserId})

	if len(r.ThreadId) == 0 {
		return nil, errors.New("there is not thread id")
	}

	if len(r.PhotoUrl) == 0 {
		return nil, errors.New("there is not pthoto url ")
	}

	threadFindQuery := bson.M{"threadid": r.ThreadId}
	threadSetQuery := bson.M{"$set": bson.M{"imgurl": r.PhotoUrl}}
	if err = UpdateMongoData("thread", threadFindQuery, threadSetQuery); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_Update, r.PhotoUrl)
		return &RequestTakePictureStatus{Status: "failed"}, err
	}

	var photoKey string
	if r.Positive {
		photoKey = "positivephotourl"
	} else {
		photoKey = "negativephotourl"
	}
	playerFindQuery := bson.M{"userid": r.UserId}
	playerSetQuery := bson.M{"$set": bson.M{photoKey: r.PhotoUrl}}

	if err = UpdateMongoData("player", playerFindQuery, playerSetQuery); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_Update, r.PhotoUrl)
		return &RequestTakePictureStatus{Status: "failed"}, err
	}

	SetAllThreadCol()
	thread := &Thread{
		ThreadId:  r.ThreadId,
		UserId:    threads[r.ThreadId].UserId,
		UserName:  threads[r.ThreadId].UserName,
		Msg:       threads[r.ThreadId].Msg,
		ImgUrl:    threads[r.ThreadId].ImgUrl,
		ColorCode: threads[r.ThreadId].ColorCode,
		Positive:  threads[r.ThreadId].Positive,
		CreatedAt: threads[r.ThreadId].CreatedAt,
	}

	ThreadChan <- thread

	requestTakePictureStatus, err := RequestTakePicture(r.TeamUserIds)
	if err != nil {
		return nil, err
	}

	if len(requestTakePictureStatus.ThreadId) != 0 {
		return requestTakePictureStatus, nil
	}

	return &RequestTakePictureStatus{Status: "success"}, nil

}
Beispiel #7
0
func (player TMainPlayer) GetJosekiMove(ban *TBan, all_moves *map[int]*TMove) *TMove {
	logger := GetLogger()
	current_sfen := ban.ToSFEN(false)

	// 現在の局面に定跡が登録されているか確認する
	fix_move, fix_move_exists := player.Joseki.FixOpening[*(ban.Tesuu)+1]
	var fix_move_string string = ""
	if fix_move_exists {
		fix_move_string = fix_move.GetUSIMoveString()
		logger.Trace("[MainPlayer] fix_move_string is: " + fix_move_string)
	} else {
		sfen_joseki_move, exists := player.Joseki.SFENMap[current_sfen]
		if exists {
			fix_move_string = sfen_joseki_move.GetUSIMoveString()
			logger.Trace("[MainPlayer] sfen_joseki_move_string is: " + fix_move_string)
		}
	}

	// 定跡手が存在する場合、(念のため)手があることを確認して返す
	if fix_move_string != "" {
		for key, move := range *all_moves {
			move_string := move.GetUSIMoveString()
			if fix_move_string == move_string {
				return (*all_moves)[key]
			} else {
				continue
			}
		}
	}
	return nil
}
func RegisterTeamColData(date string, teamCols []TeamCol) (*Status, error) {
	l.PutInfo(l.I_M_RegisterCol, date, teamCols)

	defer SetAllPlayerCol()
	defer SetAllTeamCol()

	db, session := mongoConn()
	playerC := db.C("player")
	teamC := db.C("team")
	defer session.Close()

	var OneBeforebyteOfA byte = 64
	alphabet := make([]byte, 1)
	alphabet[0] = OneBeforebyteOfA

	totalHoleNum := 18

	for _, teamCol := range teamCols {
		if len(teamCol.UserIds) == 0 {
			l.PutErr(nil, l.Trace(), l.E_Nil, teamCol)
			return &Status{"this team do not have user id"}, nil
		}

		alphabet[0] += 1
		teamCol.Name = string(alphabet)
		teamCol.Defined = false
		teamCol.Date = date

		if err := teamC.Insert(teamCol); err != nil {
			l.PutErr(err, l.Trace(), l.E_M_Insert, teamCol)
			return &Status{"can not insert"}, err
		}

		for _, userId := range teamCol.UserIds {
			scores := []bson.M{}
			for holeNum := 1; holeNum <= totalHoleNum; holeNum++ {
				score := bson.M{
					"hole":  holeNum,
					"putt":  0,
					"total": 0,
				}
				scores = append(scores, score)

			}

			player := PlayerCol{
				UserId: userId,
				Score:  scores,
				Date:   date,
			}
			if err := playerC.Insert(player); err != nil {
				l.PutErr(err, l.Trace(), l.E_M_Insert, player)
				return &Status{"can not insert"}, err
			}
		}
	}
	return &Status{"success"}, nil
}
func PostScoreEntrySheetPageData(teamName string, holeString string, teamScore *PostTeamScore) (*RequestTakePictureStatus, error) {
	l.PutInfo(l.I_M_PostPage, teamName, teamScore)

	userIds := teams[teamName].UserIds
	//更新情報をGlobal変数に格納する
	defer SetPlayerCol(userIds)

	if len(holeString) == 0 {
		l.PutErr(nil, l.Trace(), l.E_Nil, teamName)
		return &RequestTakePictureStatus{Status: "failed"}, errors.New("hole is not string")
	}

	holeNum, _ := strconv.Atoi(holeString)
	holeIndex := holeNum - 1
	holeIndexString := strconv.Itoa(holeIndex)

	if teamScore.Excnt != excnt[teamName][holeNum] {
		return &RequestTakePictureStatus{Status: "other updated"}, nil
	} else {
		excnt[teamName][holeNum]++
	}

	for playerIndex, userId := range teamScore.UserIds {
		total, putt := teamScore.Total[playerIndex], teamScore.Putt[playerIndex]

		findQuery := bson.M{"userid": userId}
		setQuery := bson.M{
			"$set": bson.M{
				"score." + holeIndexString + ".total": total,
				"score." + holeIndexString + ".putt":  putt,
			},
		}
		if err = UpdateMongoData("player", findQuery, setQuery); err != nil {
			l.PutErr(err, l.Trace(), l.E_M_Update, userId)
			return &RequestTakePictureStatus{Status: "failed update score"}, err
		}
	}
	//	Thread登録
	if err := RegisterThreadOfScore(holeString, teamScore); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_RegisterThread, teamScore)
		return nil, err
	}

	//	チーム内に写真リクエストがあるか確認する
	requestTakePictureStatus, err := RequestTakePicture(userIds)
	if err != nil {
		l.PutErr(err, l.Trace(), l.E_M_SearchPhotoTask, userIds)
		return nil, err
	}

	return requestTakePictureStatus, nil
}
Beispiel #10
0
func (ban TBan) DoMove(from TPosition, to TPosition, promote bool) {
	logger := GetLogger()
	// fromにある駒を取得
	from_masu := ban.AllMasu[from]
	from_koma := ban.AllKoma[from_masu.KomaId]
	if from_koma == nil {
		// 盤と手、どちらかがおかしい
		logger.Trace("ERROR!! no Koma exists at: " + s(from))
		return
	}

	// fromにある手を取得
	moves := ban.AllMoves[from_koma.Id]
	var move *TMove = nil
	for _, value := range moves.Map {
		if value.ToPosition == to {
			move = value
			break
		}
	}
	if move == nil {
		// 盤と手、どちらかがおかしい
		logger.Trace("ERROR!! Koma at: " + s(from) + ",no Move exists to: " + s(to))
		return
	} else {
		if move.ToId == 0 {
			// 相手の駒を取る手ではない
		} else {
			// 相手の駒を取る
			capture_koma := ban.AllKoma[move.ToId]
			if capture_koma.Position != to {
				logger.Trace("ERROR!! capture_koma id " + s(move.ToId) + " is at: " + s(capture_koma.Position))
			} else {
				ban.CaptureKoma(move.ToId)
			}
		}
	}

	// fromにある駒をいったん盤から取り除く
	ban.RemoveKoma(from_masu.KomaId)

	// 取り除いた駒をtoに置く
	from_koma.Position = to
	// 駒が成る場合
	if promote {
		from_koma.Promoted = true
	}
	ban.PutKoma(from_koma)
}
func GetScoreEntrySheetPageData(teamName string, holeString string) (*ScoreEntrySheet, error) {
	l.PutInfo(l.I_M_GetPage, teamName, holeString)

	if len(holeString) == 0 {
		l.PutErr(nil, l.Trace(), l.E_Nil, teamName)
		return nil, errors.New("hole string is nil")
	}
	holeNum, _ := strconv.Atoi(holeString)
	holeIndex := holeNum - 1

	field := fields[holeNum]

	userIds := teams[teamName].UserIds
	member := make([]string, len(userIds))
	total := make([]int, len(userIds))
	putt := make([]int, len(userIds))
	for i, userId := range userIds {
		member[i] = users[userId].Name
		total[i] = players[userId].Score[holeIndex]["total"].(int)
		putt[i] = players[userId].Score[holeIndex]["putt"].(int)
	}

	scoreEntrySheet := ScoreEntrySheet{
		Team:    teamName,
		Hole:    holeNum,
		Member:  member,
		UserIds: userIds,
		Par:     field.Par,
		Yard:    field.Yard,
		Total:   total,
		Putt:    putt,
		Excnt:   excnt[teamName][holeNum],
	}
	return &scoreEntrySheet, nil
}
func make20lengthHashString() string {
	b := make([]byte, 32)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		l.PutErr(err, l.Trace(), l.E_MakeHash, rand.Reader)
	}
	longHash := strings.TrimRight(base32.StdEncoding.EncodeToString(b), "=")

	return string([]rune(longHash)[:20])
}
// serveWs handles websocket requests from the peer.
func ServeWs(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		l.PutErr(err, l.Trace(), l.E_R_Upgrader, nil)
		return
	}
	c := &connection{send: make(chan *m.Thread, 256), ws: ws}
	H.Register <- c
	go c.writePump()
	c.readPump()
}
Beispiel #14
0
func (ban *TBan) CheckEmptyMasu() {
	logger := GetLogger()
	empty_masu := make([]TPosition, 81)
	fu_drop_sente := make([]byte, 0)
	fu_drop_gote := make([]byte, 0)
	var x, y byte = 1, 1
	for x <= 9 {
		fu_sente := false
		fu_gote := false
		y = 1
		for y <= 9 {
			pos := Bytes2TPosition(x, y)
			// logger.Trace("CheckEmptyMasu pos: " + s(pos))
			masu := ban.AllMasu[pos]
			if masu.KomaId == 0 {
				// 空いたマスを保存
				empty_masu = append(empty_masu, pos)
				// logger.Trace("CheckEmptyMasu append. pos: " + s(pos))
			} else {
				koma := ban.AllKoma[masu.KomaId]
				if koma.Position != pos {
					// ありえないが、バグとしてありえるので予め
					logger.Trace("CheckEmptyMasu Ghost Koma Id: " + s(koma.Id))
					masu.KomaId = 0
					empty_masu = append(empty_masu, pos)
				} else {
					// その列の歩の有無をチェック
					if koma.Kind == Fu {
						if koma.IsSente {
							fu_sente = true
						} else {
							fu_gote = true
						}
					}
				}
			}
			y++
		}
		if !fu_sente {
			fu_drop_sente = append(fu_drop_sente, x)
		}
		if !fu_gote {
			fu_drop_gote = append(fu_drop_gote, x)
		}
		x++
	}
	// 独自のstructに値を保存するには、レシーバをアドレス表記にする必要がある。
	ban.EmptyMasu = empty_masu
	ban.FuDropSente = fu_drop_sente
	ban.FuDropGote = fu_drop_gote
	// logger.Trace("CheckEmptyMasu ok: " + s(empty_masu))
}
func SetAllUserCol() {
	db, session := mongoConn()
	col := db.C("user")
	defer session.Close()
	usersCol := []UserCol{}
	if err = col.Find(nil).All(&usersCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindEntireCol, nil)
	}

	for _, userCol := range usersCol {
		users[userCol.UserId] = userCol
	}
}
func SetAllThreadCol() {
	db, session := mongoConn()
	col := db.C("thread")
	defer session.Close()
	threadsCol := []ThreadCol{}
	if err = col.Find(nil).All(&threadsCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindEntireCol, nil)
	}

	for _, threadCol := range threadsCol {
		threads[threadCol.ThreadId] = threadCol
	}
}
func SetAllPlayerCol() {
	db, session := mongoConn()
	col := db.C("player")
	defer session.Close()
	playersCol := []PlayerCol{}
	if err = col.Find(nil).All(&playersCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindEntireCol, nil)
	}

	for _, playerCol := range playersCol {
		players[playerCol.UserId] = playerCol
	}
}
func SetAllTeamCol() {
	db, session := mongoConn()
	col := db.C("team")
	defer session.Close()
	teamsCol := []TeamCol{}
	if err = col.Find(nil).All(&teamsCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindEntireCol, nil)
	}

	for _, teamCol := range teamsCol {
		teams[teamCol.Name] = teamCol
	}
}
func SetAllFieldCol() {
	db, session := mongoConn()
	col := db.C("field")
	defer session.Close()
	fieldsCol := []FieldCol{}
	if err = col.Find(nil).All(&fieldsCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindEntireCol, nil)
	}

	for _, fieldCol := range fieldsCol {
		fields[fieldCol.Hole] = fieldCol
	}
}
func SetThreadCol(threadId string) {
	db, session := mongoConn()
	col := db.C("thread")
	defer session.Close()

	threadCol := ThreadCol{}
	findQuery := bson.M{"threadid": threadId}

	if err = col.Find(findQuery).One(&threadCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindCol, findQuery)
	}

	threads[threadId] = threadCol
}
func SetFieldCol(hole int) {
	db, session := mongoConn()
	col := db.C("field")
	defer session.Close()

	fieldCol := FieldCol{}
	findQuery := bson.M{"hole": hole}

	if err = col.Find(findQuery).One(&fieldCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindCol, findQuery)
	}

	fields[hole] = fieldCol
}
func SetTeamCol(teamName string) {
	db, session := mongoConn()
	col := db.C("team")
	defer session.Close()

	teamCol := TeamCol{}
	findQuery := bson.M{"name": teamName}

	if err = col.Find(findQuery).One(&teamCol); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_FindCol, findQuery)
	}

	teams[teamName] = teamCol
}
func RegisterUserColData(userCols []UserCol) (*Status, error) {
	l.PutInfo(l.I_M_RegisterCol, userCols, nil)

	defer SetAllUserCol()

	db, session := mongoConn()
	col := db.C("user")
	defer session.Close()

	var createCnt, updateCnt int

	for _, userCol := range userCols {
		if len(userCol.Name) == 0 {
			l.PutErr(nil, l.Trace(), l.E_Nil, userCol.Name)
			return &Status{"this user do not have name"}, nil
		}
		if len(userCol.UserId) == 0 {
			userCol.UserId = make20lengthHashString()
		}
		if len(userCol.CreatedAt) == 0 {
			userCol.CreatedAt = time.Now().Format(c.DatetimeFormat)
		}
		findQuery := bson.M{"userid": userCol.UserId}
		change, err := col.Upsert(findQuery, userCol)
		if err != nil {
			l.PutErr(err, l.Trace(), l.E_M_Upsert, userCol.UserId)
			return &Status{"can not upsert"}, err
		}
		if change.Updated == 0 {
			createCnt += 1
		} else {
			updateCnt += 1
		}
	}

	return &Status{"success"}, nil
}
Beispiel #24
0
func (player TMainPlayer) Search(ban *TBan, ms int) (string, int) {
	logger := GetLogger()
	teban := *(ban.Teban)
	logger.Trace("[MainPlayer] ban.Tesuu: " + s(*(ban.Tesuu)) + ", teban: " + s(teban))

	all_moves := MakeAllMoves(ban)

	moves_count := len(all_moves)
	logger.Trace("[MainPlayer] moves: " + s(moves_count))
	if moves_count == 0 {
		return "resign", 0
	}

	joseki_move := player.GetJosekiMove(ban, &all_moves)
	if joseki_move != nil {
		return joseki_move.GetUSIMoveString(), 0
	}

	// magic number
	width := 999
	depth := 4
	if ms < 300000 {
		depth = 3
	}
	if ms < 120000 {
		depth = 2
	}
	if ms < 60000 {
		// magic number
		depth = 0
	}

	move, score := player.GetMainBestMove(ban, &all_moves, width, depth, true)

	return move.GetUSIMoveString(), score
}
Beispiel #25
0
func (ban TBan) FindMochiKoma(teban TTeban, kind TKind) *TKoma {
	teban_koma_map := ban.GetTebanKoma(teban)
	var found *TKoma = nil
	for _, koma := range *teban_koma_map {
		if koma.Kind == kind && koma.Position == Mochigoma {
			found = koma
			break
		}
	}
	if found == nil {
		logger := GetLogger()
		logger.Trace("ERROR!! koma to drop is not found.")
	}
	return found
}
func PostScoreViewSheetPageData(teamName string, definedTeam *PostDefinedTeam) (*Status, error) {
	l.PutInfo(l.I_M_PostPage, teamName, definedTeam)

	//更新情報をGlobal変数に格納する
	defer SetTeamCol(teamName)

	findQuery := bson.M{"name": teamName}
	setQuery := bson.M{"$set": bson.M{"defined": true}}
	if err = UpdateMongoData("team", findQuery, setQuery); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_Update, teamName)
		return &Status{"failed"}, err
	}

	return &Status{"success"}, nil
}
func UpdateMongoData(collection string, findQuery bson.M, updateQuery bson.M) error {

	db, session := mongoConn()
	c := db.C(collection)
	defer session.Close()

	if err = c.Update(findQuery, updateQuery); err != nil {
		l.PutErr(err, l.Trace(), l.E_M_Update,
			map[string]bson.M{
				"findQuery":   findQuery,
				"updateQuery": updateQuery,
			},
		)
		return err
	}
	return nil
}
func SetPlayerCol(userIds []string) {
	db, session := mongoConn()
	col := db.C("player")
	defer session.Close()

	for _, userId := range userIds {

		playerCol := PlayerCol{}
		findQuery := bson.M{"userid": userId}

		if err = col.Find(findQuery).One(&playerCol); err != nil {
			l.PutErr(err, l.Trace(), l.E_M_FindCol, findQuery)
		}

		players[userId] = playerCol
	}
}
Beispiel #29
0
func (player TMainPlayer) GetMainBestMove(ban *TBan, all_moves *map[int]*TMove, width int, depth int, is_disp bool) (*TMove, int) {
	logger := GetLogger()
	teban := *(ban.Teban)
	current_sfen := ban.ToSFEN(false)
	score_channel := player.GetScore(current_sfen, teban, all_moves, is_disp)

	oute_map := make(map[int]int)
	better_moves_map := make(map[int]int)

	if depth == 0 {
		// 緊急避難ロジック
		return (*all_moves)[0], 28
	}

	if width == 999 {
		width = len(*all_moves) / 2
	}
	if width > 32 {
		width = 32
	}
	if width == 0 {
		width = 1
	}

	// logger.Trace("------start------")
	// ゴルーチンの結果待ち
	for i := 0; i < len(*all_moves); i++ {
		result := <-score_channel
		// "key_of_all_moves:score:Oute(if oute)"
		result_arr := strings.Split(result, ":")
		key, _ := strconv.Atoi(result_arr[0])
		score, _ := strconv.Atoi(result_arr[1])
		sfen := result_arr[2]
		player.Cache[sfen] = score
		if len(result_arr) == 4 {
			// 王手フラグあり。候補手とする
			oute_map[key] = score
		} else {
			// 上位width件だけ候補手とする
			PutToMap(&better_moves_map, key, score, width)
		}
	}

	// 王手を候補手に追加
	for k, s := range oute_map {
		better_moves_map[k] = s
	}

	// /2にして幅を広くしても、時間を浪費して自滅する。
	next_width := width / 4
	// 最低幅を4にすると、重すぎ。2でどうか?2でも重い。
	if next_width < 1 {
		next_width = 1
	}
	next_depth := depth - 1

	current_move_key := 0
	current_score := 0
	if depth >= 2 {
		// depthが2以上なら、絞り込んだ結果を元に、相手の手番でdepth-1手先まで読む。
		current_min := 99999
		// logger.Trace("depth: " + s(depth))
		// logger.Trace("moves: " + s(len(better_moves_map)))
		for key, score := range better_moves_map {
			new_ban := FromSFEN(current_sfen)
			move := (*all_moves)[key]
			move_string := move.GetUSIMoveString()
			need_sente_move := true
			need_gote_move := true
			if teban {
				// need_gote_move = true
			} else {
				// need_sente_move = false
			}
			new_ban.ApplyMove(move_string, true, need_sente_move, need_gote_move)
			// ここのApplyMove後では、相手側の手だけあれば。
			// 王手なら、利きも必要になる。ただ、現在王手かどうかの判定に利きを使っているので、現状は利きと相手側の手だけで。
			next_moves := MakeAllMoves(new_ban)
			if len(next_moves) == 0 {
				// 手がないので詰み。下のは読んだ先で詰みがある場合?
				current_move_key = key
				current_score = 99999
				logger.Trace("[BestMove3] tsumi: " + move_string)
				break
			}
			next_best_move, count := player.GetMainBestMove(new_ban, &next_moves, next_width, next_depth, false)
			if next_best_move == nil {
				// 手がないのはつまり詰み。
				current_move_key = key
				current_score = -99999
				logger.Trace("[BestMove3] tsumi: " + move_string)
				break
			}
			next_best_move_string := next_best_move.GetUSIMoveString()
			if is_disp {
				Resp("info time 0 depth 1 nodes 1 score cp "+ToDisplayScore(count, teban)+" pv "+move_string+" "+next_best_move_string, logger)
			}
			if current_min > count {
				current_min = count
				current_move_key = key
				current_score = score
			} else {
				if current_min == count {
					if current_score < score {
						current_move_key = key
						current_score = score
					}
				}
			}
		}
	} else {
		// depthが1なら、上位width件の中で最高の評価値の手を返す
		max := -99999
		for key, score := range better_moves_map {
			if score > max {
				max = score
				current_move_key = key
				current_score = score
			}
		}
	}
	// logger.Trace("[BestMove3] score: " + s(current_score))
	selected_move := (*all_moves)[current_move_key]
	// logger.Trace("------ end ------")
	return selected_move, current_score
}
Beispiel #30
0
func main() {
	// 独自のLoggerを使用
	InitLogger()
	logger := GetLogger()
	defer logger.Close()

	// master ban
	var master *TBan
	var tesuu int = 0
	//player := NewPlayer("Slide")
	//player := NewPlayer("Random")
	player := NewPlayer("Main")

	// 将棋所とのやりとり
	// TODO:いつでも返答すべきコマンドは常時listenするイメージで。GoRoutineとChannelを使えばよさげ
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		text := scanner.Text()
		logger.Req(text)
		switch text {
		// エンジン登録時は、usiとquitのみ入力される。
		case "usi":
			respUSI(logger)
		case "quit":
			// TODO 終了前処理
			os.Exit(0)
		case "setoption name USI_Ponder value true":
			// TODO 設定を保存する
		case "setoption name USI_Hash value 256":
			// TODO 設定を保存する
		case "isready":
			master = CreateInitialState()
			tesuu = 0
			Resp("readyok", logger)
		case "usinewgame":
			// TODO: モードを切り替えるべきか。
		case "gameover":
			// TODO: 対局待ち状態に戻る。
		default:
			if s.HasPrefix(text, "position") {
				logger.Trace(text)
				split_text := s.Split(text, " ")
				// 通常の対局
				// position startpos moves 7g7f 8b7b 2g2f
				is_sfen := false
				if split_text[1] == "sfen" {
					is_sfen = true
					// 局面編集からの検討だとこのように
					// position sfen lnsgkgsnl/1r5b1/1pppppppp/p8/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1 moves 2g2f
					sfen_index := s.Index(text, "sfen")
					moves_index := s.Index(text, "moves")
					var sfen_str string
					if moves_index == -1 {
						sfen_str = text[sfen_index:]
					} else {
						sfen_str = text[sfen_index : moves_index-1]
					}
					master = FromSFEN(sfen_str)
				}
				if is_sfen {
					// こちらのルートはどうすればいいのか不明。デッドコピーとしておく。
					for index, value := range split_text {
						if index < 7 {
							continue
						}
						// 何度も一手ずつ反映する必要はないので、スキップしている。
						if index-7 < tesuu {
							continue
						}
						logger.Trace("to apply: " + value)
						master.ApplyMove(value, true, true, true)
						logger.Trace(master.Display())
						tesuu++
					}
					// resp("info string "+text, logger)
				} else {
					for index, value := range split_text {
						if index < 3 {
							continue
						}
						// 何度も一手ずつ反映する必要はないので、スキップしている。
						if index-3 < tesuu {
							continue
						}
						logger.Trace("to apply: " + value)
						master.ApplyMove(value, true, true, true)
						logger.Trace(master.Display())
						logger.Trace(master.ToSFEN(true))
						tesuu++
					}
				}
			} else if s.HasPrefix(text, "go") {
				split_text := s.Split(text, " ")
				btime := split_text[2]
				wtime := split_text[4]
				teban := *(master.Teban)
				var ms int = 0
				if teban {
					ms, _ = strconv.Atoi(btime)
				} else {
					ms, _ = strconv.Atoi(wtime)
				}
				bestmove, score := player.Search(master, ms)
				if len(bestmove) < 6 {
					master.ApplyMove(bestmove, true, true, true)
					logger.Trace(master.Display())
					logger.Trace(master.ToSFEN(true))
					tesuu++
				}
				Resp(("info time 0 depth 1 nodes 1 score cp " + ToDisplayScore(score, teban) + " pv " + bestmove), logger)
				bestmove_str := "bestmove " + bestmove
				Resp(bestmove_str, logger)
			}
		}
	}
}