From a3236c8a066294da39ddc812077229c0f6fb2a2e Mon Sep 17 00:00:00 2001 From: Mick Killianey Date: Wed, 1 Jun 2022 16:22:14 -0700 Subject: [PATCH] Add Ruby port of 08_Batnum --- 08_Batnum/ruby/batnum.rb | 130 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100755 08_Batnum/ruby/batnum.rb diff --git a/08_Batnum/ruby/batnum.rb b/08_Batnum/ruby/batnum.rb new file mode 100755 index 00000000..a390e339 --- /dev/null +++ b/08_Batnum/ruby/batnum.rb @@ -0,0 +1,130 @@ +#!/usr/bin/env ruby + +def instructions + puts <<~EOF + THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE + COMPUTER IS YOUR OPPONENT. + + THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU + AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. + WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR + NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS. + DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME. + ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING. + EOF +end + +def ask_for_pile_size + loop do + puts "ENTER PILE SIZE:" + pile_size = gets.to_i + break pile_size if pile_size != 0 + end +end + +GOAL_TAKE_LAST = 1 +GOAL_AVOID_LAST = 2 +def ask_for_goal + loop do + puts "ENTER WIN OPTION - #{GOAL_TAKE_LAST} TO TAKE LAST, #{GOAL_AVOID_LAST} TO AVOID LAST:" + response = gets.to_i + break response if [GOAL_TAKE_LAST, GOAL_AVOID_LAST].member? response + end +end + +def ask_for_min_max_take + loop do + puts "ENTER MIN AND MAX, SEPARATED BY A COMMA:" + response = gets.split(',').map {|piece| piece.to_i} + next if response.length != 2 + min_take, max_take = response + break min_take, max_take if 0 < min_take && min_take <= max_take + end +end + +COMPUTER_MOVE = 1 +PLAYER_MOVE = 2 +def ask_who_makes_first_move + loop do + puts "ENTER START OPTION - #{COMPUTER_MOVE} COMPUTER FIRST, #{PLAYER_MOVE} YOU FIRST:" + response = gets.to_i + break response if [COMPUTER_MOVE, PLAYER_MOVE].member? response + end +end + +def ask_for_player_take(min_take:, max_take:) + loop do + puts "YOUR MOVE:" + response = gets.to_i + break response if response == 0 || response == response.clamp(min_take, max_take) + puts "ILLEGAL MOVE, REENTER IT." + end +end + +def battle(pile:, goal:, min_take:, max_take:, first_move:) + next_move = first_move + loop do + if next_move == COMPUTER_MOVE + next_move = PLAYER_MOVE + take = ( + if goal == GOAL_TAKE_LAST + pile % (min_take + max_take) + else + (pile - 1) % (min_take + max_take) + end + ).clamp(min_take, max_take) + pile = pile - take + if pile > 0 + puts "COMPUTER TAKES #{take} AND LEAVES #{pile}" + else + if goal == GOAL_TAKE_LAST + puts "COMPUTER TAKES #{take} AND WINS." + break + else + puts "COMPUTER TAKES #{take} AND LOSES." + break + end + end + else + next_move = COMPUTER_MOVE + take = ask_for_player_take(min_take: min_take, max_take: max_take) + if take == 0 + puts "I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT." + break + end + pile = pile - take + if pile > 0 + puts "PLAYER TAKES #{take} AND LEAVES #{pile}" + else + if goal == GOAL_TAKE_LAST + puts "CONGRATULATIONS, YOU WIN." + break + else + puts "TOUGH LUCK, YOU LOSE." + break + end + end + end + end +end + + +def main + instructions + loop do + pile = ask_for_pile_size + break if pile < 0 + goal = ask_for_goal + min_take, max_take = ask_for_min_max_take + first_move = ask_who_makes_first_move + battle( + pile: pile, + goal: goal, + min_take: min_take, + max_take: max_take, + first_move: first_move, + ) + end +end + +main