Files
basic-computer-games/04_Awari/ruby/awari.rb
Alex Scown d0c124a312 Initial port
Game works, but AI behaves differently to the original.

Need to try and remove the globals.
2022-01-09 14:21:29 +00:00

287 lines
5.5 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
require 'strscan'
def print_beans(beans)
puts
# Print computer beans
print " "
beans[7..12].reverse.each {|bean_count| print_bean(bean_count)}
puts
# Print home beans
print_bean(beans[13])
print ' '
print_number(beans[6]) # This is not print_bean in line with the original version
puts
# Print player beans
print " "
beans[0..5].each {|bean_count| print_bean(bean_count)}
puts
puts
end
def print_bean(bean_count)
print ' ' if bean_count < 10
print_number(bean_count)
end
def print_number(n)
# PRINT adds padding after a number and before a positive number
print ' ' if n >= 0
print n.to_s
print ' '
end
def get_move(prompt, beans)
move = get_integer_input(prompt)
while move < 1 || move > 6 || beans[move - 1] == 0
puts "ILLEGAL MOVE"
move = get_integer_input("AGAIN")
end
move - 1
end
def get_integer_input(prompt)
integer_value = nil
input_values = input(prompt)
while integer_value.nil?
print '!EXTRA INPUT IGNORED' if (input_values.size > 1)
value = input_values.first
begin
integer_value = Integer(value)
rescue
puts '!NUMBER EXPECTED - RETRY INPUT LINE'
input_values = input('')
end
end
integer_value
end
def input(prompt)
prompt_suffix = '? '
print "#{prompt}#{prompt_suffix}"
input = gets.chomp.strip
scanner = StringScanner.new(input)
input_values = []
until scanner.eos?
scanner.scan(/\s+/)
if scanner.check(/"/)
scanner.scan(/"/)
next_string = scanner.scan_until(/"/)
if next_string
# Remove the trailing close quote
next_string.chomp!('"')
else
# No close quote Vintage Basic crashes in this case
raise ArgumentError('Unmatched quotes in input')
end
elsif scanner.exist?(/,/)
next_string = scanner.scan_until(/,/).chomp(',')
else
next_string = scanner.scan_until(/\s+|$/).rstrip
end
input_values << next_string
end
input_values << '' if input_values.empty?
input_values
end
def distribute_beans(beans, start_pit, home_pit)
beans_to_distribute = beans[start_pit]
beans[start_pit] = 0
current_pit = start_pit
(0...beans_to_distribute).each do
current_pit = (current_pit + 1) % beans.size
beans[current_pit] += 1
end
# If the last pit was empty before we put a bean in it (and it's not a scoring pit), add beans to score
if beans[current_pit] == 1 && current_pit != 6 && current_pit != 13 && beans[12 - current_pit] != 0
beans[home_pit] = beans[home_pit] + beans[12 - current_pit] + 1
beans[current_pit] = 0
beans[12 - current_pit] = 0
end
current_pit
end
def update_internals(beans)
$k = $k - 7 if $k > 6
$c = $c + 1
$f[$n] = $f[$n] * 6 + $k if $c < 9
unless beans[0...6].find { |b| b != 0 } && beans[7...13].find { |b| b != 0 }
$game_over = true
end
end
# @param [Array] beans
# @param [Integer] move
# @param [Integer] home_pit
def perform_move(beans, move, home_pit)
last_pit = distribute_beans(beans, move, home_pit)
update_internals(beans)
last_pit
end
def end_game(beans)
puts
puts "GAME OVER"
difference = beans[6] - beans[13]
if difference < 0
puts "I WIN BY #{-difference} POINTS"
return
end
$n += 1
puts "YOU WIN BY #{difference} POINTS" if difference > 0
puts "DRAWN GAME" if difference == 0
end
# @param [Array] beans
def get_computer_move(beans)
d = -99
home_pit = 13
beans_copy = beans.dup
move_to_do = 0
(7..12).each do |move_under_test|
if beans[move_under_test] == 0
next
end
max_score = 0
distribute_beans(beans_copy, move_under_test, home_pit)
(0...6).each do |i|
next if beans_copy[i] == 0
l = beans_copy[i] + i
r = l / 14
l_mod_14 = l % 14
r = beans_copy[12 - l_mod_14] + r if beans_copy[l_mod_14] == 0 && l_mod_14 != 6 && l_mod_14 != 13
max_score = r if r > max_score
end
final_score = beans_copy[13] - beans_copy[6] - max_score
if $c <=8
$k = move_under_test
$k = $k - 7 if $k > 6
end
(1...$n).each do |i|
final_score = final_score - 2 if $f[$n] * 6 + $k == (($f[i]/6 ** (7-$c)) + 0.1).floor
end
if final_score >= d
move_to_do = move_under_test
d = final_score
end
end
last_pit = perform_move(beans, move_to_do, home_pit)
[move_to_do, last_pit]
end
puts 'AWARI'.center(80)
puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(80)
# Initialise stable variables
$f = Array.new(50)
$n = 0
# APPLICATION LOOP
:game
while true
print "\n", "\n"
beans = Array.new(13, 3)
beans[6] = 0
beans[13] = 0
$f[$n] = 0
$game_over = false
$c = 0
until $game_over
print_beans(beans)
move = get_move("YOUR MOVE", beans)
home_pit = 6
computer_home_pit = 13
$k = move
last_pit = perform_move(beans, move, home_pit)
print_beans(beans)
if $game_over
end_game(beans)
next :game
end
if home_pit == last_pit
second_move = get_move("AGAIN", beans)
$k = second_move
perform_move(beans, second_move, home_pit)
print_beans(beans)
if $game_over
end_game(beans)
next :game
end
end
computer_move, computer_last_pit = get_computer_move(beans)
print "MY MOVE IS #{computer_move - 6}"
if $game_over
end_game(beans)
next :game
end
if computer_last_pit == computer_home_pit
second_computer_move, _ = get_computer_move(beans)
print ",#{second_computer_move - 6}"
if $game_over
end_game(beans)
next :game
end
end
end
end