Example #1
0
// Creates a new game, but does not start it.
func newGame() *Game {
	id := generateId()

	util.LogInfo("Creating a new game with id: %s.", id)
	game := Game{}

	game.Id = id
	fields := make([][]*Field, conf.BoardSize)
	for i := range fields {
		fields[i] = make([]*Field, conf.BoardSize)
	}
	game.Board = &Board{Fields: fields}
	game.isStarted = false

	// init channels
	game.playerJoinedCh = make(chan int)

	board := game.Board
	for i, row := range board.Fields {
		for j, _ := range row {
			board.Fields[i][j] = new(Field)
		}
	}

	return &game
}
Example #2
0
// Adds a player to the registry.
func (player *Player) Join(game *Game) error {
	util.LogInfo("New player (with name: %s) attempts to join the game.", player.Name)
	if game.hasAlreadyJoined(player) {
		return util.Errorf("Player with name %s has already joined the game.", player.Name)
	}

	err := game.Board.placeShips(game.Players, player)
	if err != nil {
		return err
	}

	game.addPlayer(player)

	util.LogInfo("Player with name %s (id: %s) has joined the game.", player.Name, player.Id)
	return nil
}
Example #3
0
// Places the appropriate number of ships on the board randomly. The number of
// ships is based on the current average score for the players in the game.
func (board *Board) placeShips(allPlayers []*Player, player *Player) error {
	scores := make([]float64, len(allPlayers))
	for idx, p := range allPlayers {
		scores[idx] = p.getCurrentScore()
	}

	avg := average(scores)
	util.LogInfo("average board score is %f", avg)
	if len(allPlayers) == 0 {
		avg = BASE_SCORE
	}

	deployment := computeShipDeployment(avg)
	util.LogInfo("Deployment for %s player: %v", player.Name, deployment)
	return board.deployShips(player, deployment)
}
Example #4
0
// Starts a new turn for a player. Block while the player's turn ends.
func (g *Game) doTurn(player *Player) {
	util.LogInfo("%s started her turn.", player.Name)

	// set current player
	g.CurrentPlayerId = player.Id

	// when the player is a bot, just shoot and end the turn
	if player.IsBot {
		if g.isAllBot() && conf.WaitForBots {
			time.Sleep(time.Second * time.Duration(conf.BotTurnDurationSec))
		}
		g.shootForAI()
	} else {
		// human player have time to react
		g.endTurn = make(chan int)
		go g.measureTurnTime()

		<-g.endTurn
	}
	util.LogInfo("%s finished her turn.", player.Name)
}
Example #5
0
// main loop for the program, starts new game when needed
func mainLoop() {
	endGame := make(chan int)

	for {
		currentGame = engine.NewGame(endGame)
		currentGame.Start()

		<-endGame
		History = append(History, currentGame)
		util.LogInfo("Game ended with id: %s.", currentGame.Id)
	}
}
Example #6
0
func (g *Game) shootForAI() {
	row, col := rand.Intn(conf.BoardSize), rand.Intn(conf.BoardSize)
	result, _ := g.Board.shootAt(row, col, nil)

	for result == INVALID {
		row, col = rand.Intn(conf.BoardSize), rand.Intn(conf.BoardSize)
		result, _ = g.Board.shootAt(row, col, nil)
	}

	g.notifyViewsAfterShot(row, col, result)

	util.LogInfo("Bot player shot at %s and the result is: %s", RowColToS(row, col), result)
}
Example #7
0
func (g *Game) step() {
	// wait for enough players to start
	for {
		numberOfPlayers := <-g.playerJoinedCh
		if numberOfPlayers > conf.MinimalPlayerCnt-1 {
			g.isStarted = true
			break
		}
	}

	// notify views that the game started
	for _, reporter := range g.views {
		reporter.ReportGameStarted()
	}

	// we have enough players so start the first player's turn
	g.reportTurnStart(g.Players[0], g.Players[1])
	g.doTurn(g.Players[0])

	// game event loop
	for {
		// check if we have a winner
		// when we do, break the game loop
		if result, winner := g.hasWinner(); result {
			g.Winner = winner
			util.LogInfo("The winner is: %s", winner.Name)
			break
		}

		prevPlayerId := g.CurrentPlayerId
		player, err := g.getNextPlayer(prevPlayerId)
		if err != nil {
			util.LogError("No player found for id %v", prevPlayerId)
			continue
		}

		// report new turn for player
		nextPlayer, _ := g.getNextPlayer(player.Id)
		g.reportTurnStart(player, nextPlayer)

		g.doTurn(player)
	}

	// notify views
	for _, reporter := range g.views {
		reporter.ReportGameOver(g.Winner)
	}
	g.endCh <- 1 // signal the main loop
	g.cleanUp()
}
Example #8
0
// shoot handler
func shootHandler(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie(PLAYER_ID_COOKIE)

	// the play might not be registered
	if err != nil {
		// TODO: error handling
		fmt.Fprint(w, "Join the game first!")
		return
	}

	var shootResult ShootResult
	shootResult.Game = currentGame
	shootResult.Player = currentGame.GetPlayerById(cookie.Value)

	if shootResult.Player == nil {
		fmt.Fprint(w, "No player registered with the given id. Go to home page and register.")
		return
	}

	if r.Method == "POST" {
		// check if the player is up
		if currentGame.CurrentPlayerId != cookie.Value {
			// -1 : it's not your turn
			fmt.Fprint(w, "-1")
			return
		}

		colS := r.FormValue("col")
		rowS := r.FormValue("row")

		row, err := strconv.Atoi(rowS)
		if renderParseError(w, err) {
			return
		}
		// 0 based indexing
		row -= 1

		if len(colS) == 0 && renderParseError(w, errors.New("Column should be [A-Z]")) {
			return
		}
		col := int(colS[0] - 'A')

		shootResult.Feedback = currentGame.Shoot(row, col)
		util.LogInfo("Player shot at (%s) with result: %s", engine.RowColToS(row, col), shootResult.Feedback)
		fmt.Fprint(w, shootResult.Feedback)
		return
	}

	renderTemplate(w, SHOOT_TEMPLATE, shootResult)
}
Example #9
0
// Makes the player quit the game, sets the player to be a bot for the rest of
// the game. There is no re-entry option.
func quitHandler(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie(PLAYER_ID_COOKIE)
	if err != nil {
		http.Redirect(w, r, "/", http.StatusFound)
		return
	}

	for _, player := range currentGame.Players {
		// if player exists, set it to be a bot
		if player.Id == cookie.Value {
			player.IsBot = true
			break
		}
	}
	// delete the cookie
	cookie.MaxAge = -1
	http.SetCookie(w, cookie)
	http.Redirect(w, r, "/", http.StatusFound)
	util.LogInfo("Player with %s id left the game.", cookie.Value)
}