capim_tictactoe 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/capim_tictactoe/ascii_art.rb +23 -0
- data/lib/capim_tictactoe/board.rb +42 -0
- data/lib/capim_tictactoe/color.rb +21 -0
- data/lib/capim_tictactoe/evaluator.rb +37 -0
- data/lib/capim_tictactoe/game.rb +33 -0
- data/lib/capim_tictactoe/grid.rb +45 -0
- data/lib/capim_tictactoe/input_handler.rb +40 -0
- data/lib/capim_tictactoe/presenter.rb +16 -0
- data/lib/capim_tictactoe/silly_line.rb +25 -0
- data/lib/capim_tictactoe.rb +7 -0
- metadata +11 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e03634fb0b4ef193da5af352b234f8dc1e263a48170a120a8d43b82956b2dc2d
|
4
|
+
data.tar.gz: 1e8b561474920f1b02773ba2e4848743359fa3ca52f2aa9a611ff5f6cddf4434
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10caab0ca5d16acca5e10b0dbb84669e417806cdc94259880addd35731137d59d7de0ee54d7465f5d7bb5d7f665b4d25378efedcd90bf867409d902b624ab87f
|
7
|
+
data.tar.gz: b01115d9c8d2a052ba0a4de82b5fc43ca7b69452952ac905d1a4306f109c1a12b2bcc7111634d467a8da14d12dabd0a7323aae204a7cb83e575c1d7b8cf3d198
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AsciiArt
|
4
|
+
require 'rainbow'
|
5
|
+
|
6
|
+
GRASS = '⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
7
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
8
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
9
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
10
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
11
|
+
⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
12
|
+
⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
13
|
+
⠀⠀⢠⡇⠀⠀⡆⠀⠀⠀⠀⠀⢀⠀⠀⣼⣿⠀⠀⠀⢰⠀⠀⠀⢀⡇⠀⠀⠀⠀
|
14
|
+
⠀⠀⢸⡇⠀⠀⣷⠀⠀⢠⠀⠀⣸⡀⠀⣿⣿⠀⠀⠀⣼⡇⠀⠀⣼⠀⠀⢠⡆⠀
|
15
|
+
⠀⠀⣼⡇⠀⠀⣿⡆⠀⣾⠀⠀⣿⡇⢀⣿⣿⠀⠀⠀⣿⣿⠀⢀⣿⡇⠀⢸⡇⠀
|
16
|
+
⠀⠀⣿⣇⠀⢠⣿⣧⢀⣿⠀⢰⣿⡇⢸⣿⣿⡇⠀⢠⣿⣿⡆⢸⣿⡇⠀⣿⣷⠀
|
17
|
+
⠀⢀⣿⣿⠀⢸⣿⣿⢸⣿⡄⣼⣿⣷⢸⣿⣿⣿⣀⣾⣿⣿⡇⣿⣿⣷⢰⣿⣿⠀
|
18
|
+
⠀⢸⣿⣿⡇⢸⣿⣿⣾⣿⣿⣿⣿⣿⣼⣿⣿⣿⣿⣿⣿⣿⣇⣿⣿⣿⣿⣿⣿⠀
|
19
|
+
⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
|
20
|
+
⠀⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠀'
|
21
|
+
|
22
|
+
GREEN_GRASS = Rainbow(GRASS).green
|
23
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Board
|
4
|
+
require_relative 'color'
|
5
|
+
require_relative 'grid'
|
6
|
+
|
7
|
+
include Color
|
8
|
+
|
9
|
+
attr_reader :spots, :grid
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@spots = %w[0 1 2 3 4 5 6 7 8]
|
13
|
+
@grid = Grid.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid_line?(set)
|
17
|
+
set.each do |line|
|
18
|
+
return true if line.uniq.length == 1
|
19
|
+
end
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def center_marked?
|
24
|
+
@grid.get_at(4) != '4'
|
25
|
+
end
|
26
|
+
|
27
|
+
def mark_center(marker)
|
28
|
+
@grid.spot_marker(4, marker)
|
29
|
+
end
|
30
|
+
|
31
|
+
def available_spots
|
32
|
+
@grid.spots.select { |spot| %(0 1 2 3 4 5 6 7 8).include?(spot) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def game_over?(spots = @grid.spots)
|
36
|
+
valid_line?(@grid.rows(spots)) || valid_line?(@grid.columns(spots)) || valid_line?(@grid.diagonals)
|
37
|
+
end
|
38
|
+
|
39
|
+
def tie?
|
40
|
+
@grid.spots.all? { |spot| [x_marker, o_marker].include?(spot) }
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Color
|
4
|
+
require 'rainbow'
|
5
|
+
|
6
|
+
def pipe
|
7
|
+
Rainbow(' | ').red.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def line
|
11
|
+
Rainbow("\n---+---+---\n").red.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def x_marker
|
15
|
+
Rainbow('X').green
|
16
|
+
end
|
17
|
+
|
18
|
+
def o_marker
|
19
|
+
Rainbow('O').blue
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Evaluator
|
4
|
+
def eval_board(board, human_marker, computer_marker)
|
5
|
+
unless board.center_marked?
|
6
|
+
board.mark_center(computer_marker)
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
spot = get_best_move(board, human_marker, computer_marker)
|
11
|
+
spot = board.grid.marked?(spot) ? nil : board.grid.spot_marker(spot, computer_marker)
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_best_move(board, human_marker, computer_marker)
|
15
|
+
best_move = nil
|
16
|
+
|
17
|
+
board.available_spots.each do |available_spot|
|
18
|
+
if winning_move?(board, computer_marker, available_spot.to_i)
|
19
|
+
best_move = available_spot.to_i
|
20
|
+
return best_move
|
21
|
+
end
|
22
|
+
|
23
|
+
best_move = available_spot.to_i if winning_move?(board, human_marker, available_spot.to_i)
|
24
|
+
end
|
25
|
+
return best_move if best_move
|
26
|
+
|
27
|
+
board.available_spots.sample.to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
def winning_move?(board, marker, spot)
|
31
|
+
# A tmp board is used to avoid mutating the board instance variable spots.
|
32
|
+
tmp_board = board.grid.spots.dup
|
33
|
+
tmp_board[spot] = marker
|
34
|
+
|
35
|
+
board.game_over?(tmp_board)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Game
|
4
|
+
require_relative 'board'
|
5
|
+
require_relative 'evaluator'
|
6
|
+
require_relative 'color'
|
7
|
+
require_relative 'presenter'
|
8
|
+
require_relative 'input_handler'
|
9
|
+
|
10
|
+
include Color
|
11
|
+
include Evaluator
|
12
|
+
include Presenter
|
13
|
+
include InputHandler
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@board = Board.new
|
17
|
+
@computer = x_marker
|
18
|
+
@human = o_marker
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_game
|
22
|
+
present_game
|
23
|
+
|
24
|
+
until @board.game_over? || @board.tie?
|
25
|
+
fetch_human_spot(@board, @human)
|
26
|
+
|
27
|
+
eval_board(@board, @human, @computer) unless @board.game_over? || @board.tie?
|
28
|
+
@board.grid.display
|
29
|
+
end
|
30
|
+
|
31
|
+
puts 'Game over'
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Grid
|
4
|
+
require_relative 'color'
|
5
|
+
|
6
|
+
include Color
|
7
|
+
|
8
|
+
attr_reader :grid
|
9
|
+
alias spots grid
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@grid = %w[0 1 2 3 4 5 6 7 8]
|
13
|
+
end
|
14
|
+
|
15
|
+
def display
|
16
|
+
rows.each do |row|
|
17
|
+
print " #{row.join(pipe)} "
|
18
|
+
print line
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_at(index)
|
23
|
+
@grid[index]
|
24
|
+
end
|
25
|
+
|
26
|
+
def rows(spots = grid)
|
27
|
+
spots.each_slice(3)
|
28
|
+
end
|
29
|
+
|
30
|
+
def columns(spots)
|
31
|
+
rows(spots).to_a.transpose
|
32
|
+
end
|
33
|
+
|
34
|
+
def diagonals
|
35
|
+
[[@grid[0], @grid[4], @grid[8]], [@grid[2], @grid[4], @grid[6]]]
|
36
|
+
end
|
37
|
+
|
38
|
+
def spot_marker(spot, marker)
|
39
|
+
@grid[spot] = marker
|
40
|
+
end
|
41
|
+
|
42
|
+
def marked?(spot)
|
43
|
+
[x_marker, o_marker].include?(@grid[spot])
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module InputHandler
|
4
|
+
def fetch_human_spot(board, human_marker)
|
5
|
+
spot = nil
|
6
|
+
loop do
|
7
|
+
spot = gets.chomp
|
8
|
+
|
9
|
+
spot = validate_input(board, spot)
|
10
|
+
break if spot
|
11
|
+
|
12
|
+
puts "Please enter a valid integer that corresponds to an empty spot (#{board.available_spots.join(', ')})"
|
13
|
+
end
|
14
|
+
board.grid.spot_marker(spot, human_marker)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# to_i converts 'non integer' strings to 0: 'a'.to_i => 0.
|
20
|
+
# this method is used to verify if the input is conversible to integer
|
21
|
+
def integer?(input)
|
22
|
+
input.to_i.to_s == input
|
23
|
+
end
|
24
|
+
|
25
|
+
def within_range?(spot)
|
26
|
+
spot.between?(0, 8)
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate_input(board, input)
|
30
|
+
return false unless integer?(input)
|
31
|
+
|
32
|
+
spot = input.to_i
|
33
|
+
|
34
|
+
return false unless within_range?(spot)
|
35
|
+
|
36
|
+
return false if board.grid.marked?(spot)
|
37
|
+
|
38
|
+
spot
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Presenter
|
4
|
+
require_relative 'silly_line'
|
5
|
+
require_relative 'ascii_art'
|
6
|
+
|
7
|
+
SILLY_LINE = SillyLine::LINES.sample
|
8
|
+
GREEN_GRASS = AsciiArt::GREEN_GRASS
|
9
|
+
|
10
|
+
def present_game
|
11
|
+
print GREEN_GRASS
|
12
|
+
puts "\n#{SILLY_LINE}\n\n"
|
13
|
+
@board.grid.display
|
14
|
+
puts 'Enter [0-8]'
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# All lines were generated using ChatGPT. Although some of them don't make much sense, I like the quirkiness of it.
|
4
|
+
module SillyLine
|
5
|
+
LINES = ['Get ready to go toe-to-toe (or X-to-O) with your opponent in a battle of sheer ingenuity and grass-roots strategy.',
|
6
|
+
"It's time for the ultimate showdown of X's and O's! Who will come out on top and reign supreme on the grassy battlefield?",
|
7
|
+
"Brace yourself for a thrilling game of Tic Tac Toe, where the grass is always greener on the winning side (unless you're playing as O, of course).",
|
8
|
+
'Are you ready to test your Tic Tac Toe skills and see if you have what it takes to conquer the grassy plains of victory?',
|
9
|
+
"Welcome to the ultimate showdown of X's and O's, where the grass is always greener on the winning side (unless it's being trampled by a triumphant O, of course).",
|
10
|
+
'Get ready to engage in a battle of wits and strategy as you go head-to-head with your opponent in a game of Tic Tac Toe.',
|
11
|
+
"It's time to put your Tic Tac Toe skills to the test and see if you have what it takes to emerge victorious on the grassy battlefield.",
|
12
|
+
'Are you ready to put your strategic thinking to the test and see if you have what it takes to come out on top in a game of Tic Tac Toe?',
|
13
|
+
"Welcome to the ultimate showdown of X's and O's, where the grass is always greener on the winning side (unless it's being trampled by a triumphant O, of course).",
|
14
|
+
"Get ready to flex your strategic muscles and go head-to-head with your opponent in a battle of wits and X's and O's.",
|
15
|
+
"It's Tic Tac Toe time! Gather 'round, folks, and watch as X and O duke it out on the virtual grassy battlefield.",
|
16
|
+
'Step right up and test your Tic Tac Toe skills against the best of the best. The Capim grass is always greener on the winning side.',
|
17
|
+
"Welcome to the ultimate showdown of X's and O's, where the grass is always greener on the winning side (unless it's being trampled by a triumphant O, of course).",
|
18
|
+
'Get ready to engage in a battle of wits and strategy as you go head-to-head with your opponent in a game of Tic Tac Toe.',
|
19
|
+
"It's time to put your Tic Tac Toe skills to the test and see if you have what it takes to emerge victorious on the grassy battlefield.",
|
20
|
+
'Are you ready to put your strategic thinking to the test and see if you have what it takes to come out on top in a game of Tic Tac Toe?',
|
21
|
+
"Welcome to the ultimate showdown of X's and O's, where the grass is always greener on the winning side (unless it's being trampled by a triumphant O, of course).",
|
22
|
+
"Get ready to flex your strategic muscles and go head-to-head with your opponent in a battle of wits and X's and O's.",
|
23
|
+
"It's Tic Tac Toe time! Gather 'round, folks, and watch as X and O duke it out on the virtual grassy battlefield.",
|
24
|
+
'Step right up and test your Tic Tac Toe skills against the best of the best. The Capim grass is always greener'].freeze
|
25
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capim_tictactoe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gustavo Maia
|
@@ -61,6 +61,16 @@ extensions: []
|
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
63
|
- bin/capim_tictactoe
|
64
|
+
- lib/capim_tictactoe.rb
|
65
|
+
- lib/capim_tictactoe/ascii_art.rb
|
66
|
+
- lib/capim_tictactoe/board.rb
|
67
|
+
- lib/capim_tictactoe/color.rb
|
68
|
+
- lib/capim_tictactoe/evaluator.rb
|
69
|
+
- lib/capim_tictactoe/game.rb
|
70
|
+
- lib/capim_tictactoe/grid.rb
|
71
|
+
- lib/capim_tictactoe/input_handler.rb
|
72
|
+
- lib/capim_tictactoe/presenter.rb
|
73
|
+
- lib/capim_tictactoe/silly_line.rb
|
64
74
|
homepage: https://github.com/itsmaia/blank
|
65
75
|
licenses:
|
66
76
|
- MIT
|