capim_tictactoe 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34d4e66814cd152649f3b7289f9e75bd2ecd8381a48b08279dd86bc567fda669
4
- data.tar.gz: 1c6ffc4e16e54880b7cb819cfa7195b3511a219543dac070ef56fffe076631e2
3
+ metadata.gz: af5438498606e56585414a109688fd4ed6da9766ab9fa3633d690ef632106065
4
+ data.tar.gz: 6c190f9b3a0e5a52f9185c1104fefca0509dc433d0ba085360e8897bc13a68c8
5
5
  SHA512:
6
- metadata.gz: 2e900ef997174b0622d08d4641a5be4f88c036d4f4169e96c36cdb91e8263c68d0d2ce7018cf2f34d7e547bc16d67a17afa137f4b3532d4c732cb47c19696cbd
7
- data.tar.gz: 9ed61a26db9e832cf5b27c7269154caf23c2c4b95c3e77b74e5a9e9e06694db5260932e43133df84327548bf2efd20b33293292a09d01188a94a132153f837bc
6
+ metadata.gz: 710cbad2dbef5e4e8192b2238f151a396b7659576176e92f2b47efcd78351b1f2371b8b9d0309e856d0dee01cbfe74aa54ad4ee8a2ab39f3c838856533a08e55
7
+ data.tar.gz: ce435feff0209a2fd670109793fefd8c75fd220e4c50e9f925b8e9766ae112e3ab9be6d6b7c404e63d02b59a2472eebd74cdac58ce1abbcbe784d1534de6d737
@@ -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
@@ -0,0 +1,7 @@
1
+ require_relative 'capim_tictactoe/game'
2
+
3
+ class Capimtictactoe
4
+ def self.start
5
+ Game.new.start_game
6
+ end
7
+ 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.1
4
+ version: 0.0.2
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