14 февраля 2011 г.

Silverlght: Бадания с Canvas

Простая задача. Необходимо на странице разместить в экземпляре ScrollViewer разместить  Canavas, а в нем уже изображение, TextBox или что-то еще. Делалось с той целью, чтобы получился такой объект в него можно было добавлять новые компоненты (помимо Image или TextBox), а он при этом растягивался и оставлял для доступа «ползунок” . Зараза Canvas, совсем не так работает как предполагалось. Скриншот тогда не сделал, поэтому не могу продемонстрировать — все содержимое обрезалось по фактическому размеру ScrollViewer (полоса прокрутки не потребовалась).
Озарение: Canvas не определяет свой размер по размеру дочернего элемента.
Второй целью этой задачи было создать компонент, который сможет не только справится с выше озвученной проблемой, но и сможет принимать новые параметры. Понятным языком — необходимо сделать доступным в xaml разметке компонента пользовательские свойства, через которые можно передавать параметры новому компоненту.
Озарение: Для создания пользовательских свойств компонента, доступных в xaml разметки необходимо использовать объект   свойств зависимостей public static readonly DependencyProperty.
 И так, постановка задачи:
1) Любой ценой разместить Canvas в ScrollViewer;
2) Реализовать эту задачу, как чисто в xaml так и чисто в C# (создав компонент)
3) Привести пример использование DependencyProperty

Замечание: Добавлять Canvas в ScrollViewer напрямую не удастся, вместо этого в ScrollViewer будет вложен Grid, в нем что угодно, в том числе Canvas. Все прочее что необходимо будет добавить добавляем в Grid:
Реализация на xaml:
<ScrollViewer HorizontalScrollBarVisibility="Auto"  Width="auto" Height="auto" Grid.Column="0" Grid.Row="1">
    <ScrollViewer.Content>
        <!-- Объект Canvas вложенный В объект ScrollViewer примет размер Scroll viewer и не будет учитывать
        рамер объектов размещенных в  Canvasе!! - поэтому используется Grid, а в нем Canvas -->

        <Grid Width="auto" Height="auto" >
            <!-- Смастерим просмотрщик: Размер Gridа будет под размер изображения-->
            <Image x:Name="loadedImage" Width="auto" Height="auto">
               <Image.RenderTransform>
               <CompositeTransform ScaleX="1" ScaleY="1"/><!-- Задел для масштабирования-->
               </Image.RenderTransform>
               </Image>
            <!-- Если не все дочерние эл-ты в Grid разместить в одной ячейки то они могут идти как два слоя  -->
               <Canvas Background="Transparent" >
               <!-- Поверх Image будет прозрачный Холст, а на нем кнопка (можно заменить на что, нибудь другое) -->
                <Button Content="It s Canvas" Canvas.Left="100" Canvas.Top="100"/>
              <!-- Вообщим Canvas будет такого-же размера как и  Image -->
            </Canvas>
        </Grid>
    </ScrollViewer.Content>
</ScrollViewer>Syhi-подсветка кода
Реализация компонента на C#:
// Небольшой класс реализующий возможность простых манипуляций изображений
// В данном случае возможность просмотра изображения превышающего размер окна
public class ImageManipulate : ContentControl
{
    // Добавляем произвольное свойство к создаваемому компоненту - исходное изображение
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(Image),typeof(ImageManipulate), null);
    //Дополнительное свойство позволяющее принимать canvas как параметр в xaml разметке
    public static readonly DependencyProperty CanvasInsideProperty =
        DependencyProperty.Register("CanvasInside", typeof(Canvas), typeof(ImageManipulate), null);
    private double _imageWidth;     // Ширина оригинального изображения
    private double _imageHeight;    // Высота оригинального изображения
    private Image _image;           // Изображение для возможных манипуляций
    private ScrollViewer viewerBox;
    private Grid mainGridContainer;
        //Свойство которое и осуществляет прием  и передачу изображения
    public Image Source
    {
                get { return (Image)GetValue(SourceProperty); }
        set
            {
            SetValue(SourceProperty, value);
            _image = value;//Кэшируем изображение
            _imageWidth = _image.Width;
            _imageHeight = _image.Height;
            this.mainGridContainer.Children.Add(this._image);//Добавляем изображение в Grid
            }
    }
    public Canvas CanvasInside
    {
        get { return (Canvas)GetValue(CanvasInsideProperty); }
        set
        {
            SetValue(CanvasInsideProperty, value);
            this.mainGridContainer.Children.Add(value);
        }
    }
    public ImageManipulate()
    {
        this.mainGridContainer = new Grid();
        viewerBox = new ScrollViewer() { HorizontalScrollBarVisibility = ScrollBarVisibility.Auto };
        viewerBox.Content = this.mainGridContainer;// Создаем объект контейнера с "ползунками" и добаляем в него Грид
        this.Content = viewerBox;
    }
}Syhi-подсветка кода
Его ре инкарнация в xaml разметке:
<!-- xmlns:local="clr-namespace:FotoDocDemo1;assembly=FotoDocDemo1" - ссылаемся на пространство имен
в котором находится класс ImageManipulate-->

<local:ImageManipulate Grid.Row="1" Width="auto" Height="auto">
        <!-- Свойство Source: -->
    <local:ImageManipulate.Source>
        <Image Source="img/avstria.jpg" Width="auto" Height="auto"/>
    </local:ImageManipulate.Source>
        <!-- Свойство CanvasInside-->
    <local:ImageManipulate.CanvasInside>
        <Canvas Width="auto" Height="auto">
            <Button Content="Click" Canvas.Left="200" Canvas.Top="200"/>
        </Canvas>
</local:ImageManipulate.CanvasInside>
</local:ImageManipulate>Syhi-подсветка кода

10 февраля 2011 г.

Задача "Восемь Ферзей"

Matraska продолжает изучать алгоритмические задачи. На этот раз задача будет о Восьми ферзях (см. WikiPedia).
Эта задача, да и все подобные полезны тем, что позволяют отточить навыки кодинга, здорово поломать голову, и конечно научится новому.
Так на примере этой задачи небезызвестный автор этого труда познал приемы работы с двумерными массивами (до этого как то не доходили руки), почесал репу и не смог найти другого  алгоритма решения этой задачи, кроме как метода подбора... И в правду задача немного сложнее, а написанный на ruby код немного объемнее, чем реализации этой задачи  других авторов на C, Basic и прочих языках, которые удалось найти при не продолжительном поиске по Гуглю.
class Eight_ferz
  attr_reader :chease_board
  def initialize()
    #Создаем многомерный массив
    @chease_board = Array.new(8)
    @chease_board.map! { Array.new(8,0) }# Инициализируем массив 0-ми
  end
 #Метод демонстрирующий всю доску
  def show_board
    @chease_board.each do |row|
      p row
    end
  end
  # Метод устанавливающий фигуру на шахматной доске
  # n- номер строки, m - номер столбца
  def set_figure(n,m)
    # Устанавливаем 1 (замораживаем точки) по ортогональным линиям шахмотной доски
    (0..7).each{|index| @chease_board[n][index]=@chease_board[index][m]=1}
    # Рассматриваем 4 ю четверть СК(центр СК точка n,m)
    n4,m4=n,m
    #puts("n: #{n4}, m: #{m4}")
    while (n4<8&&m4<8)
      @chease_board[n4][m4]=1
      n4+=1;
      m4+=1
      #puts("n: #{n4}, m: #{m4}")
    end
    n1,m1=n,m
    while(n1>=0&&m1<8)
      @chease_board[n1][m1]=1
      n1-=1;
      m1+=1
    end
    n2,m2=n,m
    while(n2>=0&&m2>=0)
      @chease_board[n2][m2]=1
      n2-=1
      m2-=1
    end
    n3,m3=n,m
    while(n3<8&&m3>=0)
      @chease_board[n3][m3]=1
      n3+=1
      m3-=1
    end
    @chease_board[n][m]=2;
  end
  def free_positions()
    free_pos=Array.new()
    # Перебираем все позиции, если равен 0 в массив
    (0..7).each do|n|
      (0..7).each do |m|
        if @chease_board[n][m]==0
          #puts("N[#{n}], M[#{m}]")
          free_pos<<[n,m]
        end
      end
    end
    # В качестве ответа метода выводим координаты выбранной точки и кол-во свободных позиций
    if free_pos.size>0
      free_pos[rand(free_pos.size-1)]<<free_pos.size
    else
      nil
    end
   
  end
  # Решение методом перебора(может заполнить доску 5-8 ферзями!)
  def start
  count=0
  current_position=self.free_positions()# получаем координаты позицию на которую можно поставить ферзя
    while (!current_position.nil?)
      self.set_figure(current_position[0],current_position[1]) # устанавливаем ферзя
      current_position=self.free_positions() #
      count+=1
    end
  puts("Count #{count}")
  end
endSyhi-подсветка кода
Пример вызова (может быть от 5-до 8 ферзей!):

obj1=Eight_ferz.new()
obj1.start
obj1.show_board

5 февраля 2011 г.

Задача «Треугольник Пифагора»

Ну или оригинальное название (http://habrahabr.ru/blogs/python/111898/) - «Double Squares»
Эта задача из Hacker Cup Qualification Round, очень нравится :
Matraska хочет участвовать в Facebook Hacker Cup 2011 (хоть и заочно) и заодно представить решение этой задачи на ruby ибо python-ом автор опуса не орудует, в отличие от авторов оригинальной статьи (ссылка была в начале абзаца).
Автор (Matraska пр. ред.) позволил себе назвать эту задачу, казалось бы таким уже «истертым» названием, потому что увидел в ней скрытый смысл, о котором будет написано далее. А все скрытое неприменно привлекает внимание и побуждает к действию.
И так текст задачи:
«Найти число представлений целого числа в виде суммы двух полных квадратов целых. Диапазон входящих чисел от нуля до 2147483647.»
Рассмотрим задачу на двух пальцах. Пусть  имеется коллекция целых  неотрицательных чисел m; 0, 2, 67 и т. д. и необходимо определить  для каждого числа количество возможных комбинаций вида
c^2=b^2+a^2,
где с, b и а целые положительные числа.
Почему Пифагора — потому что если обозначить c,  a и b как стороны прямоугольного треугольника, то  c будет гипотенузой, a и b — катетами.
Представляю код:
class Pifagor
  # Метод, который возращает корень входного числа если оно имеет целый корень и nil если иначе
  def simple?(input_number)
    # Dy=number -round(sqrt(number))^2
    dy=input_number- Math.sqrt(input_number).floor**2
    dy==0?Math.sqrt(input_number):nil
  end
  def work(number) #number - то число которое раскладываем
    a_limit=self.simple?(number)
    b_limit=0 # a_limit, b_limit определяют диапазон значений a и b для перебора
    i=0 #кол-во комбинаций
    if !a_limit.nil?
      (0..a_limit).each do|a|
        (0..b_limit).each do |b|
          if(a**2+b**2)==number
            puts("a: #{a}, b: #{b}")
            i+=1
          end
        end
        b_limit+=1# Делаем нижне треугольная матрицу [a_limit x b_limit]
      end
    end
    puts("Number: #{i}")
  end
endSyhi-подсветка кода
Здесь задачу решаем перебором, перебираем в двух циклах от 0 до round(sqrt(c^2) )
Пример вызова:
Pifagor.new.work(25)