Created
May 29, 2014 05:08
-
-
Save Rican7/fba6c1ee2d9fa8bd1354 to your computer and use it in GitHub Desktop.
This is an "Object Oriented" rewrite of my already rewritten Go(lang) battleship game. I wanted to see how the OOP design worked in Go. Its different. Original, more functional approach: https://gist.github.com/Rican7/fac67bb68672be09678e
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"math/rand" | |
"strings" | |
"time" | |
) | |
/** | |
* Types | |
*/ | |
// A location on the board | |
type Point struct { | |
X, Y int | |
} | |
// A mark on the board, represented by a location with a representation | |
type Mark struct { | |
Point | |
checked bool | |
representation string | |
} | |
// The game board | |
type Board struct { | |
spots [][]Mark | |
} | |
// The game | |
type Game struct { | |
board Board | |
turns int | |
enemy Point | |
} | |
/** | |
* Type Functions | |
*/ | |
// Create a new Mark | |
func NewMark(location Point, checked bool) *Mark { | |
mark := Mark{location, false, ""} | |
mark.SetChecked(checked) | |
return &mark | |
} | |
// Get the string representation of a mark | |
func (m Mark) Representation() string { | |
return m.representation | |
} | |
// Set the string representation of a mark | |
func (m *Mark) SetRepresentation(rep string) { | |
m.representation = strings.ToUpper(rep[:len(rep)-1]) | |
} | |
// Check if the mark has been "checked" as used | |
func (m Mark) Checked() bool { | |
return m.checked | |
} | |
// Set the mark's "checked" status | |
func (m *Mark) SetChecked(checked bool) { | |
m.checked = checked | |
if checked { | |
m.representation = "X" | |
} else { | |
m.representation = "O" | |
} | |
} | |
// Get a mark as a string | |
func (m Mark) String() string { | |
return m.representation | |
} | |
// Create a new board | |
func NewBoard(rows, columns int) *Board { | |
// Set a default size | |
if rows <= 0 || columns <= 0 { | |
return nil | |
} | |
board := Board{make([][]Mark, rows)} | |
// Fill the board with default marks | |
for i := 0; i < rows; i++ { | |
board.spots[i] = make([]Mark, columns) | |
for idx := range board.spots[i] { | |
board.spots[i][idx] = *NewMark(Point{(i + 1), (idx + 1)}, false) | |
} | |
} | |
return &board | |
} | |
// Get the number of rows on the board | |
func (b Board) GetRowCount() int { | |
return len(b.spots) | |
} | |
// Get the number of columns on the board | |
func (b Board) GetColumnCount() int { | |
return len(b.spots[0]) | |
} | |
// Get a mark on the board by a Point location | |
func (b Board) GetMarkByLocation(location Point) *Mark { | |
return &b.spots[location.Y][location.X] | |
} | |
// Check if a given location is within the bounds of the board | |
func (b Board) IsLocationWithinBounds(location Point) bool { | |
if (location.X < 0 || location.X > (b.GetColumnCount()-1)) || | |
(location.Y < 0 || location.Y > (b.GetRowCount()-1)) { | |
return false | |
} | |
return true | |
} | |
// Generate a random location that fits on the board | |
func (b Board) GenerateRandomLocation() *Point { | |
maxRowIndex := (b.GetRowCount() - 1) | |
maxColumnIndex := (b.GetColumnCount() - 1) | |
r := rand.New(rand.NewSource(time.Now().UnixNano())) | |
return &Point{X: r.Intn(maxColumnIndex), Y: r.Intn(maxRowIndex)} | |
} | |
// Get a board as a string | |
func (b Board) String() string { | |
var buffer bytes.Buffer | |
for i := 0; i < b.GetRowCount(); i++ { | |
for j := 0; j < b.GetColumnCount(); j++ { | |
mark := b.GetMarkByLocation(Point{j, i}) | |
buffer.WriteString(mark.String()) | |
buffer.WriteString(" ") | |
} | |
buffer.WriteString("\r\n") | |
} | |
return buffer.String() | |
} | |
// Create a new Game | |
// Pass a "nil" enemy to generate one randomly | |
func NewGame(board Board, turns int, enemy *Point) *Game { | |
// Generate a default enemy if nil passed | |
if nil == enemy { | |
enemy = board.GenerateRandomLocation() | |
} | |
return &Game{board: board, turns: turns, enemy: *enemy} | |
} | |
// Get the game's board | |
func (g Game) Board() Board { | |
return g.board | |
} | |
// Get the number of turns in the game | |
func (g Game) Turns() int { | |
return g.turns | |
} | |
// Get the enemy location | |
func (g Game) GetEnemyLocation() Point { | |
return g.enemy | |
} | |
// Check if a guessed location is the location of the enemy | |
func (g Game) checkGuess(guess Point) bool { | |
if g.GetEnemyLocation() == guess { | |
fmt.Println("Congratulations! You sunk my battleship!") | |
return true | |
} else { | |
if !g.Board().IsLocationWithinBounds(guess) { | |
fmt.Println("Oops, that's not even in the ocean.") | |
} else if g.Board().GetMarkByLocation(guess).Checked() { | |
fmt.Println("You guessed that one already.") | |
} else { | |
fmt.Println("You missed my battleship!") | |
g.Board().GetMarkByLocation(guess).SetChecked(true) | |
} | |
} | |
fmt.Println() | |
return false | |
} | |
// Play the game! | |
func (g Game) Play() bool { | |
won := false | |
for turn := 0; turn < g.Turns(); turn++ { | |
fmt.Println(g.Board()) | |
guess := GetGuessPoint() | |
won = g.checkGuess(*guess) | |
if won { | |
break | |
} | |
fmt.Println("Finished turn", (turn + 1)) | |
} | |
return won | |
} | |
// Get the user's guess | |
func GetGuessPoint() *Point { | |
var x, y int | |
// Get our guess | |
fmt.Println("Guess the row: ") | |
fmt.Scanf("%d", &y) | |
fmt.Println("Guess the column: ") | |
fmt.Scanf("%d", &x) | |
fmt.Println() | |
return &Point{X: x, Y: y} | |
} | |
/** | |
* Program Entrance | |
*/ | |
func main() { | |
// Intro | |
fmt.Println("Let's play Battleship!") | |
fmt.Println() | |
// Construct our game | |
board := NewBoard(5, 5) | |
game := NewGame(*board, 5, nil) | |
// Play!! | |
won := game.Play() | |
if won { | |
fmt.Println("Woot!") | |
} else { | |
fmt.Println("Sorry... Game over") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment